Why touching "d_name" makes calls to readdir() fail?

I'm trying to write a little helper for Windows which eventually will accept a file extension as an argument and return the number of files of that kind in the current directory.

To do so, I'm reading the file entries in the directories and after getting the extension I'd like to convert it to lowercase to compare it with the yet-to-add specified argument.

When converting the extension to lowercase I found that touching even a duplicate string of the d_name variable will cause a strange behaviour, like no more calls to readdir are called.

Here is the code I'm using right now (the commented code is preliminary) and outputs for a given directory:

#include <ctype.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>

char * strrch(char *string, size_t elements, char character) {
    char *reverse = string + elements;
    while (--reverse != string)
        if (*reverse == character)
            return reverse;
    return NULL;
}

void test(char *string) {
    // Even being a duplicate will make it fail:
    char *str = strdup(string);
    printf("Strings: %s %s\n", string, str);
    *str = 'a';
    printf("Strings: %s %s\n", string, str);

    //unsigned short int i = 0;
    //for (; str[i] != '\0', str++; i++)
    //   str[i] = tolower((unsigned char) str[i]);
    //puts(str);
}

int main(int argc, char **argv) {
    DIR *directory;
    struct dirent *element;   

    if (directory = opendir(".")) {
        while (element = readdir(directory))
            test(strrch(element->d_name, element->d_namlen, '.'));
        closedir(directory);
        puts(NULL);
    } else
        puts("Couldn't open the directory.\n");
}

Output without modifying the duplicate (modification and the second printf call commented):

Strings: (null) (null)
Strings: . .
Strings: .exe .exe
Strings: .pdf .pdf
Strings: .c .c
Strings: .ini .ini
Strings: .pdf .pdf
Strings: .pdf .pdf
Strings: .pdf .pdf
Strings: .flac .flac
Strings: .FLAC .FLAC
Strings: .lnk .lnk
Strings: .URL .URL

Output of the same directory (with the code above, with the 2 printfs):

Strings: (null) (null)

Is there anything wrong? Is it a compiler issue? I'm using GCC 4.4.3 in Windows (MinGW) right now.

Thank you very much for your help.

By the way, is there any other way to work with files and directories in a Windows environment not using the POSIX functions?

Answers


On Windows systems, the "native" API is not POSIX but Win32. With Win32, try FindFirstFile() and FindNextFile().

As for your code: your first line shows that the first call to test() is with a NULL pointer (that's what your strrch() function returns for a file name of "."). strdup() is kind enough not to crash on NULL but returns NULL. Then you modify the "string", which does not exist. This is a NULL pointer dereference, at which point anything goes. On a Unix system this would imply immediate application termination, with a segfault. On Windows, this probably depends on the OS brand.


Need Your Help

php calculate float

php math floating-point

I have a weird math calculation here. I hope someone will explain.

Fastcgi 500 error on preg_match_all in PHP

php regex

I'm trying to set up some exotic PHP code (I'm not an expert), and I get a FastCGI Error 500 on a PHP line containing 'preg_match_all'.