diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 25e7b6ae4..873848a17 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,13 @@ +2004-04-03 Corinna Vinschen + + * fhandler_disk_file.cc (fhandler_base::fstat_helper): Request + compressed size only if the matching attributes are set. Use + NtQueryInformationFile instead of GetCompressedFileSize. + (fhandler_base::fstat_by_handle): Remove NT 3.5 cruft since + local.dwVolumeSerialNumber isn't used subsequently. + * ntdll.h: Add typedefs for FILE_COMPRESSION_INFORMATION and + FILE_INFORMATION_CLASS. + 2004-04-03 Corinna Vinschen * fhandler_raw.cc (fhandler_dev_raw::open): Actually use "options". diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 8661445a1..62e133f76 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -23,6 +23,8 @@ details. */ #include "cygheap.h" #include "shared_info.h" #include "pinfo.h" +#include +#include "ntdll.h" #include #include @@ -94,24 +96,12 @@ path_conv::ndisk_links (DWORD nNumberOfLinks) int __stdcall fhandler_base::fstat_by_handle (struct __stat64 *buf) { - int res = 0; BY_HANDLE_FILE_INFORMATION local; - - /* NT 3.51 seems to have a bug when attempting to get vol serial - numbers. This loop gets around this. */ - for (int i = 0; i < 2; i++) - { - if (!(res = GetFileInformationByHandle (get_handle (), &local))) - break; - if (local.dwVolumeSerialNumber && (long) local.dwVolumeSerialNumber != -1) - break; - } - + BOOL res = GetFileInformationByHandle (get_handle (), &local); debug_printf ("%d = GetFileInformationByHandle (%s, %d)", res, get_win32_name (), get_handle ()); - if (res == 0) - /* GetFileInformationByHandle will fail if it's given stdin/out/err - or a pipe*/ + /* GetFileInformationByHandle will fail if it's given stdio handle or pipe*/ + if (!res) { memset (&local, 0, sizeof (local)); local.nFileSizeLow = GetFileSize (get_handle (), &local.nFileSizeHigh); @@ -231,6 +221,9 @@ fhandler_base::fstat_helper (struct __stat64 *buf, DWORD nFileIndexLow, DWORD nNumberOfLinks) { + IO_STATUS_BLOCK st; + FILE_COMPRESSION_INFORMATION fci; + /* This is for FAT filesystems, which don't support atime/ctime */ if (ftLastAccessTime.dwLowDateTime == 0 && ftLastAccessTime.dwHighDateTime == 0) @@ -276,16 +269,13 @@ fhandler_base::fstat_helper (struct __stat64 *buf, buf->st_blksize = S_BLKSIZE; - /* GetCompressedFileSize() gets autoloaded. It returns INVALID_FILE_SIZE - if it doesn't exist. Since that's also a valid return value on 64bit - capable file systems, we must additionally check for the win32 error. */ - nFileSizeLow = GetCompressedFileSizeA (pc, &nFileSizeHigh); - if (nFileSizeLow != INVALID_FILE_SIZE || GetLastError () == NO_ERROR) - /* On systems supporting compressed (and sparsed) files, - GetCompressedFileSize() returns the actual amount of - bytes allocated on disk. */ - buf->st_blocks = (((_off64_t)nFileSizeHigh << 32) - + nFileSizeLow + S_BLKSIZE - 1) / S_BLKSIZE; + /* On compressed and sparsed files, we request the actual amount of bytes + allocated on disk. */ + if (pc.has_attribute (FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_SPARSE_FILE) + && get_io_handle () + && !NtQueryInformationFile (get_io_handle (), &st, (PVOID) &fci, + sizeof fci, FileCompressionInformation)) + buf->st_blocks = (fci.CompressedSize.QuadPart + S_BLKSIZE - 1) / S_BLKSIZE; else /* Just compute no. of blocks from file size. */ buf->st_blocks = (buf->st_size + S_BLKSIZE - 1) / S_BLKSIZE; diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 21e63932e..33aa1296e 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -357,11 +357,25 @@ typedef struct _FILE_NAME_INFORMATION WCHAR FileName[MAX_PATH + 100]; } FILE_NAME_INFORMATION; +typedef struct _FILE_COMPRESSION_INFORMATION +{ + LARGE_INTEGER CompressedSize; + USHORT CompressionFormat; + UCHAR CompressionUnitShift; + UCHAR Unknown; + UCHAR ClusterSizeShift; +} FILE_COMPRESSION_INFORMATION, *PFILE_COMPRESSION_INFORMATION; + +typedef enum _FILE_INFORMATION_CLASS +{ + FileCompressionInformation = 28 +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + typedef enum _OBJECT_INFORMATION_CLASS { - ObjectBasicInformation = 0, - ObjectNameInformation = 1, - ObjectHandleInformation = 4 + ObjectBasicInformation = 0, + ObjectNameInformation = 1, + ObjectHandleInformation = 4 // and many more } OBJECT_INFORMATION_CLASS;