views:

86

answers:

1

Hi, 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?

+2  A: 

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.

Thomas Pornin
Oh, thank you very much! I didn't realize that, if it crashed instead it would be more obvious.
Sarah Mani