diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 079aa89f8..3c9804b28 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,32 @@ +2015-12-10 Corinna Vinschen + + * path.h (class path_conv_handle): Use FILE_ALL_INFORMATION instead of + FILE_NETWORK_OPEN_INFORMATION. Use definitions from ntdll.h since it's + included anyway. + (path_conv_handle::fai): Change name from fnoi. + (path_conv::fai): Ditto. + (file_get_fai): Change name from file_get_fnoi. Drop second parameter. + * path.cc (file_get_fai): Ditto. Fetch FileAllInformation rather than + FileNetworkOpenInformation. Convert STATUS_BUFFER_OVERFLOW to + STATUS_SUCCESS. Remove workaround to fetch FileBasicInformation and + FileStandardInformation on filesystems with broken + FileNetworkOpenInformation handling. + (symlink_info::check): Accommodate above changes. In case of using + the NtQueryDirectoryFile fallback, fetch FileIdBothDirectoryInformation + to get inode number as well. + * fhandler_disk_file.cc (fhandler_base::fstat_by_handle): Drop outdated + comment. Accommodate change to using FileAllInformation. Drop + extra function calls to fetch NumberOfLinks and IndexNumber. Set ino + directly from IndexNumber stored in pc.fai(). Drop second argument + from call to fstat_helper. + (fhandler_base::fstat_by_name): Drop second argument from call to + fstat_helper. + (fhandler_base::fstat_helper): Drop second parameter. Accommodate + the fact that we access a FILE_ALL_INFORMATION structure now. + (fhandler_base::open_fs): Set ino directly from IndexNumber stored in + pc.fai(). + * fhandler.h (fhandler_base::fstat_helper): Fix declaration accrdingly. + 2015-12-10 Corinna Vinschen * fhandler_disk_file.cc (path_conv::ndisk_links): Drop unused method. diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 43e56efa6..adb84414e 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -341,8 +341,7 @@ class fhandler_base void __reg2 stat_fixup (struct stat *buf); int __reg2 fstat_fs (struct stat *buf); private: - int __reg3 fstat_helper (struct stat *buf, - DWORD nNumberOfLinks); + int __reg2 fstat_helper (struct stat *buf); int __reg2 fstat_by_nfs_ea (struct stat *buf); int __reg2 fstat_by_handle (struct stat *buf); int __reg2 fstat_by_name (struct stat *buf); diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index e7e22a240..fe9dd03fc 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -319,59 +319,25 @@ fhandler_base::fstat_by_nfs_ea (struct stat *buf) int __reg2 fhandler_base::fstat_by_handle (struct stat *buf) { - /* Don't use FileAllInformation info class. It returns a pathname rather - than a filename, so it needs a really big buffer for no good reason - since we don't need the name anyway. So we just call the three info - classes necessary to get all information required by stat(2). */ - FILE_STANDARD_INFORMATION fsi; - FILE_INTERNAL_INFORMATION fii; - HANDLE h = get_stat_handle (); NTSTATUS status = 0; - IO_STATUS_BLOCK io; /* If the file has been opened for other purposes than stat, we can't rely - on the information stored in pc.fnoi. So we overwrite them here. */ + on the information stored in pc.fai. So we overwrite them here. */ if (get_io_handle ()) { - status = file_get_fnoi (h, pc.has_broken_fnoi (), pc.fnoi ()); + status = file_get_fai (h, pc.fai ()); if (!NT_SUCCESS (status)) { - debug_printf ("%y = NtQueryInformationFile(%S, " - "FileNetworkOpenInformation)", + debug_printf ("%y = NtQueryInformationFile(%S, FileAllInformation)", status, pc.get_nt_native_path ()); return -1; } } - if (!pc.hasgood_inode ()) - fsi.NumberOfLinks = 1; - else - { - status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi, - FileStandardInformation); - if (!NT_SUCCESS (status)) - { - debug_printf ("%y = NtQueryInformationFile(%S, " - "FileStandardInformation)", - status, pc.get_nt_native_path ()); - return -1; - } - if (!ino) - { - status = NtQueryInformationFile (h, &io, &fii, sizeof fii, - FileInternalInformation); - if (!NT_SUCCESS (status)) - { - debug_printf ("%y = NtQueryInformationFile(%S, " - "FileInternalInformation)", - status, pc.get_nt_native_path ()); - return -1; - } - else if (pc.isgood_inode (fii.IndexNumber.QuadPart)) - ino = fii.IndexNumber.QuadPart; - } - } - return fstat_helper (buf, fsi.NumberOfLinks); + if (pc.hasgood_inode () + && pc.isgood_inode (pc.fai ()->InternalInformation.IndexNumber.QuadPart)) + ino = pc.fai ()->InternalInformation.IndexNumber.QuadPart; + return fstat_helper (buf); } int __reg2 @@ -415,7 +381,7 @@ fhandler_base::fstat_by_name (struct stat *buf) ino = fdi_buf.fdi.FileId.QuadPart; } } - return fstat_helper (buf, 1); + return fstat_helper (buf); } int __reg2 @@ -463,22 +429,23 @@ fhandler_base::fstat_fs (struct stat *buf) } int __reg3 -fhandler_base::fstat_helper (struct stat *buf, DWORD nNumberOfLinks) +fhandler_base::fstat_helper (struct stat *buf) { IO_STATUS_BLOCK st; FILE_COMPRESSION_INFORMATION fci; HANDLE h = get_stat_handle (); - PFILE_NETWORK_OPEN_INFORMATION pfnoi = pc.fnoi (); + PFILE_ALL_INFORMATION pfai = pc.fai (); ULONG attributes = pc.file_attributes (); - to_timestruc_t (&pfnoi->LastAccessTime, &buf->st_atim); - to_timestruc_t (&pfnoi->LastWriteTime, &buf->st_mtim); + to_timestruc_t (&pfai->BasicInformation.LastAccessTime, &buf->st_atim); + to_timestruc_t (&pfai->BasicInformation.LastWriteTime, &buf->st_mtim); /* If the ChangeTime is 0, the underlying FS doesn't support this timestamp (FAT for instance). If so, it's faked using LastWriteTime. */ - to_timestruc_t (pfnoi->ChangeTime.QuadPart ? &pfnoi->ChangeTime - : &pfnoi->LastWriteTime, + to_timestruc_t (pfai->BasicInformation.ChangeTime.QuadPart + ? &pfai->BasicInformation.ChangeTime + : &pfai->BasicInformation.LastWriteTime, &buf->st_ctim); - to_timestruc_t (&pfnoi->CreationTime, &buf->st_birthtim); + to_timestruc_t (&pfai->BasicInformation.CreationTime, &buf->st_birthtim); buf->st_dev = get_dev (); /* CV 2011-01-13: Observations on the Cygwin mailing list point to an interesting behaviour in some Windows versions. Apparently the size of @@ -487,11 +454,13 @@ fhandler_base::fstat_helper (struct stat *buf, DWORD nNumberOfLinks) 0 in the first call and size > 0 in the second call. This in turn can affect applications like newer tar. FIXME: Is the allocation size affected as well? */ - buf->st_size = pc.isdir () ? 0 : (off_t) pfnoi->EndOfFile.QuadPart; + buf->st_size = pc.isdir () + ? 0 + : (off_t) pfai->StandardInformation.EndOfFile.QuadPart; /* The number of links to a directory includes the number of subdirectories in the directory, since all those subdirectories point to it. However, this is painfully slow, so we do without it. */ - buf->st_nlink = nNumberOfLinks; + buf->st_nlink = pc.fai()->StandardInformation.NumberOfLinks; /* Enforce namehash as inode number on untrusted file systems. */ if (ino && pc.isgood_inode (ino)) @@ -501,11 +470,11 @@ fhandler_base::fstat_helper (struct stat *buf, DWORD nNumberOfLinks) buf->st_blksize = PREFERRED_IO_BLKSIZE; - if (pfnoi->AllocationSize.QuadPart >= 0LL) + if (pfai->StandardInformation.AllocationSize.QuadPart >= 0LL) /* A successful NtQueryInformationFile returns the allocation size correctly for compressed and sparse files as well. */ - buf->st_blocks = (pfnoi->AllocationSize.QuadPart + S_BLKSIZE - 1) - / S_BLKSIZE; + buf->st_blocks = (pfai->StandardInformation.AllocationSize.QuadPart + + S_BLKSIZE - 1) / S_BLKSIZE; else if (::has_attribute (attributes, FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_SPARSE_FILE) && h && !is_fs_special () @@ -1509,7 +1478,9 @@ fhandler_base::open_fs (int flags, mode_t mode) return 0; } - ino = pc.get_ino_by_handle (get_handle ()); + if (pc.hasgood_inode () + && pc.isgood_inode (pc.fai ()->InternalInformation.IndexNumber.QuadPart)) + ino = pc.fai ()->InternalInformation.IndexNumber.QuadPart; out: syscall_printf ("%d = fhandler_disk_file::open(%S, %y)", res, diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index d86cf99a7..e49f18043 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -1300,44 +1300,18 @@ path_conv::is_binary () && (bin == SCS_32BIT_BINARY || bin == SCS_64BIT_BINARY); } -/* Helper function to fill the fnoi datastructure for a file. */ +/* Helper function to fill the fai datastructure for a file. */ NTSTATUS -file_get_fnoi (HANDLE h, bool skip_network_open_inf, - PFILE_NETWORK_OPEN_INFORMATION pfnoi) +file_get_fai (HANDLE h, PFILE_ALL_INFORMATION pfai) { NTSTATUS status; IO_STATUS_BLOCK io; /* Some FSes (Netapps) don't implement FileNetworkOpenInformation. */ - status = skip_network_open_inf ? STATUS_INVALID_PARAMETER - : NtQueryInformationFile (h, &io, pfnoi, sizeof *pfnoi, - FileNetworkOpenInformation); - if (status == STATUS_INVALID_PARAMETER) - { - /* Apart from accessing Netapps, this also occurs when accessing SMB - share root dirs hosted on NT4. */ - FILE_BASIC_INFORMATION fbi; - FILE_STANDARD_INFORMATION fsi; - - status = NtQueryInformationFile (h, &io, &fbi, sizeof fbi, - FileBasicInformation); - if (NT_SUCCESS (status)) - { - memcpy (pfnoi, &fbi, 4 * sizeof (LARGE_INTEGER)); - if (NT_SUCCESS (NtQueryInformationFile (h, &io, &fsi, - sizeof fsi, - FileStandardInformation))) - { - pfnoi->EndOfFile.QuadPart = fsi.EndOfFile.QuadPart; - pfnoi->AllocationSize.QuadPart - = fsi.AllocationSize.QuadPart; - } - else - pfnoi->EndOfFile.QuadPart - = pfnoi->AllocationSize.QuadPart = 0; - pfnoi->FileAttributes = fbi.FileAttributes; - } - } + status = NtQueryInformationFile (h, &io, pfai, sizeof *pfai, + FileAllInformation); + if (status == STATUS_BUFFER_OVERFLOW) + status = STATUS_SUCCESS; return status; } @@ -2833,10 +2807,9 @@ restart: } else { - status = file_get_fnoi (h, fs.has_broken_fnoi (), - conv_hdl.fnoi ()); + status = file_get_fai (h, conv_hdl.fai ()); if (NT_SUCCESS (status)) - fileattr = conv_hdl.fnoi ()->FileAttributes; + fileattr = conv_hdl.fai ()->BasicInformation.FileAttributes; } } if (!NT_SUCCESS (status)) @@ -2874,7 +2847,7 @@ restart: OBJECT_ATTRIBUTES dattr; HANDLE dir; struct { - FILE_BOTH_DIR_INFORMATION fdi; + FILE_ID_BOTH_DIR_INFORMATION fdi; WCHAR dummy_buf[NAME_MAX + 1]; } fdi_buf; @@ -2906,7 +2879,7 @@ restart: { status = NtQueryDirectoryFile (dir, NULL, NULL, NULL, &io, &fdi_buf, sizeof fdi_buf, - FileBothDirectoryInformation, + FileIdBothDirectoryInformation, TRUE, &basename, TRUE); /* Take the opportunity to check file system while we're having the handle to the parent dir. */ @@ -2932,18 +2905,20 @@ restart: } else { - PFILE_NETWORK_OPEN_INFORMATION pfnoi = conv_hdl.fnoi (); + PFILE_ALL_INFORMATION pfai = conv_hdl.fai (); fileattr = fdi_buf.fdi.FileAttributes; - memcpy (pfnoi, &fdi_buf.fdi.CreationTime, sizeof *pfnoi); - /* Amazing, but true: The FILE_NETWORK_OPEN_INFORMATION - structure has the AllocationSize and EndOfFile members - interchanged relative to the directory information - classes. */ - pfnoi->AllocationSize.QuadPart + memcpy (&pfai->BasicInformation.CreationTime, + &fdi_buf.fdi.CreationTime, + 4 * sizeof (LARGE_INTEGER)); + pfai->BasicInformation.FileAttributes = fileattr; + pfai->StandardInformation.AllocationSize.QuadPart = fdi_buf.fdi.AllocationSize.QuadPart; - pfnoi->EndOfFile.QuadPart + pfai->StandardInformation.EndOfFile.QuadPart = fdi_buf.fdi.EndOfFile.QuadPart; + pfai->StandardInformation.NumberOfLinks = 1; + pfai->InternalInformation.IndexNumber.QuadPart + = fdi_buf.fdi.FileId.QuadPart; } } ext_tacked_on = !!*ext_here; @@ -2977,7 +2952,8 @@ restart: if (res > 0) { /* A symlink is never a directory. */ - conv_hdl.fnoi ()->FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; + conv_hdl.fai ()->BasicInformation.FileAttributes + &= ~FILE_ATTRIBUTE_DIRECTORY; break; } else diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index ab7222ee0..730f943c9 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -91,23 +91,12 @@ enum path_types }; class symlink_info; -struct _FILE_NETWORK_OPEN_INFORMATION; class path_conv_handle { HANDLE hdl; union { - /* Identical to FILE_NETWORK_OPEN_INFORMATION. We don't want to pull in - ntdll.h here, though. */ - struct { - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER AllocationSize; - LARGE_INTEGER EndOfFile; - ULONG FileAttributes; - } _fnoi; + FILE_ALL_INFORMATION _fai; /* For NFS. */ fattr3 _fattr3; } attribs; @@ -128,8 +117,8 @@ public: hdl = NULL; } inline HANDLE handle () const { return hdl; } - inline struct _FILE_NETWORK_OPEN_INFORMATION *fnoi () - { return (struct _FILE_NETWORK_OPEN_INFORMATION *) &attribs._fnoi; } + inline PFILE_ALL_INFORMATION fai () + { return (PFILE_ALL_INFORMATION) &attribs._fai; } inline struct fattr3 *nfsattr () { return (struct fattr3 *) &attribs._fattr3; } }; @@ -390,7 +379,7 @@ class path_conv bool is_binary (); HANDLE handle () const { return conv_handle.handle (); } - struct _FILE_NETWORK_OPEN_INFORMATION *fnoi () { return conv_handle.fnoi (); } + PFILE_ALL_INFORMATION fai () { return conv_handle.fai (); } struct fattr3 *nfsattr () { return conv_handle.nfsattr (); } void reset_conv_handle () { conv_handle.set (NULL); } void close_conv_handle () { conv_handle.close (); } @@ -444,7 +433,7 @@ bool __reg2 has_dot_last_component (const char *dir, bool test_dot_dot); int __reg3 path_prefix_p (const char *path1, const char *path2, int len1, bool caseinsensitive); -NTSTATUS file_get_fnoi (HANDLE, bool, struct _FILE_NETWORK_OPEN_INFORMATION *); +NTSTATUS file_get_fai (HANDLE, PFILE_ALL_INFORMATION); int normalize_win32_path (const char *, char *, char *&); int normalize_posix_path (const char *, char *, char *&); PUNICODE_STRING __reg3 get_nt_native_path (const char *, UNICODE_STRING&, bool);