Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

#127 Mingw dirent implementation bug

closed-fixed
Earnie Boyd
2002-04-18
2002-04-17
Pascal Obry
No

opendir is not immune to directory change. The
following program fails on Windows.

#include <dirent.h>

int
main (void)
{
DIR *dir;
struct dirent *entry;

dir = opendir ("toto");
chdir ("toto");

while (entry = readdir (dir))
{
printf ("%s\n", entry->d_name);
}

closedir (dir);
}

$ mkdir toto
$ echo > toto/file1
$ main

On UNIX it works just fine. It seems to me that the
dirent should use absolute pathname to avoid this
problem. Here is a patch to fix that:

<<
*** dirent.c.orig Wed Apr 17 20:14:58 2002
--- dirent.c Wed Apr 17 20:19:26 2002
***************
*** 40,45 ****
--- 40,46 ----
{
DIR *nd;
unsigned int rc;
+ char _szPath [MAX_PATH];

errno = 0;

***************
*** 70,78 ****
return (DIR *) 0;
}

/* Allocate enough space to store DIR structure
and the complete
* directory path given. */
! nd = (DIR *) malloc (sizeof (DIR) + strlen
(szPath) + strlen (SLASH) +
strlen (SUFFIX));

if (!nd)
--- 71,96 ----
return (DIR *) 0;
}

+ /* change _szPath to be an absolute pathname */
+ if (((isalpha(_szPath[0]) && (_szPath[1]) == ':')
+ || (_szPath[0] == '/') || (_szPath[0]
== '\\')) == 0)
+ {
+ char cdir[MAX_PATH];
+
+ getcwd (cdir, MAX_PATH);
+
+ strcpy (_szPath, cdir);
+ strcat (_szPath, "\\");
+ strcat (_szPath, szPath);
+ }
+ else
+ {
+ strcpy (_szPath, szPath);
+ }
+
/* Allocate enough space to store DIR structure
and the complete
* directory path given. */
! nd = (DIR *) malloc (sizeof (DIR) + strlen
(_szPath) + strlen (SLASH) +
strlen (SUFFIX));

if (!nd)
***************
*** 83,89 ****
}

/* Create the search expression. */
! strcpy (nd->dd_name, szPath);

/* Add on a slash if the path does not end with
one. */
if (nd->dd_name[0] != '\0' &&
--- 101,107 ----
}

/* Create the search expression. */
! strcpy (nd->dd_name, _szPath);

/* Add on a slash if the path does not end with
one. */
if (nd->dd_name[0] != '\0' &&
>>

Pascal.

Discussion

  • Danny Smith
    Danny Smith
    2002-04-18

    Logged In: YES
    user_id=11494

    Thanks Pascal. One problem:

    This:
    + /* change _szPath to be an absolute pathname */
    + if (((isalpha(_szPath[0]) && (_szPath[1]) == ':')
    + || (_szPath[0] == '/') || (_szPath[0] == '\\')) ==
    0)

    is always true.

    Shouldn't it be this:

    /* If szPath is not an absolute pathname, make it one */
    if (((isalpha(szPath[0]) && (szPath[1]) == ':')
    || (szPath[0] == '/') || (szPath[0] == '\\')) == 0)

    If there are no objections from other developers, I'll
    commit with above change and if you can provide a ChangeLog
    entry.

    Danny

     
  • Danny Smith
    Danny Smith
    2002-04-18

    Logged In: YES
    user_id=11494

    Here is a much simpler fix, using the runtime function
    _fullpath. It cleans up things like ../../../toto as
    well, so we don't fail on (rare) cases where the
    extra ../'s would overflow the _MAX_PATH buffer
    Danny

    --- dirent.c.orig Sat Mar 23 10:43:17 2002
    +++ dirent.c Thu Apr 18 19:33:04 2002
    @@ -40,6 +40,7 @@ opendir (const char *szPath)
    {
    DIR *nd;
    unsigned int rc;
    + char szFullPath [MAX_PATH];

    errno = 0;

    @@ -70,9 +71,12 @@ opendir (const char *szPath)
    return (DIR *) 0;
    }

    + /* Make an absolute pathname. */
    + _fullpath(szFullPath, szPath, MAX_PATH);
    +
    /* Allocate enough space to store DIR structure and the
    complete
    * directory path given. */
    - nd = (DIR *) malloc (sizeof (DIR) + strlen (szPath) +
    strlen (SLASH) +
    + nd = (DIR *) malloc (sizeof (DIR) + strlen (szFullPath)
    + strlen (SLASH) +
    strlen (SUFFIX));

    if (!nd)
    @@ -83,7 +87,7 @@ opendir (const char *szPath)
    }

    /* Create the search expression. */
    - strcpy (nd->dd_name, szPath);
    + strcpy (nd->dd_name, szFullPath);

    /* Add on a slash if the path does not end with one. */
    if (nd->dd_name[0] != '\0' &&

     
  • Pascal Obry
    Pascal Obry
    2002-04-18

    Logged In: YES
    user_id=518488

    Danny,

    OK, it is indeed far better to use _fullpath here. My patch
    was indeed wrong, it has been built on an older version of
    MingW and I have integreted it into the latest version...
    As you found out I forget to rename the szPath variable :(

    Anyway the _fullpath is the way to go.

    Here is the proposed ChangeLog entry
    <<
    2002-04-17 Pascal Obry <obry@gnat.com>

    \* dirent.c:
    \(opendir\): Set DIR struct with the directory
     full pathname to be immune to directory
     change after calling opendir.
    

    >>

    Of course you can change the developper name since you have
    provided a better patch :)

    Thanks,
    Pascal.

     
  • Danny Smith
    Danny Smith
    2002-04-18

    • status: open --> closed-fixed
     
  • Danny Smith
    Danny Smith
    2002-04-18

    Logged In: YES
    user_id=11494

    Commited to CVS. Thanks Pascal.