diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index d7cbb3aec..12fd4db4a 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,75 @@ +2007-07-26 Corinna Vinschen + + * dir.cc (readdir_worker): Drop dir parameter from call to + readdir_get_ino. + * fhandler.h (fhandler_disk_file::readdir_helper): Switch file name + parameter to PUNICODE_STRING. + * fhandler_disk_file.cc: Drop including ntdef.h. + (class __DIR_mounts): Store mount points in UNICODE. Additionally + store cygdrive prefix in unicode here. Change methods accordingly. + (__DIR_mounts::eval_ino): Call new stat_worker instead of lstat64. + (__DIR_mounts::~__DIR_mounts): New destructor to free UNICODE buffers. + (path_conv::ndisk_links): Rewrite using native NT functions. + (fhandler_base::fstat_by_handle): Use NAME_MAX instead of CYG_MAX_PATH. + Always set pfvi->VolumeSerialNumber to non-0. Remove last resort + code. + (fhandler_base::fstat_by_name): Rewrite using native NT functions. + (fhandler_base::fstat_fs): Always call fstat_by_name if fstat_by_handle + fails. + (fhandler_base::fstat_helper): Rely on dwVolumeSerialNumber. + (fhandler_disk_file::facl): Call fstat_by_name if fstat_by_handle fails. + (DIR_BUF_SIZE): Define using NAME_MAX instead of CYG_MAX_PATH. + (__DIR_cache): Remove __name. + (d_dirname): Remove. + (fhandler_disk_file::opendir): Drop pathname length check. + Remove outdated comment. Use get_name method instead of accessing + pc.normalized_path directly. + (readdir_get_ino): Drop unused dir parameter. Accomodate throughout. + Allocate fname dynamically. Call new stat_worker instead of lstat64. + Call NtOpenFile instead of CreateFile. Call NtClose instead of + CloseHandle. + (fhandler_disk_file::readdir_helper): Use native NT functions. + Check for volume mount points and use correct inode number. + (fhandler_disk_file::readdir): Simplify slightly. + Use get_name instead of pc.normalized_path. + (fhandler_disk_file::rewinddir): Use RtlInitUnicodeString. + (fhandler_cygdrive::fstat): Ignore floppy drives. Set st_nlink + correctly. + (fhandler_cygdrive::readdir): Ignore floppy drives. + * fhandler_netdrive.cc (fhandler_netdrive::readdir): Accommodate + change to readdir_get_ino. + * fhandler_proc.cc (PROC_DIR_COUNT): Define. + (fhandler_proc::fstat): Evaluate correct link count for /proc. + * ntdll.h (struct _FILE_DIRECTORY_INFORMATION): Define. + (NtFsControlFile): Declare. + (RtlAppendUnicodeToString): Declare. + (RtlAppendUnicodeStringToString): Declare. + (RtlCompareUnicodeString): Declare. + (RtlCopyUnicodeString): Declare. + (RtlCreateUnicodeStringFromAsciiz): Declare. + (RtlEqualUnicodeString): Declare. + (RtlFreeUnicodeString): Declare. + (RtlInitEmptyUnicodeString): Declare. + (RtlSecondsSince1970ToTime): Declare. + (RtlInitEmptyUnicodeString): Define as inline function. + (RtlInitCountedUnicodeString): Define as inline function. + * path.cc (path_conv::check): New method with PUNICODE_STRING as path, + preliminary implementation. + (mount_info::get_mounts_here): Change to create UNICODE_STRINGs. + Also copy cygpath prefix into UNICODE_STRING. + (is_floppy): Drop 9x consideration. + * path.h: Drop including ntdef.h. + (path_conv::check): Add declaration. + (path_conv::path_conv): Add constructor for UNICODE_STRING paths. + * shared_info.h (mount_info::get_mounts_here): Change declaration. + * syscalls.cc: Drop forward declaration of stat_worker. + (stat_worke): Take path_conv as parameter. Drop nofollow flag. + (stat64): Create matching path_conv and call stat_worker with it. + (lstat64): Ditto. + * winsup.h: Include ntdef.h. + (stat_worker): Declare. + (readdir_get_ino): Change declaration. + 2007-07-25 Corinna Vinschen * autoload.cc (CreateToolhelp32Snapshot): Remove. @@ -172,8 +244,8 @@ 2007-07-16 Corinna Vinschen * cygheap.h (cygheap_user::curr_imp_token): Rename from current_token. - Accommodate changge throughout Cygwin. - (cygheap_user::imp_token): Rename from token. Accommodate changge + Accommodate change throughout Cygwin. + (cygheap_user::imp_token): Rename from token. Accommodate change throughout Cygwin. (rcygheap_user::eimpersonate): Use primary token for impersonation. * grp.cc (internal_getgroups): Use primary impersonation token when diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc index 822a5e5fe..72d6ac1ab 100644 --- a/winsup/cygwin/dir.cc +++ b/winsup/cygwin/dir.cc @@ -132,8 +132,7 @@ readdir_worker (DIR *dir, dirent *de) } if (is_dot_dot && !(dir->__flags & dirent_isroot)) - de->d_ino = readdir_get_ino (dir, - ((fhandler_base *) dir->__fh)->get_name (), + de->d_ino = readdir_get_ino (((fhandler_base *) dir->__fh)->get_name (), true); else { diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 07b26607e..cf1f27cc0 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -671,7 +671,7 @@ class fhandler_dev_tape: public fhandler_dev_raw class fhandler_disk_file: public fhandler_base { - int readdir_helper (DIR *, dirent *, DWORD, DWORD, char *) __attribute__ ((regparm (3))); + int readdir_helper (DIR *, dirent *, DWORD, DWORD, PUNICODE_STRING fname) __attribute__ ((regparm (3))); public: fhandler_disk_file (); diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 59fcb4450..dd2034095 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -26,7 +26,6 @@ details. */ #include "cygheap.h" #include "shared_info.h" #include "pinfo.h" -#include #include "ntdll.h" #include #include @@ -37,11 +36,12 @@ details. */ class __DIR_mounts { - int count; - const char *parent_dir; - int parent_dir_len; - char *mounts[MAX_MOUNTS]; - bool found[MAX_MOUNTS + 2]; + int count; + const char *parent_dir; + int parent_dir_len; + UNICODE_STRING mounts[MAX_MOUNTS]; + bool found[MAX_MOUNTS + 2]; + UNICODE_STRING cygdrive; #define __DIR_PROC (MAX_MOUNTS) #define __DIR_CYGDRIVE (MAX_MOUNTS+1) @@ -49,15 +49,16 @@ class __DIR_mounts __ino64_t eval_ino (int idx) { __ino64_t ino = 0; - char fname[CYG_MAX_PATH]; + char fname[parent_dir_len + mounts[idx].Length / sizeof (WCHAR) + 2]; struct __stat64 st; - int len = parent_dir_len; - strcpy (fname, parent_dir); - if (fname[len - 1] != '/') - fname[len++] = '/'; - strcpy (fname + len, mounts[idx]); - if (!lstat64 (fname, &st)) + char *c = stpcpy (fname, parent_dir); + if (c[- 1] != '/') + *c++ = '/'; + sys_wcstombs (c, mounts[idx].Length / sizeof (WCHAR) + 1, + mounts[idx].Buffer, mounts[idx].Length / sizeof (WCHAR)); + path_conv pc (fname, PC_SYM_NOFOLLOW | PC_POSIX); + if (!stat_worker (pc, &st)) ino = st.st_ino; return ino; } @@ -67,59 +68,73 @@ public: : parent_dir (posix_path) { parent_dir_len = strlen (parent_dir); - count = mount_table->get_mounts_here (parent_dir, parent_dir_len, mounts); + count = mount_table->get_mounts_here (parent_dir, parent_dir_len, mounts, + &cygdrive); rewind (); } - __ino64_t check_mount (const char *name, __ino64_t ino, bool eval = true) + ~__DIR_mounts () + { + for (int i = 0; i < count; ++i) + RtlFreeUnicodeString (&mounts[i]); + RtlFreeUnicodeString (&cygdrive); + } + __ino64_t check_mount (PUNICODE_STRING fname, __ino64_t ino, + bool eval = true) { if (parent_dir_len == 1) /* root dir */ { - if (strcasematch (name, "proc")) + UNICODE_STRING proc; + + RtlInitUnicodeString (&proc, L"proc"); + if (RtlEqualUnicodeString (fname, &proc, TRUE)) { found[__DIR_PROC] = true; - return hash_path_name (0, "/proc"); + return 2; } - if (strlen (name) == mount_table->cygdrive_len - 2 - && strncasematch (name, mount_table->cygdrive + 1, - mount_table->cygdrive_len - 2)) + if (fname->Length / sizeof (WCHAR) == mount_table->cygdrive_len - 2 + && RtlEqualUnicodeString (fname, &cygdrive, TRUE)) { found[__DIR_CYGDRIVE] = true; return 2; } } for (int i = 0; i < count; ++i) - if (strcasematch (name, mounts[i])) + if (RtlEqualUnicodeString (fname, &mounts[i], TRUE)) { found[i] = true; return eval ? eval_ino (i) : 1; } return ino; } - __ino64_t check_missing_mount (char *ret_name, bool eval = true) + __ino64_t check_missing_mount (PUNICODE_STRING retname = NULL) { for (int i = 0; i < count; ++i) if (!found[i]) { found[i] = true; - strcpy (ret_name, mounts[i]); - return eval ? eval_ino (i) : 1; + if (retname) + { + *retname = mounts[i]; + return eval_ino (i); + } + return 1; } if (parent_dir_len == 1) /* root dir */ { if (!found[__DIR_PROC]) { found[__DIR_PROC] = true; - strcpy (ret_name, "proc"); - return hash_path_name (0, "/proc"); + if (retname) + RtlInitUnicodeString (retname, L"proc"); + return 2; } if (!found[__DIR_CYGDRIVE]) { found[__DIR_CYGDRIVE] = true; - if (mount_table->cygdrive_len > 1) + if (cygdrive.Length > 0) { - strncpy (ret_name, mount_table->cygdrive + 1, - mount_table->cygdrive_len - 2); - ret_name[mount_table->cygdrive_len - 2] = '\0'; + if (retname) + *retname = cygdrive; return 2; } } @@ -135,66 +150,91 @@ path_conv::ndisk_links (DWORD nNumberOfLinks) if (!isdir () || isremote ()) return nNumberOfLinks; - int len = strlen (*this); - char fn[len + 3]; - strcpy (fn, *this); + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + HANDLE fh; - const char *s; - unsigned count; + if (!NT_SUCCESS (NtOpenFile (&fh, SYNCHRONIZE | FILE_LIST_DIRECTORY, + get_object_attr (attr, sec_none_nih), + &io, FILE_SHARE_VALID_FLAGS, + FILE_SYNCHRONOUS_IO_NONALERT + | FILE_OPEN_FOR_BACKUP_INTENT + | FILE_DIRECTORY_FILE))) + return nNumberOfLinks; + + unsigned count = 0; + bool first = true; + NTSTATUS status; + PFILE_DIRECTORY_INFORMATION fdibuf = (PFILE_DIRECTORY_INFORMATION) + alloca (65536); __DIR_mounts *dir = new __DIR_mounts (normalized_path); - if (nNumberOfLinks <= 1) + while (NT_SUCCESS (NtQueryDirectoryFile (fh, NULL, NULL, 0, &io, fdibuf, + 65536, FileDirectoryInformation, + FALSE, NULL, first))) { - s = "\\*"; - count = 0; - } - else - { - s = "\\.."; - count = nNumberOfLinks; - } + if (first) + { + first = false; + /* All directories have . and .. as their first entries. + If . is not present as first entry, we're on a drive's + root direcotry, which doesn't have these entries. */ + if (fdibuf->FileNameLength != 2 || fdibuf->FileName[0] != L'.') + count = 2; + } + for (PFILE_DIRECTORY_INFORMATION pfdi = fdibuf; + pfdi; + pfdi = (PFILE_DIRECTORY_INFORMATION) + (pfdi->NextEntryOffset ? (PBYTE) pfdi + pfdi->NextEntryOffset + : NULL)) + { + switch (pfdi->FileAttributes + & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) + { + case FILE_ATTRIBUTE_DIRECTORY: + /* Just a directory */ + ++count; + break; + case FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT: + /* Volume mount point or symlink to directory */ + { + HANDLE reph; + UNICODE_STRING fname; - if (len == 0 || isdirsep (fn[len - 1])) - strcpy (fn + len, s + 1); - else - strcpy (fn + len, s); - - WIN32_FIND_DATA buf; - HANDLE h = FindFirstFile (fn, &buf); - - int saw_dot = 2; - if (h != INVALID_HANDLE_VALUE) - { - if (nNumberOfLinks > 1) - saw_dot--; - else - do - { - if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - count++; - if (buf.cFileName[0] == '.' - && (buf.cFileName[1] == '\0' - || (buf.cFileName[1] == '.' && buf.cFileName[2] == '\0'))) - saw_dot--; - dir->check_mount (buf.cFileName, 0, false); - } - while (FindNextFileA (h, &buf)); - FindClose (h); + RtlInitCountedUnicodeString (&fname, pfdi->FileNameLength, + pfdi->FileName); + InitializeObjectAttributes (&attr, &fname, + OBJ_CASE_INSENSITIVE, fh, NULL); + if (NT_SUCCESS (status = NtOpenFile (&reph, READ_CONTROL, &attr, &io, + FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT + | FILE_OPEN_REPARSE_POINT))) + { + PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER) + alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + if (NT_SUCCESS (NtFsControlFile (reph, NULL, NULL, NULL, + &io, FSCTL_GET_REPARSE_POINT, NULL, 0, + (LPVOID) rp, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)) + && rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT + && rp->SymbolicLinkReparseBuffer.PrintNameLength == 0) + ++count; + NtClose (reph); + } + } + break; + default: + break; + } + UNICODE_STRING fname; + RtlInitCountedUnicodeString (&fname, pfdi->FileNameLength, + pfdi->FileName); + dir->check_mount (&fname, 0, false); + } } - - if (nNumberOfLinks > 1) - { - fn[len + 2] = '\0'; - h = FindFirstFile (fn, &buf); - if (h) - saw_dot--; - FindClose (h); - } - while (dir->check_missing_mount (buf.cFileName, false)) + while (dir->check_missing_mount ()) ++count; - + NtClose (dir); delete dir; - - return count + saw_dot; + return count; } inline bool @@ -214,9 +254,10 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) NTSTATUS status; IO_STATUS_BLOCK io; /* The entries potentially contain a name of MAX_PATH wide characters. */ - const DWORD fvi_size = 2 * CYG_MAX_PATH + const DWORD fvi_size = (NAME_MAX + 1) * sizeof (WCHAR) + sizeof (FILE_FS_VOLUME_INFORMATION); - const DWORD fai_size = 2 * CYG_MAX_PATH + sizeof (FILE_ALL_INFORMATION); + const DWORD fai_size = (NAME_MAX + 1) * sizeof (WCHAR) + + sizeof (FILE_ALL_INFORMATION); PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION) alloca (fvi_size); @@ -228,7 +269,7 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) { debug_printf ("%u = NtQueryVolumeInformationFile)", RtlNtStatusToDosError (status)); - pfvi->VolumeSerialNumber = 0; /* Set to pc.volser () in helper. */ + pfvi->VolumeSerialNumber = pc.volser (); } status = NtQueryInformationFile (get_handle (), &io, pfai, fai_size, FileAllInformation); @@ -241,9 +282,9 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) pfai->BasicInformation.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; pc.file_attributes (pfai->BasicInformation.FileAttributes); return fstat_helper (buf, - pfai->BasicInformation.ChangeTime.QuadPart ? - *(FILETIME *) &pfai->BasicInformation.ChangeTime : - *(FILETIME *) &pfai->BasicInformation.LastWriteTime, + pfai->BasicInformation.ChangeTime.QuadPart + ? *(FILETIME *) &pfai->BasicInformation.ChangeTime + : *(FILETIME *) &pfai->BasicInformation.LastWriteTime, *(FILETIME *) &pfai->BasicInformation.LastAccessTime, *(FILETIME *) &pfai->BasicInformation.LastWriteTime, *(FILETIME *) &pfai->BasicInformation.CreationTime, @@ -254,66 +295,119 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) pfai->StandardInformation.NumberOfLinks, pfai->BasicInformation.FileAttributes); } - debug_printf ("%u = NtQueryInformationFile)", RtlNtStatusToDosError (status)); - - /* Last resort */ - FILETIME ft = { 0, 0 }; - DWORD lowfs, highfs; - - lowfs = GetFileSize (get_handle (), &highfs); - if (lowfs == 0xffffffff && GetLastError ()) - lowfs = highfs = 0; - return fstat_helper (buf, ft, ft, ft, ft, 0, (ULONGLONG) highfs << 32 | lowfs, - -1LL, 0ULL, 1, DWORD (pc)); + return -1; } int __stdcall fhandler_base::fstat_by_name (struct __stat64 *buf) { - int res = -1; NTSTATUS status; OBJECT_ATTRIBUTES attr; - FILE_NETWORK_OPEN_INFORMATION fnoi; + IO_STATUS_BLOCK io; + UNICODE_STRING dirname; + UNICODE_STRING basename; + HANDLE dir; + const DWORD fdi_size = (NAME_MAX + 1) * sizeof (WCHAR) + + sizeof (FILE_ID_BOTH_DIR_INFORMATION); + const DWORD fvi_size = (NAME_MAX + 1) * sizeof (WCHAR) + + sizeof (FILE_FS_VOLUME_INFORMATION); + PFILE_ID_BOTH_DIR_INFORMATION pfdi = (PFILE_ID_BOTH_DIR_INFORMATION) + alloca (fdi_size); + PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION) + alloca (fvi_size); + LARGE_INTEGER FileId; if (!pc.exists ()) { debug_printf ("already determined that pc does not exist"); set_errno (ENOENT); + return -1; } - else if (NT_SUCCESS (status = NtQueryFullAttributesFile ( - pc.get_object_attr (attr, sec_none_nih), &fnoi))) + /* Split path in dirname and basename */ + dirname = *pc.get_nt_native_path (); + USHORT len = dirname.Length / sizeof (WCHAR); + while (len > 0 && dirname.Buffer[--len] != L'\\') + ; + ++len; + RtlInitCountedUnicodeString (&basename, + dirname.Length - len * sizeof (WCHAR), + &dirname.Buffer[len]); + dirname.Length = len * sizeof (WCHAR); + InitializeObjectAttributes (&attr, &dirname, OBJ_CASE_INSENSITIVE, + NULL, NULL); + if (!NT_SUCCESS (status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY, + &attr, &io, FILE_SHARE_VALID_FLAGS, + FILE_SYNCHRONOUS_IO_NONALERT + | FILE_OPEN_FOR_BACKUP_INTENT + | FILE_DIRECTORY_FILE))) { - if (pc.is_rep_symlink ()) - fnoi.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; - pc.file_attributes (fnoi.FileAttributes); - res = fstat_helper (buf, - *(FILETIME *) (fnoi.ChangeTime.QuadPart - ? &fnoi.ChangeTime - : &fnoi.LastWriteTime), - *(FILETIME *) &fnoi.LastAccessTime, - *(FILETIME *) &fnoi.LastWriteTime, - *(FILETIME *) &fnoi.CreationTime, + debug_printf ("%u = NtOpenFile)", RtlNtStatusToDosError (status)); + goto too_bad; + } + if (wincap.has_fileid_dirinfo () + && NT_SUCCESS (status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, + pfdi, fdi_size, + FileIdBothDirectoryInformation, + TRUE, &basename, TRUE))) + FileId = pfdi->FileId; + else if (NT_SUCCESS (status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, + pfdi, fdi_size, + FileBothDirectoryInformation, + TRUE, &basename, TRUE))) + FileId.QuadPart = 0; /* get_namehash is called in fstat_helper. */ + if (!NT_SUCCESS (status)) + { + debug_printf ("%u = NtQueryDirectoryFile)", + RtlNtStatusToDosError (status)); + NtClose (dir); + goto too_bad; + } + status = NtQueryVolumeInformationFile (dir, &io, pfvi, fvi_size, + FileFsVolumeInformation); + if (!NT_SUCCESS (status)) + { + debug_printf ("%u = NtQueryVolumeInformationFile)", + RtlNtStatusToDosError (status)); + pfvi->VolumeSerialNumber = pc.volser (); + } + NtClose (dir); + /* If the change time is 0, it's a file system which doesn't + support a change timestamp. In that case use the LastWriteTime + entry, as in other calls to fstat_helper. */ + if (pc.is_rep_symlink ()) + pfdi->FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; + pc.file_attributes (pfdi->FileAttributes); + return fstat_helper (buf, + pfdi->ChangeTime.QuadPart ? + *(FILETIME *) &pfdi->ChangeTime : + *(FILETIME *) &pfdi->LastWriteTime, + *(FILETIME *) &pfdi->LastAccessTime, + *(FILETIME *) &pfdi->LastWriteTime, + *(FILETIME *) &pfdi->CreationTime, + pfvi->VolumeSerialNumber, + pfdi->EndOfFile.QuadPart, + pfdi->AllocationSize.QuadPart, + pfdi->FileId.QuadPart, + 1, + pfdi->FileAttributes); + +too_bad: + LARGE_INTEGER ft; + /* Arbitrary value: 2006-12-01 */ + RtlSecondsSince1970ToTime (1164931200L, &ft); + return fstat_helper (buf, + *(FILETIME *) &ft, + *(FILETIME *) &ft, + *(FILETIME *) &ft, + *(FILETIME *) &ft, pc.volser (), - fnoi.EndOfFile.QuadPart, - fnoi.AllocationSize.QuadPart, + 0ULL, + -1LL, 0ULL, 1, - fnoi.FileAttributes); - } - else if (pc.isdir ()) - { - FILETIME ft = {}; - res = fstat_helper (buf, ft, ft, ft, ft, pc.volser (), 0ULL, -1LL, 0ULL, - 1, FILE_ATTRIBUTE_DIRECTORY); - } - else - { - __seterrno_from_nt_status (status); - res = -1; - } - return res; + pc.file_attributes ()); } int __stdcall @@ -325,10 +419,11 @@ fhandler_base::fstat_fs (struct __stat64 *buf) if (get_io_handle ()) { - if (nohandle () || is_fs_special ()) - return fstat_by_name (buf); - else - return fstat_by_handle (buf); + if (!nohandle () && !is_fs_special ()) + res = fstat_by_handle (buf); + if (res) + res = fstat_by_name (buf); + return res; } query_open (query_stat_control); if (!(oret = open_fs (open_flags, 0)) && get_errno () == EACCES) @@ -353,7 +448,7 @@ fhandler_base::fstat_fs (struct __stat64 *buf) nohandle (no_handle); set_io_handle (NULL); } - else + if (res) res = fstat_by_name (buf); return res; @@ -389,7 +484,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf, to_timestruc_t (&ftLastWriteTime, &buf->st_mtim); to_timestruc_t (&ftChangeTime, &buf->st_ctim); to_timestruc_t (&ftCreationTime, &buf->st_birthtim); - buf->st_dev = dwVolumeSerialNumber ?: pc.volser (); + buf->st_dev = dwVolumeSerialNumber; buf->st_size = (_off64_t) nFileSize; /* The number of links to a directory includes the number of subdirectories in the directory, since all @@ -753,10 +848,10 @@ fhandler_disk_file::facl (int cmd, int nentries, __aclent32_t *aclbufp) if (!get_io_handle ()) { query_open (query_read_attributes); - if (!(oret = open (O_BINARY, 0))) - return -1; + oret = open (O_BINARY, 0); } - if (!fstat_by_handle (&st)) + if ((!oret && !fstat_by_handle (&st)) + || !fstat_by_name (&st)) { aclbufp[0].a_type = USER_OBJ; aclbufp[0].a_id = st.st_uid; @@ -1482,22 +1577,20 @@ fhandler_disk_file::rmdir () /* This is the minimal number of entries which fit into the readdir cache. The number of bytes allocated by the cache is determined by this number, To tune caching, just tweak this number. To get a feeling for the size, - the size of the readdir cache is DIR_NUM_ENTRIES * 632 + 264 bytes. */ + the size of the readdir cache is DIR_NUM_ENTRIES * 624 + 4 bytes. */ -#define DIR_NUM_ENTRIES 100 /* Cache size 63464 bytes */ +#define DIR_NUM_ENTRIES 100 /* Cache size 62404 bytes */ #define DIR_BUF_SIZE (DIR_NUM_ENTRIES \ * (sizeof (FILE_ID_BOTH_DIR_INFORMATION) \ - + 2 * CYG_MAX_PATH)) + + 2 * (NAME_MAX + 1))) struct __DIR_cache { - char __name[CYG_MAX_PATH]; ULONG __pos; char __cache[DIR_BUF_SIZE]; }; -#define d_dirname(d) (((__DIR_cache *) (d)->__d_dirname)->__name) #define d_cachepos(d) (((__DIR_cache *) (d)->__d_dirname)->__pos) #define d_cache(d) (((__DIR_cache *) (d)->__d_dirname)->__cache) @@ -1508,12 +1601,9 @@ fhandler_disk_file::opendir (int fd) { DIR *dir; DIR *res = NULL; - size_t len; if (!pc.isdir ()) set_errno (ENOTDIR); - else if ((len = strlen (pc)) > CYG_MAX_PATH - 3) - set_errno (ENAMETOOLONG); else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL) set_errno (ENOMEM); else if ((dir->__d_dirname = (char *) malloc ( sizeof (struct __DIR_cache))) @@ -1530,30 +1620,17 @@ fhandler_disk_file::opendir (int fd) } else { - strcpy (d_dirname (dir), get_win32_name ()); - dir->__d_dirent->__d_version = __DIRENT_VERSION; cygheap_fdnew cfd; - if (cfd < 0 && fd < 0) goto free_dirent; - /* FindFirstFile doesn't seem to like duplicate /'s. - The dirname is generated with trailing backslash here which - simplifies later usage of dirname for checking symlinks. - Appending a "*" is moved right before calling FindFirstFile. - Since FindFirstFile is only called once, this should even be a - teeny little bit faster. */ - len = strlen (d_dirname (dir)); - if (len && !isdirsep (d_dirname (dir)[len - 1])) - strcpy (d_dirname (dir) + len, "\\"); + dir->__d_dirent->__d_version = __DIRENT_VERSION; dir->__d_cookie = __DIRENT_COOKIE; dir->__handle = INVALID_HANDLE_VALUE; dir->__d_position = 0; - - dir->__flags = (pc.normalized_path[0] == '/' - && pc.normalized_path[1] == '\0') + dir->__flags = (get_name ()[0] == '/' && get_name ()[1] == '\0') ? dirent_isroot : 0; - dir->__d_internal = (unsigned) new __DIR_mounts (pc.normalized_path); + dir->__d_internal = (unsigned) new __DIR_mounts (get_name ()); d_cachepos (dir) = 0; if (!pc.iscygdrive ()) @@ -1628,50 +1705,6 @@ free_dir: return res; } -int -fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err, - DWORD attr, char *fname) -{ - if (w32_err) - { - bool added = false; - if ((de->d_ino = d_mounts (dir)->check_missing_mount (fname))) - added = true; - if (!added) - return geterrno_from_win_error (w32_err); - - attr = 0; - dir->__flags &= ~dirent_set_d_ino; - } - - /* Check for Windows shortcut. If it's a Cygwin or U/WIN - symlink, drop the .lnk suffix. */ - if (attr & FILE_ATTRIBUTE_READONLY) - { - char *c = fname; - char *e = strchr (fname, '\0') - 4; - if (e > c && strcasematch (e, ".lnk")) - { - char fbuf[CYG_MAX_PATH]; - strcpy (fbuf, d_dirname (dir)); - strcat (fbuf, c); - path_conv fpath (fbuf, PC_SYM_NOFOLLOW); - if (fpath.issymlink () || fpath.is_fs_special ()) - *e = '\0'; - } - } - - if (pc.isencoded ()) - fnunmunge (de->d_name, fname); - else - strcpy (de->d_name, fname); - if (dir->__d_position == 0 && !strcmp (fname, ".")) - dir->__flags |= dirent_saw_dot; - else if (dir->__d_position == 1 && !strcmp (fname, "..")) - dir->__flags |= dirent_saw_dot_dot; - return 0; -} - static inline __ino64_t readdir_get_ino_by_handle (HANDLE hdl) { @@ -1685,45 +1718,150 @@ readdir_get_ino_by_handle (HANDLE hdl) } __ino64_t __stdcall -readdir_get_ino (DIR *dir, const char *path, bool dot_dot) +readdir_get_ino (const char *path, bool dot_dot) { - char fname[CYG_MAX_PATH]; + char *fname; struct __stat64 st; HANDLE hdl; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; __ino64_t ino = 0; - strcpy (fname, path); if (dot_dot) - strcat (fname, (*fname && fname[strlen (fname) - 1] == '/') - ? ".." : "/.."); - path_conv pc (fname, PC_SYM_NOFOLLOW); + { + fname = (char *) alloca (strlen (path) + 4); + char *c = stpcpy (fname, path); + if (c[-1] != '/') + *c++ = '/'; + strcpy (c, ".."); + path = fname; + } + path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX); if (pc.isspecial ()) { - if (!lstat64 (fname, &st)) + if (!stat_worker (pc, &st)) ino = st.st_ino; } else if (!pc.hasgood_inode ()) ino = hash_path_name (0, pc); - else if ((hdl = CreateFile (pc, GENERIC_READ, FILE_SHARE_VALID_FLAGS, - NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, NULL)) - != INVALID_HANDLE_VALUE) + else if (NT_SUCCESS (NtOpenFile (&hdl, READ_CONTROL, + pc.get_object_attr (attr, sec_none_nih), + &io, FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT))) { ino = readdir_get_ino_by_handle (hdl); - CloseHandle (hdl); + NtClose (hdl); } return ino; } +int +fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err, + DWORD attr, PUNICODE_STRING fname) +{ + if (w32_err) + { + bool added = false; + if ((de->d_ino = d_mounts (dir)->check_missing_mount (fname))) + added = true; + if (!added) + return geterrno_from_win_error (w32_err); + + attr = 0; + dir->__flags &= ~dirent_set_d_ino; + } + + /* Check for directory reparse point. These are potential volume mount + points which have another inode than the underlying directory. */ + if ((attr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) + == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) + { + HANDLE reph; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + + InitializeObjectAttributes (&attr, fname, OBJ_CASE_INSENSITIVE, + get_handle (), NULL); + if (NT_SUCCESS (NtOpenFile (&reph, READ_CONTROL, &attr, &io, + FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT + | FILE_OPEN_REPARSE_POINT))) + { + PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER) + alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + if (NT_SUCCESS (NtFsControlFile (reph, NULL, NULL, NULL, + &io, FSCTL_GET_REPARSE_POINT, NULL, 0, + (LPVOID) rp, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)) + && rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT + && rp->SymbolicLinkReparseBuffer.PrintNameLength == 0) + { + NtClose (reph); + if (NT_SUCCESS (NtOpenFile (&reph, READ_CONTROL, &attr, &io, + FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT))) + { + de->d_ino = readdir_get_ino_by_handle (reph); + NtClose (reph); + } + } + else + NtClose (reph); + } + } + + /* Check for Windows shortcut. If it's a Cygwin or U/WIN + symlink, drop the .lnk suffix. */ + if ((attr & FILE_ATTRIBUTE_READONLY) && fname->Length > 4 * sizeof (WCHAR)) + { + UNICODE_STRING uname; + UNICODE_STRING lname; + + RtlInitCountedUnicodeString (&uname, 4 * sizeof (WCHAR), + fname->Buffer + + fname->Length / sizeof (WCHAR) - 4); + RtlInitCountedUnicodeString (&lname, 4 * sizeof (WCHAR), + (PWCHAR) L".lnk"); + + if (RtlEqualUnicodeString (&uname, &lname, TRUE)) + { + UNICODE_STRING dirname = *pc.get_nt_native_path (); + dirname.Buffer += 4; /* Skip leading \??\ */ + dirname.Length -= 4 * sizeof (WCHAR); + UNICODE_STRING fbuf; + ULONG len = dirname.Length + fname->Length + 2 * sizeof (WCHAR); + + RtlInitEmptyUnicodeString (&fbuf, (PCWSTR) alloca (len), len); + RtlCopyUnicodeString (&fbuf, &dirname); + RtlAppendUnicodeToString (&fbuf, L"\\"); + RtlAppendUnicodeStringToString (&fbuf, fname); + path_conv fpath (&fbuf, PC_SYM_NOFOLLOW); + if (fpath.issymlink () || fpath.is_fs_special ()) + fname->Length -= 4 * sizeof (WCHAR); + } + } + + char tmp[NAME_MAX + 1]; + sys_wcstombs (tmp, NAME_MAX, fname->Buffer, fname->Length / sizeof (WCHAR)); + if (pc.isencoded ()) + fnunmunge (de->d_name, tmp); + else + strcpy (de->d_name, tmp); + if (dir->__d_position == 0 && !strcmp (tmp, ".")) + dir->__flags |= dirent_saw_dot; + else if (dir->__d_position == 1 && !strcmp (tmp, "..")) + dir->__flags |= dirent_saw_dot_dot; + return 0; +} + int fhandler_disk_file::readdir (DIR *dir, dirent *de) { int res = 0; NTSTATUS status = STATUS_SUCCESS; PFILE_ID_BOTH_DIR_INFORMATION buf = NULL; - wchar_t *FileName; - char fname[CYG_MAX_PATH]; + PWCHAR FileName; IO_STATUS_BLOCK io; + UNICODE_STRING fname; /* d_cachepos always refers to the next cache entry to use. If it's 0 we must reload the cache. */ @@ -1818,9 +1956,8 @@ go_ahead: } else FileName = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileName; - sys_wcstombs (fname, CYG_MAX_PATH - 1, FileName, buf->FileNameLength / 2); - - de->d_ino = d_mounts (dir)->check_mount (fname, de->d_ino); + RtlInitCountedUnicodeString (&fname, buf->FileNameLength, FileName); + de->d_ino = d_mounts (dir)->check_mount (&fname, de->d_ino); if (de->d_ino == 0 && (dir->__flags & dirent_set_d_ino)) { OBJECT_ATTRIBUTES attr; @@ -1829,24 +1966,23 @@ go_ahead: && FileName[0] == '.') de->d_ino = readdir_get_ino_by_handle (get_handle ()); else if (dir->__d_position == 1 && buf->FileNameLength == 4 - && FileName[0] == '.' && FileName[1] == '.') + && FileName[0] == L'.' && FileName[1] == L'.') if (!(dir->__flags & dirent_isroot)) - de->d_ino = readdir_get_ino (dir, pc.normalized_path, true); + de->d_ino = readdir_get_ino (get_name (), true); else de->d_ino = readdir_get_ino_by_handle (get_handle ()); else { HANDLE hdl; - UNICODE_STRING upath = {buf->FileNameLength, CYG_MAX_PATH * 2, - FileName}; - InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, - get_handle () , NULL); - if (!NtOpenFile (&hdl, READ_CONTROL, &attr, &io, - FILE_SHARE_VALID_FLAGS, - FILE_OPEN_FOR_BACKUP_INTENT)) + + InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE, + get_handle (), NULL); + if (NT_SUCCESS (NtOpenFile (&hdl, READ_CONTROL, &attr, &io, + FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT))) { de->d_ino = readdir_get_ino_by_handle (hdl); - CloseHandle (hdl); + NtClose (hdl); } } /* Enforce namehash as inode number on untrusted file systems. */ @@ -1859,7 +1995,7 @@ go_ahead: } if (!(res = readdir_helper (dir, de, RtlNtStatusToDosError (status), - buf ? buf->FileAttributes : 0, fname))) + buf ? buf->FileAttributes : 0, &fname))) dir->__d_position++; else if (!(dir->__flags & dirent_saw_dot)) { @@ -1873,7 +2009,7 @@ go_ahead: { strcpy (de->d_name , ".."); if (!(dir->__flags & dirent_isroot)) - de->d_ino = readdir_get_ino (dir, pc.normalized_path, true); + de->d_ino = readdir_get_ino (get_name (), true); else de->d_ino = readdir_get_ino_by_handle (get_handle ()); dir->__d_position++; @@ -1910,12 +2046,13 @@ fhandler_disk_file::rewinddir (DIR *dir) to NtQueryDirectoryFile on remote shares is ignored, thus resulting in not being able to rewind on remote shares. By reopening the directory, we get a fresh new directory pointer. */ - UNICODE_STRING fname = {0, CYG_MAX_PATH * 2, (WCHAR *) L""}; + UNICODE_STRING fname; OBJECT_ATTRIBUTES attr; NTSTATUS status; IO_STATUS_BLOCK io; HANDLE new_dir; + RtlInitUnicodeString (&fname, L""); InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE, get_handle (), NULL); status = NtOpenFile (&new_dir, SYNCHRONIZE | FILE_LIST_DIRECTORY, @@ -2003,9 +2140,18 @@ fhandler_cygdrive::set_drives () int fhandler_cygdrive::fstat (struct __stat64 *buf) { - buf->st_mode = S_IFDIR | 0555; + fhandler_base::fstat (buf); buf->st_ino = 2; - buf->st_nlink = 1; + buf->st_mode = S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + if (!ndrives) + set_drives (); + char flptst[] = "X:"; + int n = ndrives; + for (const char *p = pdrive; p && *p; p = strchr (p, '\0') + 1) + if (is_floppy ((flptst[0] = *p, flptst)) + || GetFileAttributes (p) == INVALID_FILE_ATTRIBUTES) + --n; + buf->st_nlink = n + 2; return 0; } @@ -2024,6 +2170,8 @@ fhandler_cygdrive::opendir (int fd) int fhandler_cygdrive::readdir (DIR *dir, dirent *de) { + char flptst[] = "X:"; + while (true) { if (!pdrive || !*pdrive) @@ -2036,13 +2184,15 @@ fhandler_cygdrive::readdir (DIR *dir, dirent *de) } return ENMFILE; } - if (GetFileAttributes (pdrive) != INVALID_FILE_ATTRIBUTES) + if (!is_floppy ((flptst[0] = *pdrive, flptst)) + && GetFileAttributes (pdrive) != INVALID_FILE_ATTRIBUTES) break; pdrive = strchr (pdrive, '\0') + 1; } *de->d_name = cyg_tolower (*pdrive); de->d_name[1] = '\0'; - de->d_ino = readdir_get_ino (dir, pdrive, false); + user_shared->warned_msdos = true; + de->d_ino = readdir_get_ino (pdrive, false); dir->__d_position++; pdrive = strchr (pdrive, '\0') + 1; syscall_printf ("%p = readdir (%p) (%s)", &de, dir, de->d_name); diff --git a/winsup/cygwin/fhandler_netdrive.cc b/winsup/cygwin/fhandler_netdrive.cc index 975caf105..a72bbab0e 100644 --- a/winsup/cygwin/fhandler_netdrive.cc +++ b/winsup/cygwin/fhandler_netdrive.cc @@ -210,7 +210,7 @@ fhandler_netdrive::readdir (DIR *dir, dirent *de) de->d_ino = hash_path_name (get_namehash (), de->d_name); else { - de->d_ino = readdir_get_ino (dir, nro->lpRemoteName, false); + de->d_ino = readdir_get_ino (nro->lpRemoteName, false); /* We can't trust remote inode numbers of only 32 bit. That means, all remote inode numbers when running under NT4, as well as remote NT4 NTFS, as well as shares of Samba version < 3.0. */ diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc index d7da1bc3d..ce0892eda 100644 --- a/winsup/cygwin/fhandler_proc.cc +++ b/winsup/cygwin/fhandler_proc.cc @@ -65,6 +65,8 @@ static const char *proc_listing[] = { NULL }; +#define PROC_DIR_COUNT 4 + static const int PROC_LINK_COUNT = (sizeof (proc_listing) / sizeof (const char *)) - 1; /* FH_PROC in the table below means the file/directory is handles by @@ -178,8 +180,10 @@ fhandler_proc::fstat (struct __stat64 *buf) if (!*path) { - buf->st_nlink = 1; + winpids pids ((DWORD) 0); + buf->st_ino = 2; buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + buf->st_nlink = PROC_DIR_COUNT + 2 + pids.npids; return 0; } else diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 973d48ee6..d3837bb99 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -88,6 +88,20 @@ typedef struct _FILE_NAMES_INFORMATION WCHAR FileName[1]; } FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; +typedef struct _FILE_DIRECTORY_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; + typedef struct _FILE_BOTH_DIR_INFORMATION { ULONG NextEntryOffset; @@ -709,6 +723,9 @@ extern "C" PTOKEN_GROUPS, PTOKEN_PRIVILEGES, PTOKEN_OWNER, PTOKEN_PRIMARY_GROUP, PTOKEN_DEFAULT_DACL, PTOKEN_SOURCE); + NTSTATUS NTAPI NtFsControlFile (HANDLE, HANDLE, PVOID, PVOID, + PIO_STATUS_BLOCK, ULONG, PVOID, ULONG, + PVOID, ULONG); NTSTATUS NTAPI NtLockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG); NTSTATUS NTAPI NtMapViewOfSection (HANDLE, HANDLE, PVOID *, ULONG, ULONG, PLARGE_INTEGER, PULONG, SECTION_INHERIT, @@ -750,11 +767,42 @@ extern "C" PSECURITY_DESCRIPTOR); NTSTATUS NTAPI NtUnlockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG); NTSTATUS NTAPI NtUnmapViewOfSection (HANDLE, PVOID); + NTSTATUS NTAPI RtlAppendUnicodeToString (PUNICODE_STRING, PCWSTR); + NTSTATUS NTAPI RtlAppendUnicodeStringToString (PUNICODE_STRING, + PUNICODE_STRING); NTSTATUS NTAPI RtlAnsiStringToUnicodeString (PUNICODE_STRING, PANSI_STRING, BOOLEAN); + LONG NTAPI RtlCompareUnicodeString (PUNICODE_STRING, PUNICODE_STRING, + BOOLEAN); + VOID NTAPI RtlCopyUnicodeString (PUNICODE_STRING, PUNICODE_STRING); + ULONG WINAPI RtlCreateUnicodeStringFromAsciiz (PUNICODE_STRING, PCSTR); + BOOLEAN NTAPI RtlEqualUnicodeString (PUNICODE_STRING, PUNICODE_STRING, + BOOLEAN); + VOID NTAPI RtlFreeUnicodeString (PUNICODE_STRING); + VOID NTAPI RtlInitEmptyUnicodeString (PUNICODE_STRING, PCWSTR, USHORT); VOID NTAPI RtlInitUnicodeString (PUNICODE_STRING, PCWSTR); ULONG NTAPI RtlIsDosDeviceName_U (PCWSTR); ULONG NTAPI RtlNtStatusToDosError (NTSTATUS); NTSTATUS NTAPI RtlOemStringToUnicodeString (PUNICODE_STRING, POEM_STRING, BOOLEAN); + VOID NTAPI RtlSecondsSince1970ToTime (ULONG, PLARGE_INTEGER); + + /* A few Rtl functions are either actually macros, or they just don't + exist even though they would be a big help. We implement them here + as inline functions. */ + inline + VOID NTAPI RtlInitEmptyUnicodeString(PUNICODE_STRING dest, PCWSTR buf, + USHORT len) + { + dest->Length = 0; + dest->MaximumLength = len; + dest->Buffer = (PWSTR) buf; + } + inline + VOID NTAPI RtlInitCountedUnicodeString (PUNICODE_STRING dest, USHORT len, + PCWSTR buf) + { + dest->Length = dest->MaximumLength = len; + dest->Buffer = (PWSTR) buf; + } } diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 6e345588e..062f5ab7e 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -637,6 +637,23 @@ warn_msdos (const char *src) SYMLINK_CONTENTS - just return symlink contents */ +/* TODO: This implementation is only preliminary. For internal + purposes it's necessary to have a path_conv::check function which + takes a UNICODE_STRING src path, otherwise we waste a lot of time + for converting back and forth. The below implementation does + realy nothing but converting to char *, until path_conv handles + wide-char paths directly. */ +void +path_conv::check (PUNICODE_STRING src, unsigned opt, + const suffix_info *suffixes) +{ + char path[CYG_MAX_PATH]; + + user_shared->warned_msdos = true; + sys_wcstombs (path, CYG_MAX_PATH, src->Buffer, src->Length / 2); + path_conv::check (path, opt, suffixes); +} + void path_conv::check (const char *src, unsigned opt, const suffix_info *suffixes) @@ -1840,7 +1857,8 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, int mount_info::get_mounts_here (const char *parent_dir, int parent_dir_len, - char **mount_points) + PUNICODE_STRING mount_points, + PUNICODE_STRING cygd) { int n_mounts = 0; @@ -1853,12 +1871,16 @@ mount_info::get_mounts_here (const char *parent_dir, int parent_dir_len, if (last_slash == mi->posix_path) { if (parent_dir_len == 1 && mi->posix_pathlen > 1) - mount_points[n_mounts++] = last_slash + 1; + RtlCreateUnicodeStringFromAsciiz (&mount_points[n_mounts++], + last_slash + 1); } else if (parent_dir_len == last_slash - mi->posix_path && strncasematch (parent_dir, mi->posix_path, parent_dir_len)) - mount_points[n_mounts++] = last_slash + 1; + RtlCreateUnicodeStringFromAsciiz (&mount_points[n_mounts++], + last_slash + 1); } + RtlCreateUnicodeStringFromAsciiz (cygd, cygdrive + 1); + cygd->Length -= 2; // Strip trailing slash return n_mounts; } @@ -2794,8 +2816,7 @@ is_floppy (const char *dos) char dev[256]; if (!QueryDosDevice (dos, dev, 256)) return false; - return strncasematch (dev, "\\Device\\Floppy", 14) - || strcasematch (dev, "A:"); + return strncasematch (dev, "\\Device\\Floppy", 14); } extern "C" FILE * diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 6e553be6b..c9ba9f311 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -13,7 +13,6 @@ details. */ #include #include -#include #define isproc_dev(devn) \ (devn == FH_PROC || devn == FH_REGISTRY || devn == FH_PROCESS || \ @@ -234,8 +233,10 @@ class path_conv void set_has_symlinks () {path_flags |= PATH_HAS_SYMLINKS;} void set_exec (int x = 1) {path_flags |= x ? PATH_EXEC : PATH_NOTEXEC;} + void check (PUNICODE_STRING upath, unsigned opt = PC_SYM_FOLLOW, + const suffix_info *suffixes = NULL) __attribute__ ((regparm(3))); void check (const char *src, unsigned opt = PC_SYM_FOLLOW, - const suffix_info *suffixes = NULL) __attribute__ ((regparm(3))); + const suffix_info *suffixes = NULL) __attribute__ ((regparm(3))); path_conv (const device& in_dev): fileattr (INVALID_FILE_ATTRIBUTES), wide_path (NULL), path_flags (0), known_suffix (NULL), error (0), @@ -250,6 +251,12 @@ class path_conv check (src, opt, suffixes); } + path_conv (PUNICODE_STRING src, unsigned opt = PC_SYM_FOLLOW, + const suffix_info *suffixes = NULL) + { + check (src, opt | PC_NULLEMPTY, suffixes); + } + path_conv (const char *src, unsigned opt = PC_SYM_FOLLOW, const suffix_info *suffixes = NULL) { diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h index c99917306..54b506ea0 100644 --- a/winsup/cygwin/shared_info.h +++ b/winsup/cygwin/shared_info.h @@ -91,7 +91,9 @@ class mount_info int get_cygdrive_info (char *user, char *system, char* user_flags, char* system_flags); void cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p); - int get_mounts_here (const char *parent_dir, int, char **mount_points); + int get_mounts_here (const char *parent_dir, int, + PUNICODE_STRING mount_points, + PUNICODE_STRING cygd); private: diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 65aac3b64..b27947cb4 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -96,9 +96,6 @@ SYSTEM_INFO system_info; static int __stdcall mknod_worker (const char *, mode_t, mode_t, _major_t, _minor_t); -static int __stdcall stat_worker (const char *name, struct __stat64 *buf, - int nofollow) __attribute__ ((regparm (3))); - /* Close all files and process any queued deletions. Lots of unix style applications will open a tmp file, unlink it, but never call close. This function is called by _exit to @@ -1225,8 +1222,8 @@ sync () } /* Cygwin internal */ -static int __stdcall -stat_worker (const char *name, struct __stat64 *buf, int nofollow) +int __stdcall +stat_worker (path_conv &pc, struct __stat64 *buf) { int res = -1; fhandler_base *fh = NULL; @@ -1235,8 +1232,7 @@ stat_worker (const char *name, struct __stat64 *buf, int nofollow) if (efault.faulted (EFAULT)) goto error; - if (!(fh = build_fh_name (name, NULL, nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, - stat_suffixes))) + if (!(fh = build_fh_pc (pc))) goto error; if (fh->error ()) @@ -1246,8 +1242,8 @@ stat_worker (const char *name, struct __stat64 *buf, int nofollow) } else if (fh->exists ()) { - debug_printf ("(%s, %p, %d, %p), file_attributes %d", name, buf, nofollow, - fh, (DWORD) *fh); + debug_printf ("(%s, %p, %p), file_attributes %d", + pc.normalized_path, buf, fh, (DWORD) *fh); memset (buf, 0, sizeof (*buf)); res = fh->fstat (buf); if (!res) @@ -1266,7 +1262,7 @@ stat_worker (const char *name, struct __stat64 *buf, int nofollow) delete fh; error: MALLOC_CHECK; - syscall_printf ("%d = (%s, %p)", res, name, buf); + syscall_printf ("%d = (%s, %p)", res, pc.normalized_path, buf); return res; } @@ -1274,7 +1270,8 @@ extern "C" int stat64 (const char *name, struct __stat64 *buf) { syscall_printf ("entering"); - return stat_worker (name, buf, 0); + path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes); + return stat_worker (pc, buf); } extern "C" int @@ -1312,7 +1309,8 @@ extern "C" int lstat64 (const char *name, struct __stat64 *buf) { syscall_printf ("entering"); - return stat_worker (name, buf, 1); + path_conv pc (name, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes); + return stat_worker (pc, buf); } /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */ diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index f6dc71bd4..2d099304b 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -97,6 +97,7 @@ extern const char case_folded_upper[]; #include #include #include +#include #undef _WINGDI_H #undef _WINUSER_H #undef _WINNLS_H @@ -290,8 +291,9 @@ int symlink_worker (const char *, const char *, bool, bool) class path_conv; int fcntl_worker (int fd, int cmd, void *arg); +int __stdcall stat_worker (path_conv &pc, struct __stat64 *buf) __attribute__ ((regparm (2))); -__ino64_t __stdcall readdir_get_ino (struct __DIR *dir, const char *path, bool dot_dot) __attribute__ ((regparm (3))); +__ino64_t __stdcall readdir_get_ino (const char *path, bool dot_dot) __attribute__ ((regparm (2))); extern "C" int low_priority_sleep (DWORD) __attribute__ ((regparm (1))); #define SLEEP_0_STAY_LOW INFINITE