From 380b8bac123f819fb24eccbea12c23b88a5d12b7 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 21 May 2008 10:23:19 +0000 Subject: [PATCH] * fhandler_disk_file.cc (get_ino_by_handle): Rename pfai to fai. (fhandler_base::fstat_by_handle): Drop fai_size and pfai in favor of static struct fai_buf. Restructure. (fhandler_base::fstat_by_name): Drop fvi_size and pfvi. Drop fdi_size and pfdi in favor of static struct fdi_buf. Drop redundant test for existance. Use FileDirectoryInformation class instead of FileBothDirectoryInformation. Drop call to NtQueryVolumeInformationFile in favor of using pc.fs_serial_number (). Fix FileId information given to fstat_helper. (fhandler_disk_file::fstatvfs): Drop fvi_size, pfvi, fai_size and pfai. Drop getting FileFsVolumeInformation and FileFsAttributeInformation in favor of using the related path_conv info. (fhandler_disk_file::opendir): Fix comment. (fhandler_disk_file::readdir): Ditto. Use FileDirectoryInformation class instead of FileBothDirectoryInformation. * path.cc (fs_info::update): Store MaximumComponentNameLength in new member name_len. * path.h (struct fs_info): Use ULONG rather than DWORD. Add member name_len to store MaximumComponentNameLength. Add accessor methods. (path_conv::fs_name_len): New method. --- winsup/cygwin/ChangeLog | 23 ++++ winsup/cygwin/fhandler_disk_file.cc | 185 +++++++++++----------------- winsup/cygwin/path.cc | 1 + winsup/cygwin/path.h | 11 +- 4 files changed, 103 insertions(+), 117 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 499495e78..98d189d52 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,26 @@ +2008-05-21 Corinna Vinschen + + * fhandler_disk_file.cc (get_ino_by_handle): Rename pfai to fai. + (fhandler_base::fstat_by_handle): Drop fai_size and pfai in favor of + static struct fai_buf. Restructure. + (fhandler_base::fstat_by_name): Drop fvi_size and pfvi. Drop fdi_size + and pfdi in favor of static struct fdi_buf. Drop redundant test for + existance. Use FileDirectoryInformation class instead of + FileBothDirectoryInformation. Drop call to NtQueryVolumeInformationFile + in favor of using pc.fs_serial_number (). Fix FileId information given + to fstat_helper. + (fhandler_disk_file::fstatvfs): Drop fvi_size, pfvi, fai_size and pfai. + Drop getting FileFsVolumeInformation and FileFsAttributeInformation in + favor of using the related path_conv info. + (fhandler_disk_file::opendir): Fix comment. + (fhandler_disk_file::readdir): Ditto. Use FileDirectoryInformation + class instead of FileBothDirectoryInformation. + * path.cc (fs_info::update): Store MaximumComponentNameLength in new + member name_len. + * path.h (struct fs_info): Use ULONG rather than DWORD. Add member + name_len to store MaximumComponentNameLength. Add accessor methods. + (path_conv::fs_name_len): New method. + 2008-05-21 Corinna Vinschen * fhandler.h (dirent_states): Add dirent_nfs_d_ino state and add it to diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index a8558a700..56f6809b9 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -168,11 +168,11 @@ static inline __ino64_t get_ino_by_handle (HANDLE hdl) { IO_STATUS_BLOCK io; - FILE_INTERNAL_INFORMATION pfai; + FILE_INTERNAL_INFORMATION fai; - if (NT_SUCCESS (NtQueryInformationFile (hdl, &io, &pfai, sizeof pfai, + if (NT_SUCCESS (NtQueryInformationFile (hdl, &io, &fai, sizeof fai, FileInternalInformation))) - return pfai.FileId.QuadPart; + return fai.FileId.QuadPart; return 0; } @@ -329,38 +329,38 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) if (pc.fs_is_nfs ()) return fstat_by_nfs_ea (buf); - /* The entries potentially contain a name of MAX_PATH wide characters. */ - const DWORD fai_size = (NAME_MAX + 1) * sizeof (WCHAR) - + sizeof (FILE_ALL_INFORMATION); - PFILE_ALL_INFORMATION pfai = (PFILE_ALL_INFORMATION) alloca (fai_size); + struct { + FILE_ALL_INFORMATION fai; + WCHAR buf[NAME_MAX + 1]; + } fai_buf; - status = NtQueryInformationFile (get_handle (), &io, pfai, fai_size, - FileAllInformation); - if (NT_SUCCESS (status)) + status = NtQueryInformationFile (get_handle (), &io, &fai_buf.fai, + sizeof fai_buf, FileAllInformation); + if (!NT_SUCCESS (status)) { - /* 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 ()) - 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, - *(FILETIME *) &pfai->BasicInformation.LastAccessTime, - *(FILETIME *) &pfai->BasicInformation.LastWriteTime, - *(FILETIME *) &pfai->BasicInformation.CreationTime, - get_dev (), - pfai->StandardInformation.EndOfFile.QuadPart, - pfai->StandardInformation.AllocationSize.QuadPart, - pfai->InternalInformation.FileId.QuadPart, - pfai->StandardInformation.NumberOfLinks, - pfai->BasicInformation.FileAttributes); - } - debug_printf ("%p = NtQueryInformationFile(%S)", - status, pc.get_nt_native_path ()); - return -1; + debug_printf ("%p = NtQueryInformationFile(%S)", + status, pc.get_nt_native_path ()); + return -1; + } + /* 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 ()) + fai_buf.fai.BasicInformation.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; + pc.file_attributes (fai_buf.fai.BasicInformation.FileAttributes); + return fstat_helper (buf, + fai_buf.fai.BasicInformation.ChangeTime.QuadPart + ? *(FILETIME *) &fai_buf.fai.BasicInformation.ChangeTime + : *(FILETIME *) &fai_buf.fai.BasicInformation.LastWriteTime, + *(FILETIME *) &fai_buf.fai.BasicInformation.LastAccessTime, + *(FILETIME *) &fai_buf.fai.BasicInformation.LastWriteTime, + *(FILETIME *) &fai_buf.fai.BasicInformation.CreationTime, + get_dev (), + fai_buf.fai.StandardInformation.EndOfFile.QuadPart, + fai_buf.fai.StandardInformation.AllocationSize.QuadPart, + fai_buf.fai.InternalInformation.FileId.QuadPart, + fai_buf.fai.StandardInformation.NumberOfLinks, + fai_buf.fai.BasicInformation.FileAttributes); } int __stdcall @@ -372,22 +372,12 @@ fhandler_base::fstat_by_name (struct __stat64 *buf) 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); + struct { + FILE_ID_BOTH_DIR_INFORMATION fdi; + WCHAR buf[NAME_MAX + 1]; + } fdi_buf; LARGE_INTEGER FileId; - if (!pc.exists ()) - { - debug_printf ("already determined that pc does not exist"); - set_errno (ENOENT); - return -1; - } RtlSplitUnicodePath (pc.get_nt_native_path (), &dirname, &basename); InitializeObjectAttributes (&attr, &dirname, OBJ_CASE_INSENSITIVE, NULL, NULL); @@ -402,13 +392,13 @@ fhandler_base::fstat_by_name (struct __stat64 *buf) } if (wincap.has_fileid_dirinfo () && NT_SUCCESS (status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, - pfdi, fdi_size, + &fdi_buf.fdi, sizeof fdi_buf, FileIdBothDirectoryInformation, TRUE, &basename, TRUE))) - FileId = pfdi->FileId; + FileId = fdi_buf.fdi.FileId; else if (NT_SUCCESS (status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, - pfdi, fdi_size, - FileBothDirectoryInformation, + &fdi_buf.fdi, sizeof fdi_buf, + FileDirectoryInformation, TRUE, &basename, TRUE))) FileId.QuadPart = 0; /* get_ino is called in fstat_helper. */ if (!NT_SUCCESS (status)) @@ -418,34 +408,26 @@ fhandler_base::fstat_by_name (struct __stat64 *buf) NtClose (dir); goto too_bad; } - status = NtQueryVolumeInformationFile (dir, &io, pfvi, fvi_size, - FileFsVolumeInformation); - if (!NT_SUCCESS (status)) - { - debug_printf ("%p = NtQueryVolumeInformationFile(%S)", - status, pc.get_nt_native_path ()); - pfvi->VolumeSerialNumber = 0; - } 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); + fdi_buf.fdi.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; + pc.file_attributes (fdi_buf.fdi.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, + fdi_buf.fdi.ChangeTime.QuadPart ? + *(FILETIME *) &fdi_buf.fdi.ChangeTime : + *(FILETIME *) &fdi_buf.fdi.LastWriteTime, + *(FILETIME *) &fdi_buf.fdi.LastAccessTime, + *(FILETIME *) &fdi_buf.fdi.LastWriteTime, + *(FILETIME *) &fdi_buf.fdi.CreationTime, + pc.fs_serial_number (), + fdi_buf.fdi.EndOfFile.QuadPart, + fdi_buf.fdi.AllocationSize.QuadPart, + FileId.QuadPart, 1, - pfdi->FileAttributes); + fdi_buf.fdi.FileAttributes); too_bad: LARGE_INTEGER ft; @@ -679,14 +661,6 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs) int ret = -1, opened = 0; NTSTATUS status; IO_STATUS_BLOCK io; - const size_t fvi_size = sizeof (FILE_FS_VOLUME_INFORMATION) - + (NAME_MAX + 1) * sizeof (WCHAR); - PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION) - alloca (fvi_size); - const size_t fai_size = sizeof (FILE_FS_ATTRIBUTE_INFORMATION) - + (NAME_MAX + 1) * sizeof (WCHAR); - PFILE_FS_ATTRIBUTE_INFORMATION pfai = (PFILE_FS_ATTRIBUTE_INFORMATION) - alloca (fai_size); FILE_FS_FULL_SIZE_INFORMATION full_fsi; FILE_FS_SIZE_INFORMATION fsi; HANDLE fh = get_handle (); @@ -712,27 +686,12 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs) } } - /* Get basic volume information. */ - status = NtQueryVolumeInformationFile (fh, &io, pfvi, fvi_size, - FileFsVolumeInformation); - if (!NT_SUCCESS (status)) - { - __seterrno_from_nt_status (status); - goto out; - } - status = NtQueryVolumeInformationFile (fh, &io, pfai, fai_size, - FileFsAttributeInformation); - if (!NT_SUCCESS (status)) - { - __seterrno_from_nt_status (status); - goto out; - } sfs->f_files = ULONG_MAX; sfs->f_ffree = ULONG_MAX; sfs->f_favail = ULONG_MAX; - sfs->f_fsid = pfvi->VolumeSerialNumber; - sfs->f_flag = pfai->FileSystemAttributes; - sfs->f_namemax = pfai->MaximumComponentNameLength; + sfs->f_fsid = pc.fs_serial_number (); + sfs->f_flag = pc.fs_flags (); + sfs->f_namemax = pc.fs_name_len (); /* Get allocation related information. Try to get "full" information first, which is only available since W2K. If that fails, try to retrieve normal allocation information. */ @@ -1608,7 +1567,7 @@ fhandler_disk_file::opendir (int fd) OS/FS combinations (say, Win2K/CDFS or so). Instead of testing in readdir for yet another error code, let's use FileIdBothDirectoryInformation only on filesystems supporting - persistent ACLs, FileBothDirectoryInformation otherwise. + persistent ACLs, FileDirectoryInformation otherwise. On older NFS clients (up to SFU 3.5), dangling symlinks are hidden from directory queries, unless you use the @@ -1825,20 +1784,20 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de) nicely, but only up to the 128th entry in the directory. After reaching this entry, the next call to NtQueryDirectoryFile (FileIdBothDirectoryInformation) returns STATUS_INVALID_LEVEL. - Why should we care, we can just switch to - FileBothDirectoryInformation, isn't it? Nope! The next call to - NtQueryDirectoryFile(FileBothDirectoryInformation) actually - returns STATUS_NO_MORE_FILES, regardless how many files are left - unread in the directory. This does not happen when using - FileBothDirectoryInformation right from the start, but since + Why should we care, we can just switch to FileDirectoryInformation, + isn't it? Nope! The next call to + NtQueryDirectoryFile(FileDirectoryInformation) + actually returns STATUS_NO_MORE_FILES, regardless how many files + are left unread in the directory. This does not happen when using + FileDirectoryInformation right from the start, but since we can't decide whether the server we're talking with has this bug or not, we end up serving Samba shares always in the slow - mode using FileBothDirectoryInformation. So, what we do here is + mode using FileDirectoryInformation. So, what we do here is to implement the solution suggested by Andrew Tridgell, we just reread all entries up to dir->d_position using - FileBothDirectoryInformation. + FileDirectoryInformation. However, We do *not* mark this server as broken and fall back to - using FileBothDirectoryInformation further on. This would slow + using FileDirectoryInformation further on. This would slow down every access to such a server, even for directories under 128 entries. Also, bigger dirs only suffer from one additional call per full directory scan, which shouldn't be too big a hit. @@ -1852,7 +1811,7 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de) { status = NtQueryDirectoryFile (get_handle (), NULL, NULL, 0, &io, d_cache (dir), DIR_BUF_SIZE, - FileBothDirectoryInformation, + FileDirectoryInformation, FALSE, NULL, cnt == 0); if (!NT_SUCCESS (status)) goto go_ahead; @@ -1872,7 +1831,7 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de) d_cache (dir), DIR_BUF_SIZE, (dir->__flags & dirent_nfs_d_ino) ? FileNamesInformation - : FileBothDirectoryInformation, + : FileDirectoryInformation, FALSE, NULL, dir->__d_position == 0); } @@ -1904,9 +1863,9 @@ go_ahead: } else { - FileName = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileName; - FileNameLength = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileNameLength; - FileAttributes = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileAttributes; + FileName = ((PFILE_DIRECTORY_INFORMATION) buf)->FileName; + FileNameLength = ((PFILE_DIRECTORY_INFORMATION) buf)->FileNameLength; + FileAttributes = ((PFILE_DIRECTORY_INFORMATION) buf)->FileAttributes; } RtlInitCountedUnicodeString (&fname, FileName, FileNameLength); de->d_ino = d_mounts (dir)->check_mount (&fname, de->d_ino); diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 92994d1b1..58f0afde7 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -457,6 +457,7 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) return false; } flags (ffai_buf.ffai.FileSystemAttributes); + name_len (ffai_buf.ffai.MaximumComponentNameLength); /* Should be reevaluated for each new OS. Right now this mask is valid up to Vista. The important point here is to test only flags indicating capabilities and to ignore flags indicating a specific state of this diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index fc0d28b60..513d7e80d 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -95,8 +95,9 @@ struct fs_info private: struct status_flags { - DWORD flags; /* Volume flags */ - DWORD samba_version; /* Samba version if available */ + ULONG flags; /* Volume flags */ + ULONG samba_version; /* Samba version if available */ + ULONG name_len; /* MaximumComponentNameLength */ unsigned is_remote_drive : 1; unsigned has_buggy_open : 1; unsigned has_acls : 1; @@ -113,8 +114,9 @@ struct fs_info void clear () { memset (&status, 0 , sizeof status); sernum = 0UL; } fs_info () { clear (); } - IMPLEMENT_STATUS_FLAG (DWORD, flags) - IMPLEMENT_STATUS_FLAG (DWORD, samba_version) + IMPLEMENT_STATUS_FLAG (ULONG, flags) + IMPLEMENT_STATUS_FLAG (ULONG, samba_version) + IMPLEMENT_STATUS_FLAG (ULONG, name_len) IMPLEMENT_STATUS_FLAG (bool, is_remote_drive) IMPLEMENT_STATUS_FLAG (bool, has_buggy_open) IMPLEMENT_STATUS_FLAG (bool, has_acls) @@ -269,6 +271,7 @@ class path_conv DWORD file_attributes () const {return fileattr;} void file_attributes (DWORD new_attr) {fileattr = new_attr;} DWORD fs_flags () {return fs.flags ();} + DWORD fs_name_len () {return fs.name_len ();} bool fs_is_fat () const {return fs.is_fat ();} bool fs_is_ntfs () const {return fs.is_ntfs ();} bool fs_is_samba () const {return fs.is_samba ();} -- 2.43.5