diff options
Diffstat (limited to 'winsup/cygwin/dir.cc')
-rw-r--r-- | winsup/cygwin/dir.cc | 321 |
1 files changed, 113 insertions, 208 deletions
diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc index 079c5c4fe..45ba57ff6 100644 --- a/winsup/cygwin/dir.cc +++ b/winsup/cygwin/dir.cc @@ -1,6 +1,6 @@ /* dir.cc: Posix directory-related routines - Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc. + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. This file is part of Cygwin. @@ -9,7 +9,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <sys/fcntl.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> @@ -18,13 +17,10 @@ details. */ #define _COMPILING_NEWLIB #include <dirent.h> -#include "sync.h" -#include "sigproc.h" #include "pinfo.h" #include "cygerrno.h" #include "security.h" #include "fhandler.h" -#include "perprocess.h" #include "path.h" #include "dtable.h" #include "cygheap.h" @@ -65,6 +61,8 @@ writable_directory (const char *file) extern "C" int dirfd (DIR *dir) { + if (check_null_invalid_struct_errno (dir)) + return -1; if (dir->__d_cookie != __DIRENT_COOKIE) { set_errno (EBADF); @@ -76,220 +74,136 @@ dirfd (DIR *dir) /* opendir: POSIX 5.1.2.1 */ extern "C" DIR * -opendir (const char *dirname) +opendir (const char *name) { - int len; - DIR *dir; - DIR *res = 0; - struct stat statbuf; - - path_conv real_dirname (dirname, PC_SYM_FOLLOW | PC_FULL); - - if (real_dirname.error) - { - set_errno (real_dirname.error); - goto failed; - } - - if (stat (real_dirname, &statbuf) == -1) - goto failed; - - if (!(statbuf.st_mode & S_IFDIR)) - { - set_errno (ENOTDIR); - goto failed; - } - - len = strlen (real_dirname); - if (len > MAX_PATH - 3) - { - set_errno (ENAMETOOLONG); - goto failed; - } - - if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL) - { - set_errno (ENOMEM); - goto failed; - } - if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL) - { - free (dir); - set_errno (ENOMEM); - goto failed; - } - if ((dir->__d_dirent = - (struct dirent *) malloc (sizeof (struct dirent))) == NULL) + fhandler_base *fh; + path_conv pc; + DIR *res; + + fh = cygheap->fdtab.build_fhandler_from_name (-1, name, NULL, pc, + PC_SYM_FOLLOW | PC_FULL, NULL); + if (!fh) + res = NULL; + else if (pc.exists ()) + res = fh->opendir (pc); + else { - free (dir->__d_dirname); - free (dir); - set_errno (ENOMEM); - goto failed; + set_errno (ENOENT); + res = NULL; } - strcpy (dir->__d_dirname, real_dirname.get_win32 ()); - dir->__d_dirent->d_version = __DIRENT_VERSION; - dir->__d_dirent->d_fd = open (dir->__d_dirname, O_RDONLY | O_DIROPEN); - /* FindFirstFile doesn't seem to like duplicate /'s. */ - len = strlen (dir->__d_dirname); - if (len == 0 || SLASH_P (dir->__d_dirname[len - 1])) - strcat (dir->__d_dirname, "*"); - else - strcat (dir->__d_dirname, "\\*"); /**/ - dir->__d_cookie = __DIRENT_COOKIE; - dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; - dir->__d_position = 0; - dir->__d_dirhash = statbuf.st_ino; - res = dir; - -failed: - syscall_printf ("%p = opendir (%s)", res, dirname); + if (!res && fh) + delete fh; return res; } /* readdir: POSIX 5.1.2.1 */ extern "C" struct dirent * -readdir (DIR * dir) +readdir (DIR *dir) { - WIN32_FIND_DATA buf; - HANDLE handle; - struct dirent *res = NULL; + if (check_null_invalid_struct_errno (dir)) + return NULL; if (dir->__d_cookie != __DIRENT_COOKIE) { set_errno (EBADF); - syscall_printf ("%p = readdir (%p)", res, dir); - return res; - } - - if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE - && dir->__d_position == 0) - { - handle = FindFirstFileA (dir->__d_dirname, &buf); - DWORD lasterr = GetLastError (); - dir->__d_u.__d_data.__handle = handle; - if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) - { - seterrno_from_win_error (__FILE__, __LINE__, lasterr); - return res; - } - } - else if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE) - { - return res; - } - else if (!FindNextFileA (dir->__d_u.__d_data.__handle, &buf)) - { - DWORD lasterr = GetLastError (); - (void) FindClose (dir->__d_u.__d_data.__handle); - dir->__d_u.__d_data.__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; + syscall_printf ("%p = readdir (%p)", NULL, dir); + return NULL; } - /* We get here if `buf' contains valid data. */ - strcpy (dir->__d_dirent->d_name, buf.cFileName); + dirent *res = ((fhandler_base *) dir->__d_u.__d_data.__fh)->readdir (dir); - /* Check for Windows shortcut. If it's a Cygwin or U/WIN - symlink, drop the .lnk suffix. */ - if (buf.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + if (res) { - char *c = dir->__d_dirent->d_name; - int len = strlen (c); - if (strcasematch (c + len - 4, ".lnk")) + /* 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] == '.') { - char fbuf[MAX_PATH + 1]; - strcpy (fbuf, dir->__d_dirname); - strcpy (fbuf + strlen (fbuf) - 1, dir->__d_dirent->d_name); - path_conv fpath (fbuf, PC_SYM_NOFOLLOW); - if (fpath.issymlink ()) - c[len - 4] = '\0'; - } - } - - /* Compute d_ino by combining filename hash with the directory hash - (which was stored in dir->__d_dirhash when opendir was called). */ - if (buf.cFileName[0] == '.') - { - if (buf.cFileName[1] == '\0') - dir->__d_dirent->d_ino = dir->__d_dirhash; - else if (buf.cFileName[1] != '.' || buf.cFileName[2] != '\0') - goto hashit; - else - { - char *p, up[strlen (dir->__d_dirname) + 1]; - strcpy (up, dir->__d_dirname); - if (!(p = strrchr (up, '\\'))) + if (res->d_name[1] == '\0') + dir->__d_dirent->d_ino = dir->__d_dirhash; + else if (res->d_name[1] != '.' || res->d_name[2] != '\0') goto hashit; - *p = '\0'; - if (!(p = strrchr (up, '\\'))) - dir->__d_dirent->d_ino = hash_path_name (0, "."); else { + char *p, up[strlen (dir->__d_dirname) + 1]; + strcpy (up, dir->__d_dirname); + if (!(p = strrchr (up, '\\'))) + goto hashit; *p = '\0'; - dir->__d_dirent->d_ino = hash_path_name (0, up); + if (!(p = strrchr (up, '\\'))) + dir->__d_dirent->d_ino = hash_path_name (0, "."); + else + { + *p = '\0'; + dir->__d_dirent->d_ino = hash_path_name (0, up); + } } } + else + { + hashit: + ino_t dino = hash_path_name (dir->__d_dirhash, "\\"); + dir->__d_dirent->d_ino = hash_path_name (dino, res->d_name); + } } - else - { - hashit: - ino_t dino = hash_path_name (dir->__d_dirhash, "\\"); - dir->__d_dirent->d_ino = hash_path_name (dino, buf.cFileName); - } - - ++dir->__d_position; - res = dir->__d_dirent; - syscall_printf ("%p = readdir (%p) (%s)", - &dir->__d_dirent, dir, buf.cFileName); return res; } -/* telldir */ -extern "C" off_t -telldir (DIR * dir) +extern "C" __off64_t +telldir64 (DIR *dir) { + if (check_null_invalid_struct_errno (dir)) + return -1; + if (dir->__d_cookie != __DIRENT_COOKIE) return 0; - return dir->__d_position; + return ((fhandler_base *) dir->__d_u.__d_data.__fh)->telldir (dir); +} + +/* telldir */ +extern "C" __off32_t +telldir (DIR *dir) +{ + return telldir64 (dir); } -/* seekdir */ extern "C" void -seekdir (DIR * dir, off_t loc) +seekdir64 (DIR *dir, __off64_t loc) { + if (check_null_invalid_struct_errno (dir)) + return; + if (dir->__d_cookie != __DIRENT_COOKIE) return; - rewinddir (dir); - while (loc > dir->__d_position) - if (! readdir (dir)) - break; + return ((fhandler_base *) dir->__d_u.__d_data.__fh)->seekdir (dir, loc); +} + +/* seekdir */ +extern "C" void +seekdir (DIR *dir, __off32_t loc) +{ + seekdir64 (dir, (__off64_t)loc); } /* rewinddir: POSIX 5.1.2.1 */ extern "C" void -rewinddir (DIR * dir) +rewinddir (DIR *dir) { - syscall_printf ("rewinddir (%p)", dir); + if (check_null_invalid_struct_errno (dir)) + return; if (dir->__d_cookie != __DIRENT_COOKIE) return; - if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE) - { - (void) FindClose (dir->__d_u.__d_data.__handle); - dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; - } - dir->__d_position = 0; + return ((fhandler_base *) dir->__d_u.__d_data.__fh)->rewinddir (dir); } /* closedir: POSIX 5.1.2.1 */ extern "C" int -closedir (DIR * dir) +closedir (DIR *dir) { + if (check_null_invalid_struct_errno (dir)) + return -1; + if (dir->__d_cookie != __DIRENT_COOKIE) { set_errno (EBADF); @@ -297,25 +211,18 @@ closedir (DIR * dir) return -1; } - if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE && - FindClose (dir->__d_u.__d_data.__handle) == 0) - { - __seterrno (); - syscall_printf ("-1 = closedir (%p)", dir); - return -1; - } - - if (dir->__d_dirent->d_fd >= 0) - close (dir->__d_dirent->d_fd); - /* Reset the marker in case the caller tries to use `dir' again. */ dir->__d_cookie = 0; + int res = ((fhandler_base *) dir->__d_u.__d_data.__fh)->closedir (dir); + + cygheap->fdtab.release (dir->__d_dirent->d_fd); + free (dir->__d_dirname); free (dir->__d_dirent); free (dir); - syscall_printf ("0 = closedir (%p)", dir); - return 0; + syscall_printf ("%d = closedir (%p)", res); + return res; } /* mkdir: POSIX 5.4.1.1 */ @@ -346,6 +253,11 @@ mkdir (const char *dir, mode_t mode) if (!allow_ntsec && allow_ntea) set_file_attribute (real_dir.has_acls (), real_dir.get_win32 (), S_IFDIR | ((mode & 07777) & ~cygheap->umask)); +#ifdef HIDDEN_DOT_FILES + char *c = strrchr (real_dir.get_win32 (), '\\'); + if ((c && c[1] == '.') || *real_dir.get_win32 () == '.') + SetFileAttributes (real_dir.get_win32 (), FILE_ATTRIBUTE_HIDDEN); +#endif res = 0; } else @@ -361,37 +273,32 @@ extern "C" int rmdir (const char *dir) { int res = -1; + DWORD devn; path_conv real_dir (dir, PC_SYM_NOFOLLOW); if (real_dir.error) - { - set_errno (real_dir.error); - res = -1; - } + set_errno (real_dir.error); + else if ((devn = real_dir.get_devn ()) == FH_PROC || devn == FH_REGISTRY + || devn == FH_PROCESS) + set_errno (EROFS); else if (!real_dir.exists ()) - { - set_errno (ENOENT); - res = -1; - } + set_errno (ENOENT); else if (!real_dir.isdir ()) - { - set_errno (ENOTDIR); - res = -1; - } + set_errno (ENOTDIR); else { /* Even own directories can't be removed if R/O attribute is set. */ if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY)) SetFileAttributes (real_dir, - (DWORD) real_dir & ~FILE_ATTRIBUTE_READONLY); + (DWORD) real_dir & ~FILE_ATTRIBUTE_READONLY); if (RemoveDirectory (real_dir)) { /* RemoveDirectory on a samba drive doesn't return an error if the directory can't be removed because it's not empty. Checking for existence afterwards keeps us informed about success. */ - if (GetFileAttributes (real_dir) != (DWORD) -1) + if (GetFileAttributes (real_dir) != INVALID_FILE_ATTRIBUTES) set_errno (ENOTEMPTY); else res = 0; @@ -418,22 +325,20 @@ rmdir (const char *dir) else if ((res = rmdir (dir))) SetCurrentDirectory (cygheap->cwd.win32); } - if (GetLastError () == ERROR_ACCESS_DENIED) + if (res) { - - /* On 9X ERROR_ACCESS_DENIED is returned if you try to remove - a non-empty directory. */ - if (wincap.access_denied_on_delete ()) - set_errno (ENOTEMPTY); - else + if (GetLastError () != ERROR_ACCESS_DENIED + || !wincap.access_denied_on_delete ()) __seterrno (); - } - else - __seterrno (); + else + set_errno (ENOTEMPTY); /* On 9X ERROR_ACCESS_DENIED is + returned if you try to remove a + non-empty directory. */ - /* If directory still exists, restore R/O attribute. */ - if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY)) - SetFileAttributes (real_dir, real_dir); + /* If directory still exists, restore R/O attribute. */ + if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY)) + SetFileAttributes (real_dir, real_dir); + } } } |