diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index e0e4c3cf5..691990907 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,29 @@ +2005-08-20 Christopher Faylor + + * cygerrno.h (geterrno_from_win_error): Change declaration to default + to using GetLastError and EACCESS. + * cygwin.din: Export readdir_r. + * include/cygwin/version.h: Bump API version number to 138. + * syscalls.cc (readdir_worker): New function, renamed from old + readdir() function. + (readdir): Use readdir_worker. + (readdir_r): New function. + * fhandler.h (fhandler_base::readdir): Accommodate second argument + indicating dirent buffer. + (fhandler_disk_file::readdir): Ditto. + (fhandler_cygdrive::readdir): Ditto. + (fhandler_proc::readdir): Ditto. + (fhandler_netdrive::readdir): Ditto. + (fhandler_registry::readdir): Ditto. + (fhandler_process::readdir): Ditto. + * fhandler.cc (fhandler_base::readdir): Ditto. + * fhandler_disk_file.cc (fhandler_disk_file::readdir): Ditto. + * fhandler_cygdrive.cc (fhandler_cygdrive::readdir): Ditto. + * fhandler_proc.cc (fhandler_proc::readdir): Ditto. + * fhandler_netdrive.cc (fhandler_netdrive::readdir): Ditto. + * fhandler_registry.cc (fhandler_registry::readdir): Ditto. + * fhandler_process.cc (fhandler_process::readdir): Ditto. + 2005-08-19 Christopher Faylor * fhandler.h (dirent_states): Add dirent_saw_proc. diff --git a/winsup/cygwin/cygerrno.h b/winsup/cygwin/cygerrno.h index 48528f520..e3b1011ba 100644 --- a/winsup/cygwin/cygerrno.h +++ b/winsup/cygwin/cygerrno.h @@ -14,7 +14,7 @@ details. */ void __stdcall seterrno_from_win_error (const char *file, int line, DWORD code) __attribute__ ((regparm(3))); void __stdcall seterrno (const char *, int line) __attribute__ ((regparm(2))); -int __stdcall geterrno_from_win_error (DWORD code, int deferrno) __attribute__ ((regparm(2))); +int __stdcall geterrno_from_win_error (DWORD code = GetLastError (), int deferrno = 13 /*EACCESS*/) __attribute__ ((regparm(2))); #define __seterrno() seterrno (__FILE__, __LINE__) #define __seterrno_from_win_error(val) seterrno_from_win_error (__FILE__, __LINE__, val) diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index da8e055c3..e8a98c4f8 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -1120,6 +1120,7 @@ read SIGFE _read = read SIGFE readdir SIGFE _readdir = readdir SIGFE +readdir_r = readdir SIGFE readlink SIGFE _readlink = readlink SIGFE readv SIGFE diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc index 894691d8f..ca9ff5979 100644 --- a/winsup/cygwin/dir.cc +++ b/winsup/cygwin/dir.cc @@ -65,53 +65,51 @@ opendir (const char *name) return res; } -/* readdir: POSIX 5.1.2.1 */ -extern "C" struct dirent * -readdir (DIR *dir) +int +readdir_worker (DIR *dir, dirent *de) { myfault efault; - if (efault.faulted (EFAULT)) - return NULL; + if (efault.faulted ()) + return EFAULT; if (dir->__d_cookie != __DIRENT_COOKIE) { - set_errno (EBADF); syscall_printf ("%p = readdir (%p)", NULL, dir); - return NULL; + return EBADF; } - dirent *res = ((fhandler_base *) dir->__fh)->readdir (dir); - - if (!res) - { - if (!(dir->__flags & dirent_saw_dot)) - { - res = dir->__d_dirent; - strcpy (res->d_name, "."); - dir->__flags |= dirent_saw_dot; - dir->__d_position++; - } - else if (!(dir->__flags & dirent_saw_dot_dot)) - { - res = dir->__d_dirent; - strcpy (res->d_name, ".."); - dir->__flags |= dirent_saw_dot_dot; - dir->__d_position++; - } - } + int res = ((fhandler_base *) dir->__fh)->readdir (dir, de); if (res) + { + if (!(dir->__flags & dirent_saw_dot)) + { + strcpy (de->d_name, "."); + dir->__flags |= dirent_saw_dot; + dir->__d_position++; + res = 0; + } + else if (!(dir->__flags & dirent_saw_dot_dot)) + { + strcpy (de->d_name, ".."); + dir->__flags |= dirent_saw_dot_dot; + dir->__d_position++; + res = 0; + } + } + + if (!res) { /* Compute d_ino by combining filename hash with the directory hash (which was stored in dir->__d_dirhash when opendir was called). */ - if (res->d_name[0] == '.') + if (de->d_name[0] == '.') { - if (res->d_name[1] == '\0') + if (de->d_name[1] == '\0') { - dir->__d_dirent->d_ino = dir->__d_dirhash; + de->d_ino = dir->__d_dirhash; dir->__flags |= dirent_saw_dot; } - else if (res->d_name[1] != '.' || res->d_name[2] != '\0') + else if (de->d_name[1] != '.' || de->d_name[2] != '\0') goto hashit; else { @@ -122,11 +120,11 @@ readdir (DIR *dir) goto hashit; *p = '\0'; if (!(p = strrchr (up, '\\'))) - dir->__d_dirent->d_ino = hash_path_name (0, "."); + de->d_ino = hash_path_name (0, "."); else { *p = '\0'; - dir->__d_dirent->d_ino = hash_path_name (0, up); + de->d_ino = hash_path_name (0, up); } } } @@ -134,9 +132,36 @@ readdir (DIR *dir) { hashit: __ino64_t dino = hash_path_name (dir->__d_dirhash, "\\"); - dir->__d_dirent->d_ino = hash_path_name (dino, res->d_name); + de->d_ino = hash_path_name (dino, de->d_name); } - res->__ino32 = dir->__d_dirent->d_ino; // for legacy applications + de->__ino32 = de->d_ino; // for legacy applications + } + return res; +} + +/* readdir: POSIX 5.1.2.1 */ +extern "C" struct dirent * +readdir (DIR *dir) +{ + int res = readdir_worker (dir, dir->__d_dirent); + if (res == 0) + return dir->__d_dirent; + if (res != ENMFILE) + set_errno (res); + return NULL; +} + +extern "C" int +readdir_r (DIR *dir, dirent *de, dirent **ode) +{ + int res = readdir_worker (dir, de); + if (!res) + *ode = de; + else + { + *ode = NULL; + if (res != ENMFILE) + res = 0; } return res; } diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 60ea7a62a..63ca99b4a 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -1538,11 +1538,10 @@ fhandler_base::opendir () return NULL; } -struct dirent * -fhandler_base::readdir (DIR *) +int +fhandler_base::readdir (DIR *, dirent *) { - set_errno (ENOTDIR); - return NULL; + return ENOTDIR; } _off64_t diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 1728c1a39..f371ee0ce 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -354,7 +354,7 @@ class fhandler_base virtual int mkdir (mode_t mode); virtual int rmdir (); virtual DIR *opendir (); - virtual dirent *readdir (DIR *); + virtual int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); virtual _off64_t telldir (DIR *); virtual void seekdir (DIR *, _off64_t); virtual void rewinddir (DIR *); @@ -674,7 +674,7 @@ class fhandler_disk_file: public fhandler_base int mkdir (mode_t mode); int rmdir (); DIR *opendir (); - struct dirent *readdir (DIR *); + int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); _off64_t telldir (DIR *); void seekdir (DIR *, _off64_t); void rewinddir (DIR *); @@ -692,7 +692,7 @@ class fhandler_cygdrive: public fhandler_disk_file public: fhandler_cygdrive (); DIR *opendir (); - struct dirent *readdir (DIR *); + int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); void rewinddir (DIR *); int closedir (DIR *); int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2))); @@ -1202,7 +1202,7 @@ class fhandler_proc: public fhandler_virtual public: fhandler_proc (); int exists(); - struct dirent *readdir (DIR *); + int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); static DWORD get_proc_fhandler(const char *path); int open (int flags, mode_t mode = 0); @@ -1215,7 +1215,7 @@ class fhandler_netdrive: public fhandler_virtual public: fhandler_netdrive (); int exists(); - struct dirent *readdir (DIR *); + int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); void seekdir (DIR *, _off64_t); void rewinddir (DIR *); int closedir (DIR *); @@ -1230,7 +1230,7 @@ class fhandler_registry: public fhandler_proc public: fhandler_registry (); int exists(); - struct dirent *readdir (DIR *); + int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); _off64_t telldir (DIR *); void seekdir (DIR *, _off64_t); void rewinddir (DIR *); @@ -1250,7 +1250,7 @@ class fhandler_process: public fhandler_proc fhandler_process (); int exists(); DIR *opendir (); - struct dirent *readdir (DIR *); + int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); int open (int flags, mode_t mode = 0); int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2))); bool fill_filebuf (); diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 5c8eac9d2..f26c65dd8 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -1348,27 +1348,29 @@ free_dir: return res; } -struct dirent * -fhandler_disk_file::readdir (DIR *dir) +int +fhandler_disk_file::readdir (DIR *dir, dirent *de) { WIN32_FIND_DATA buf; HANDLE handle; - struct dirent *res = NULL; + int res; - if (dir->__handle == INVALID_HANDLE_VALUE - && dir->__d_position == 0) + if (dir->__handle == INVALID_HANDLE_VALUE && dir->__d_position == 0) { handle = FindFirstFileA (dir->__d_dirname, &buf); DWORD lasterr = GetLastError (); dir->__handle = handle; if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { - seterrno_from_win_error (__FILE__, __LINE__, lasterr); - return res; + res = geterrno_from_win_error (); + goto out; } } else if (dir->__handle == INVALID_HANDLE_VALUE) - return res; + { + res = EBADF; + goto out; + } else if (!FindNextFileA (dir->__handle, &buf)) { bool added = false; @@ -1396,15 +1398,10 @@ fhandler_disk_file::readdir (DIR *dir) buf.dwFileAttributes = 0; else { - DWORD lasterr = GetLastError (); + res = geterrno_from_win_error (); FindClose (dir->__handle); dir->__handle = INVALID_HANDLE_VALUE; - /* POSIX says you shouldn't set errno when readdir can't - find any more files; so, if another error we leave it set. */ - if (lasterr != ERROR_NO_MORE_FILES) - seterrno_from_win_error (__FILE__, __LINE__, lasterr); - syscall_printf ("%p = readdir (%p)", res, dir); - return res; + goto out; } } @@ -1427,25 +1424,25 @@ fhandler_disk_file::readdir (DIR *dir) /* We get here if `buf' contains valid data. */ if (pc.isencoded ()) - fnunmunge (dir->__d_dirent->d_name, buf.cFileName); + fnunmunge (de->d_name, buf.cFileName); else - strcpy (dir->__d_dirent->d_name, buf.cFileName); + strcpy (de->d_name, buf.cFileName); if (dir->__flags && dirent_isroot) { - if (strcasematch (dir->__d_dirent->d_name, "dev")) + if (strcasematch (de->d_name, "dev")) dir->__flags |= dirent_saw_dev; - else if (strcasematch (dir->__d_dirent->d_name, "proc")) + else if (strcasematch (de->d_name, "proc")) dir->__flags |= dirent_saw_proc; - if (strlen (dir->__d_dirent->d_name) == mount_table->cygdrive_len - 2 - && strncasematch (dir->__d_dirent->d_name, mount_table->cygdrive + 1, + if (strlen (de->d_name) == mount_table->cygdrive_len - 2 + && strncasematch (de->d_name, mount_table->cygdrive + 1, mount_table->cygdrive_len - 2)) dir->__flags |= dirent_saw_cygdrive; } dir->__d_position++; - res = dir->__d_dirent; - syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir, - buf.cFileName); + res = 0; +out: + syscall_printf ("%d = readdir (%p) (%s)", dir, &de, de->d_name); return res; } @@ -1526,24 +1523,23 @@ fhandler_cygdrive::opendir () return dir; } -struct dirent * -fhandler_cygdrive::readdir (DIR *dir) +int +fhandler_cygdrive::readdir (DIR *dir, dirent *de) { if (!pdrive || !*pdrive) - return NULL; + return ENMFILE; if (GetFileAttributes (pdrive) == INVALID_FILE_ATTRIBUTES) { pdrive = strchr (pdrive, '\0') + 1; - return readdir (dir); + return readdir (dir, de); } - *dir->__d_dirent->d_name = cyg_tolower (*pdrive); - dir->__d_dirent->d_name[1] = '\0'; + *de->d_name = cyg_tolower (*pdrive); + de->d_name[1] = '\0'; dir->__d_position++; pdrive = strchr (pdrive, '\0') + 1; - syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir, - dir->__d_dirent->d_name); - return dir->__d_dirent; + syscall_printf ("%p = readdir (%p) (%s)", &de, dir, de->d_name); + return 0; } void diff --git a/winsup/cygwin/fhandler_netdrive.cc b/winsup/cygwin/fhandler_netdrive.cc index 81064ec65..4665d2893 100644 --- a/winsup/cygwin/fhandler_netdrive.cc +++ b/winsup/cygwin/fhandler_netdrive.cc @@ -147,12 +147,13 @@ fhandler_netdrive::fstat (struct __stat64 *buf) return 0; } -struct dirent * -fhandler_netdrive::readdir (DIR *dir) +int +fhandler_netdrive::readdir (DIR *dir, dirent *de) { DWORD size; NETRESOURCE *nro; DWORD ret; + int res; if (!dir->__d_position) { @@ -167,8 +168,8 @@ fhandler_netdrive::readdir (DIR *dir) size = MAX_COMPUTERNAME_LENGTH + 1; if (!GetComputerName (namebuf + 2, &size)) { - __seterrno (); - return NULL; + res = geterrno_from_win_error (); + goto out; } } else @@ -189,24 +190,26 @@ fhandler_netdrive::readdir (DIR *dir) &nr, &dir->__handle, 0, "WNetOpenEnum"); if (ret != NO_ERROR) { - __seterrno_from_win_error (ret); dir->__handle = INVALID_HANDLE_VALUE; - return NULL; + res = geterrno_from_win_error (ret); + goto out; } } ret = create_thread_and_wait (GET_RESOURCE_ENUM, dir->__handle, nro = (LPNETRESOURCE) alloca (16384), 16384, "WnetEnumResource"); if (ret != NO_ERROR) + res = geterrno_from_win_error (ret); + else { - if (ret != ERROR_NO_MORE_ITEMS) - __seterrno_from_win_error (ret); - return NULL; + dir->__d_position++; + char *bs = strrchr (nro->lpRemoteName, '\\'); + strcpy (de->d_name, bs ? bs + 1 : nro->lpRemoteName); + res = 0; } - dir->__d_position++; - char *bs = strrchr (nro->lpRemoteName, '\\'); - strcpy (dir->__d_dirent->d_name, bs ? bs + 1 : nro->lpRemoteName); - return dir->__d_dirent; +out: + syscall_printf ("%d = readdir (%p, %p)", res, dir, de); + return res; } void @@ -216,7 +219,7 @@ fhandler_netdrive::seekdir (DIR *dir, _off64_t pos) if (pos < 0) return; while (dir->__d_position < pos) - if (!readdir (dir)) + if (!readdir (dir, dir->__d_dirent)) break; } diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc index 07ae13e0c..74b25f2f6 100644 --- a/winsup/cygwin/fhandler_proc.cc +++ b/winsup/cygwin/fhandler_proc.cc @@ -195,27 +195,32 @@ fhandler_proc::fstat (struct __stat64 *buf) return -1; } -struct dirent * -fhandler_proc::readdir (DIR * dir) +int +fhandler_proc::readdir (DIR *dir, dirent *de) { - if (dir->__d_position >= PROC_LINK_COUNT) + int res; + if (dir->__d_position < PROC_LINK_COUNT) + { + strcpy (de->d_name, proc_listing[dir->__d_position++]); + res = 0; + } + else { winpids pids ((DWORD) 0); int found = 0; + res = ENMFILE; for (unsigned i = 0; i < pids.npids; i++) if (found++ == dir->__d_position - PROC_LINK_COUNT) { - __small_sprintf (dir->__d_dirent->d_name, "%d", pids[i]->pid); + __small_sprintf (de->d_name, "%d", pids[i]->pid); dir->__d_position++; - return dir->__d_dirent; + res = 0; + break; } - return NULL; } - strcpy (dir->__d_dirent->d_name, proc_listing[dir->__d_position++]); - syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir, - dir->__d_dirent->d_name); - return dir->__d_dirent; + syscall_printf ("%d = readdir (%p, %p) (%s)", res, dir, de, de->d_name); + return res; } int diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc index 7cc53302f..1585c2fea 100644 --- a/winsup/cygwin/fhandler_process.cc +++ b/winsup/cygwin/fhandler_process.cc @@ -209,30 +209,28 @@ fhandler_process::opendir () return dir; } -struct dirent * -fhandler_process::readdir (DIR * dir) +int +fhandler_process::readdir (DIR *dir, dirent *de) { + int res = ENMFILE; if (fileid == PROCESS_FD) { if (dir->__d_position >= 2 + filesize / sizeof (int)) - return NULL; + goto out; } else if (dir->__d_position >= PROCESS_LINK_COUNT) - return NULL; + goto out; if (fileid == PROCESS_FD && dir->__d_position > 1) { int *p = (int *) filebuf; - __small_sprintf (dir->__d_dirent->d_name, "%d", p[dir->__d_position++ - 2]); - syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir, - dir->__d_dirent->d_name); + __small_sprintf (de->d_name, "%d", p[dir->__d_position++ - 2]); } else - { - strcpy (dir->__d_dirent->d_name, process_listing[dir->__d_position++]); - syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir, - dir->__d_dirent->d_name); - } - return dir->__d_dirent; + strcpy (de->d_name, process_listing[dir->__d_position++]); + res = 0; +out: + syscall_printf ("%d = readdir (%p, %p) (%s)", dir, de, de->d_name); + return res; } int diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc index 07be1d0c7..885a35247 100644 --- a/winsup/cygwin/fhandler_registry.cc +++ b/winsup/cygwin/fhandler_registry.cc @@ -273,26 +273,25 @@ fhandler_registry::fstat (struct __stat64 *buf) return 0; } -struct dirent * -fhandler_registry::readdir (DIR * dir) +int +fhandler_registry::readdir (DIR *dir, dirent *de) { DWORD buf_size = CYG_MAX_PATH; char buf[buf_size]; HANDLE handle; - struct dirent *res = NULL; const char *path = dir->__d_dirname + proc_len + 1 + registry_len; LONG error; + int res = ENMFILE; if (*path == 0) { if (dir->__d_position >= ROOT_KEY_COUNT) goto out; - strcpy (dir->__d_dirent->d_name, registry_listing[dir->__d_position++]); - res = dir->__d_dirent; + strcpy (de->d_name, registry_listing[dir->__d_position++]); + res = 0; goto out; } - if (dir->__handle == INVALID_HANDLE_VALUE - && dir->__d_position == 0) + if (dir->__handle == INVALID_HANDLE_VALUE && dir->__d_position == 0) { handle = open_key (path + 1, KEY_READ, false); dir->__handle = handle; @@ -301,9 +300,8 @@ fhandler_registry::readdir (DIR * dir) goto out; if (dir->__d_position < SPECIAL_DOT_FILE_COUNT) { - strcpy (dir->__d_dirent->d_name, - special_dot_files[dir->__d_position++]); - res = dir->__d_dirent; + strcpy (de->d_name, special_dot_files[dir->__d_position++]); + res = 0; goto out; } retry: @@ -338,16 +336,16 @@ retry: /* We get here if `buf' contains valid data. */ if (*buf == 0) - strcpy (dir->__d_dirent->d_name, DEFAULT_VALUE_NAME); + strcpy (de->d_name, DEFAULT_VALUE_NAME); else - strcpy (dir->__d_dirent->d_name, buf); + strcpy (de->d_name, buf); dir->__d_position++; if (dir->__d_position & REG_ENUM_VALUES_MASK) dir->__d_position += 0x10000; - res = dir->__d_dirent; + res = 0; out: - syscall_printf ("%p = readdir (%p)", &dir->__d_dirent, dir); + syscall_printf ("%d = readdir (%p, %p)", res, dir, de); return res; } @@ -365,7 +363,7 @@ fhandler_registry::seekdir (DIR * dir, _off64_t loc) */ rewinddir (dir); while (loc > (dir->__d_position & REG_POSITION_MASK)) - if (!readdir (dir)) + if (!readdir (dir, dir->__d_dirent)) break; } diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index d5e97953b..7984df7f2 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -265,12 +265,13 @@ details. */ 136: Add TIOCMBIS/TIOCMBIC ioctl codes. 137: fts_children, fts_close, fts_get_clientptr, fts_get_stream, fts_open, fts_read, fts_set, fts_set_clientptr, ftw, nftw. + 138: Export readdir_r. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 137 +#define CYGWIN_VERSION_API_MINOR 138 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/sys/dirent.h b/winsup/cygwin/include/sys/dirent.h index 996b1ee33..5eafbc27b 100644 --- a/winsup/cygwin/include/sys/dirent.h +++ b/winsup/cygwin/include/sys/dirent.h @@ -68,6 +68,7 @@ typedef struct __DIR DIR *opendir (const char *); struct dirent *readdir (DIR *); +int readdir_r (DIR *, struct dirent *, struct dirent **); void rewinddir (DIR *); int closedir (DIR *);