bug-glibc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

scandir() is buggy if selector() modifies errno


From: Koblinger Egmont
Subject: scandir() is buggy if selector() modifies errno
Date: Mon, 11 Aug 2003 18:10:02 +0200 (CEST)

Hi,

scandir() seems to be buggy: its return status does not only depend on
whether calls to selector() return true or false, it is also influenced by
the value of errno set in the selector() function.

Detailed description:

The first time selector() is called, errno is zero. This is nice.

Whenever selector() returns true (i.e. select the file), errno is set back
to zero, no matter if selector() has altered it. Okay.

If selector() returns false (i.e. don't select the file), errno is left
unchanged, its value is visible at the next invocation of selector(). This
wouldn't be a trouble, but...

... if errno is nonzero after the last call to selector() (which means
that a call to selector() has once set it to nonzero and no invocation of
selector() returned true since then), then the whole call to scandir()
leaves this value of errno set and scandir returns -1.

Example:

Suppose you want to retrieve existing files, hiding dangling symlinks.
For this purpose you have a stat() call inside selector() and if stat()
returns false (-1), you return false (0) in selector(). If the last entry
in the unsorted directory listing is a dangling symlink, scandir() itself
returns a false error.

Compile this piece of code:

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>

int selector (const struct dirent *d)
{
        struct stat st;
        if (stat(d->d_name, &st) < 0) return 0;
        return 1;
}

int main (int argc, char *argv[])
{
        struct dirent **dir;
        int i;
        i = scandir(".", &dir, selector, alphasort);
        printf("scandir returned %d (%s)\n", i, strerror(errno));
        return 0;
}

And then here's a typescript:

address@hidden:~/scandir$ ls -lUa
total 32
drwxr-xr-x    2 egmont   users        4096 2003-08-11 18:00 .
drwxr-xr-x  206 egmont   users       28672 2003-08-11 17:54 ..
lrwxrwxrwx    1 egmont   users           3 2003-08-11 17:58 dangling1 -> foo
lrwxrwxrwx    1 egmont   users           3 2003-08-11 17:58 dangling2 -> foo
-rw-r--r--    1 egmont   users           0 2003-08-11 17:59 file0
address@hidden:~/scandir$ scandirtest
scandir returned 3 (Success)
address@hidden:~/scandir$ ln -s foo dangling3
address@hidden:~/scandir$ ls -lUa
total 32
drwxr-xr-x    2 egmont   users        4096 2003-08-11 18:00 .
drwxr-xr-x  206 egmont   users       28672 2003-08-11 17:54 ..
lrwxrwxrwx    1 egmont   users           3 2003-08-11 17:58 dangling1 -> foo
lrwxrwxrwx    1 egmont   users           3 2003-08-11 17:58 dangling2 -> foo
-rw-r--r--    1 egmont   users           0 2003-08-11 17:59 file0
lrwxrwxrwx    1 egmont   users           3 2003-08-11 18:00 dangling3 -> foo
address@hidden:~/scandir$ scandirtest
scandir returned -1 (No such file or directory)



Tested with glibc 2.2.5 and 2.3.2.


Please CC me, I'm not subscribed. Thx.


bye,
Egmont





reply via email to

[Prev in Thread] Current Thread [Next in Thread]