# HG changeset patch # User Paul Eggert # Date 1130635924 0 # Node ID 3fd5472100131a4d554b46324a8f32e991b66941 # Parent f9d5ad5c44c0f4b020e9c01775d2fe29594c2f16 * getcwd.c (__getcwd): Don't assume that system calls after readdir leave errno alone. diff --git a/lib/ChangeLog b/lib/ChangeLog --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,8 @@ +2005-10-29 Paul Eggert + + * getcwd.c (__getcwd): Don't assume that system calls after readdir + leave errno alone. Problem reported by Dmitry V. Levin. + 2005-10-28 Paul Eggert * savedir.c (savedir): Don't assume that xrealloc etc. leave diff --git a/lib/getcwd.c b/lib/getcwd.c --- a/lib/getcwd.c +++ b/lib/getcwd.c @@ -201,6 +201,8 @@ ino_t dotino; bool mount_point; int parent_status; + size_t dirroom; + size_t namlen; /* Look at the parent directory. */ #ifdef AT_FDCWD @@ -241,11 +243,20 @@ goto lose; dotlist[dotlen++] = '/'; #endif - /* Clear errno to distinguish EOF from error if readdir returns - NULL. */ - __set_errno (0); - while ((d = __readdir (dirstream)) != NULL) + for (;;) { + /* Clear errno to distinguish EOF from error if readdir returns + NULL. */ + __set_errno (0); + d = __readdir (dirstream); + if (d == NULL) + { + if (errno == 0) + /* EOF on dirstream, which means that the current directory + has been removed. */ + __set_errno (ENOENT); + goto lose; + } if (d->d_name[0] == '.' && (d->d_name[1] == '\0' || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) @@ -303,48 +314,38 @@ break; } } - if (d == NULL) + + dirroom = dirp - dir; + namlen = _D_EXACT_NAMLEN (d); + + if (dirroom <= namlen) { - if (errno == 0) - /* EOF on dirstream, which means that the current directory - has been removed. */ - __set_errno (ENOENT); - goto lose; - } - else - { - size_t dirroom = dirp - dir; - size_t namlen = _D_EXACT_NAMLEN (d); - - if (dirroom <= namlen) + if (size != 0) + { + __set_errno (ERANGE); + goto lose; + } + else { - if (size != 0) - { - __set_errno (ERANGE); - goto lose; - } - else - { - char *tmp; - size_t oldsize = allocated; + char *tmp; + size_t oldsize = allocated; + + allocated += MAX (allocated, namlen); + if (allocated < oldsize + || ! (tmp = realloc (dir, allocated))) + goto memory_exhausted; - allocated += MAX (allocated, namlen); - if (allocated < oldsize - || ! (tmp = realloc (dir, allocated))) - goto memory_exhausted; - - /* Move current contents up to the end of the buffer. - This is guaranteed to be non-overlapping. */ - dirp = memcpy (tmp + allocated - (oldsize - dirroom), - tmp + dirroom, - oldsize - dirroom); - dir = tmp; - } + /* Move current contents up to the end of the buffer. + This is guaranteed to be non-overlapping. */ + dirp = memcpy (tmp + allocated - (oldsize - dirroom), + tmp + dirroom, + oldsize - dirroom); + dir = tmp; } - dirp -= namlen; - memcpy (dirp, d->d_name, namlen); - *--dirp = '/'; } + dirp -= namlen; + memcpy (dirp, d->d_name, namlen); + *--dirp = '/'; thisdev = dotdev; thisino = dotino;