* autoload.cc (NtQueryVolumeInformationFile): Add.

* fhandler.cc (fhandler_base::raw_write): Don't touch has_changed flag.
	* fhandler.h (enum change_state): Remove.
	(fhandler_base::status): Revert has_changed to a simple bit.
	(fhandler_base::fstat_helper): Add nAllocSize parameter.  Rename
	ftCreationTime to ftChangeTime.
	* fhandler_disk_file.cc:
	Call fstat_helper with additional
	allocation size throughout.
	(fhandler_base::fstat_by_handle): Use NT native functions to get
	full file information on NT.  Call fstat_helper with LastWriteTime
	as ctime, if ChangeTime is not available.
	(fhandler_base::fstat_by_name): Call fstat_helper with LastWriteTime
	as ctime.
	(fhandler_base::fstat_helper): Add comment. Drop special FAT
	handling since it's useless. Use nAllocSize for st_blocks if available.
	(fhandler_disk_file::touch_ctime): Only touch LastWriteTime.
	(fhandler_disk_file::fchmod): Set has_changed on 9x only.
	(fhandler_disk_file::fchown): Don't set has_changed.
	(fhandler_disk_file::facl): Ditto.
	(fhandler_disk_file::ftruncate): Ditto.
	(fhandler_disk_file::link): Set has_changed on 9x only and on original
	file only.
	(fhandler_base::open_fs): Don't set has_changed in O_TRUNC case.
	* ntdll.h (FILE_BASIC_INFORMATION): Define.
	(FILE_STANDARD_INFORMATION): Define.
	(FILE_INTERNAL_INFORMATION): Define.
	(FILE_EA_INFORMATION): Define.
	(FILE_ACCESS_INFORMATION): Define.
	(FILE_POSITION_INFORMATION): Define.
	(FILE_MODE_INFORMATION): Define.
	(FILE_ALIGNMENT_INFORMATION): Define.
	(FILE_NAME_INFORMATION): Don't define with arbitrary FileName size.
	(FILE_ALL_INFORMATION): Define.
	(FILE_INFORMATION_CLASS): Add FileAllInformation.
	(FILE_FS_VOLUME_INFORMATION): Define.
	(FS_INFORMATION_CLASS): Define.
	(NtQueryVolumeInformationFile): Define.
This commit is contained in:
Corinna Vinschen
2005-04-12 14:26:31 +00:00
parent 576d455f5f
commit 2a24463d0b
6 changed files with 202 additions and 66 deletions

View File

@ -100,6 +100,51 @@ int __stdcall
fhandler_base::fstat_by_handle (struct __stat64 *buf)
{
BY_HANDLE_FILE_INFORMATION local;
if (wincap.is_winnt ())
{
NTSTATUS status;
IO_STATUS_BLOCK io;
/* The entries potentially contain a name of MAX_PATH wide characters. */
DWORD fvi_size = 2 * CYG_MAX_PATH + sizeof (FILE_FS_VOLUME_INFORMATION);
DWORD fai_size = 2 * CYG_MAX_PATH + sizeof (FILE_ALL_INFORMATION);
PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION)
alloca (fvi_size);
PFILE_ALL_INFORMATION pfai = (PFILE_ALL_INFORMATION) alloca (fai_size);
status = NtQueryVolumeInformationFile (get_handle (), &io, pfvi, fvi_size,
FileFsVolumeInformation);
if (!NT_SUCCESS (status))
{
debug_printf ("%u = NtQueryVolumeInformationFile)",
RtlNtStatusToDosError (status));
pfvi->VolumeSerialNumber = 0; /* Set to pc.volser () in helper. */
}
status = NtQueryInformationFile (get_handle (), &io, pfai, fai_size,
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. */
return fstat_helper (buf,
pfai->BasicInformation.ChangeTime.QuadPart ?
*(FILETIME *) &pfai->BasicInformation.ChangeTime :
*(FILETIME *) &pfai->BasicInformation.LastWriteTime,
*(FILETIME *) &pfai->BasicInformation.LastAccessTime,
*(FILETIME *) &pfai->BasicInformation.LastWriteTime,
pfvi->VolumeSerialNumber,
pfai->StandardInformation.EndOfFile.HighPart,
pfai->StandardInformation.EndOfFile.LowPart,
pfai->StandardInformation.AllocationSize.QuadPart,
pfai->InternalInformation.IndexNumber.HighPart,
pfai->InternalInformation.IndexNumber.LowPart,
pfai->StandardInformation.NumberOfLinks);
debug_printf ("%u = NtQuerynformationFile)",
RtlNtStatusToDosError (status));
}
BOOL res = GetFileInformationByHandle (get_handle (), &local);
debug_printf ("%d = GetFileInformationByHandle (%s, %d)",
res, get_win32_name (), get_handle ());
@ -111,12 +156,13 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
}
return fstat_helper (buf,
local.ftCreationTime,
local.ftLastWriteTime, /* see fstat_helper comment */
local.ftLastAccessTime,
local.ftLastWriteTime,
local.dwVolumeSerialNumber,
local.nFileSizeHigh,
local.nFileSizeLow,
-1LL,
local.nFileIndexHigh,
local.nFileIndexLow,
local.nNumberOfLinks);
@ -139,12 +185,13 @@ fhandler_base::fstat_by_name (struct __stat64 *buf)
{
FindClose (handle);
res = fstat_helper (buf,
local.ftCreationTime,
local.ftLastWriteTime, /* see fstat_helper comment */
local.ftLastAccessTime,
local.ftLastWriteTime,
pc.volser (),
local.nFileSizeHigh,
local.nFileSizeLow,
-1LL,
0,
0,
1);
@ -152,7 +199,7 @@ fhandler_base::fstat_by_name (struct __stat64 *buf)
else if (pc.isdir ())
{
FILETIME ft = {};
res = fstat_helper (buf, ft, ft, ft, pc.volser (), 0, 0, 0, 0, 1);
res = fstat_helper (buf, ft, ft, ft, pc.volser (), 0, 0, -1LL, 0, 0, 1);
}
else
{
@ -213,14 +260,21 @@ fhandler_base::fstat_fs (struct __stat64 *buf)
return res;
}
/* The ftChangeTime is taken from the NTFS ChangeTime entry, if reading
the file information using NtQueryInformationFile succeeded. If not,
it's faked using the LastWriteTime entry from GetFileInformationByHandle
or FindFirstFile. We're deliberatly not using the creation time anymore
to simplify interaction with native Windows applications which choke on
creation times >= access or write times. */
int __stdcall
fhandler_base::fstat_helper (struct __stat64 *buf,
FILETIME ftCreationTime,
FILETIME ftChangeTime,
FILETIME ftLastAccessTime,
FILETIME ftLastWriteTime,
DWORD dwVolumeSerialNumber,
DWORD nFileSizeHigh,
DWORD nFileSizeLow,
LONGLONG nAllocSize,
DWORD nFileIndexHigh,
DWORD nFileIndexLow,
DWORD nNumberOfLinks)
@ -228,17 +282,9 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
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)
ftLastAccessTime = ftLastWriteTime;
if (ftCreationTime.dwLowDateTime == 0
&& ftCreationTime.dwHighDateTime == 0)
ftCreationTime = ftLastWriteTime;
to_timestruc_t (&ftLastAccessTime, &buf->st_atim);
to_timestruc_t (&ftLastWriteTime, &buf->st_mtim);
to_timestruc_t (&ftCreationTime, &buf->st_ctim);
to_timestruc_t (&ftChangeTime, &buf->st_ctim);
buf->st_dev = dwVolumeSerialNumber ?: pc.volser ();
buf->st_size = ((_off64_t) nFileSizeHigh << 32) + nFileSizeLow;
/* The number of links to a directory includes the
@ -273,15 +319,20 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
buf->st_blksize = 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)
if (nAllocSize >= 0LL)
/* A successful NtQueryInformationFile returns the allocation size
correctly for compressed and sparse files as well. */
buf->st_blocks = (nAllocSize + S_BLKSIZE - 1) / S_BLKSIZE;
else if (pc.has_attribute (FILE_ATTRIBUTE_COMPRESSED
| FILE_ATTRIBUTE_SPARSE_FILE)
&& get_io_handle ()
&& !NtQueryInformationFile (get_io_handle (), &st, (PVOID) &fci,
sizeof fci, FileCompressionInformation))
/* Otherwise we request the actual amount of bytes allocated for
compressed and sparsed files. */
buf->st_blocks = (fci.CompressedSize.QuadPart + S_BLKSIZE - 1) / S_BLKSIZE;
else
/* Just compute no. of blocks from file size. */
/* Otherwise compute no. of blocks from file size. */
buf->st_blocks = (buf->st_size + S_BLKSIZE - 1) / S_BLKSIZE;
buf->st_mode = 0;
@ -380,6 +431,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
int __stdcall
fhandler_disk_file::fstat (struct __stat64 *buf)
{
/* Changing inode data requires setting ctime (only 9x). */
if (has_changed ())
touch_ctime ();
return fstat_fs (buf);
@ -393,11 +445,10 @@ fhandler_disk_file::touch_ctime (void)
GetSystemTimeAsFileTime (&ft);
/* Modification time is touched if the file data has changed as well.
This happens for instance on write() or ftruncate(). */
if (!SetFileTime (get_io_handle (), &ft, NULL,
has_changed () == data_changed ? &ft : NULL))
if (!SetFileTime (get_io_handle (), NULL, NULL, &ft))
debug_printf ("SetFileTime (%s) failed, %E", get_win32_name ());
else
has_changed (no_change);
has_changed (false);
}
int __stdcall
@ -443,8 +494,8 @@ fhandler_disk_file::fchmod (mode_t mode)
res = 0;
/* Set ctime on success. */
if (!res)
has_changed (inode_changed);
if (!res && !wincap.is_winnt ())
has_changed (true);
if (oret)
close ();
@ -476,13 +527,8 @@ fhandler_disk_file::fchown (__uid32_t uid, __gid32_t gid)
attrib |= S_IFDIR;
int res = get_file_attribute (pc.has_acls (), get_io_handle (), pc, &attrib);
if (!res)
{
res = set_file_attribute (pc.has_acls (), get_io_handle (), pc,
uid, gid, attrib);
/* Set ctime on success. */
if (!res)
has_changed (inode_changed);
}
res = set_file_attribute (pc.has_acls (), get_io_handle (), pc,
uid, gid, attrib);
if (oret)
close ();
@ -576,10 +622,6 @@ fhandler_disk_file::facl (int cmd, int nentries, __aclent32_t *aclbufp)
}
}
/* Set ctime on success. */
if (!res && cmd == SETACL)
has_changed (inode_changed);
if (oret)
close ();
@ -626,9 +668,6 @@ fhandler_disk_file::ftruncate (_off64_t length)
res = res_bug;
/* restore original file pointer location */
lseek (prev_loc, SEEK_SET);
/* Set ctime on success. */
if (!res)
has_changed (data_changed);
}
}
return res;
@ -760,8 +799,6 @@ fhandler_disk_file::link (const char *newpath)
}
success:
/* Set ctime on success. */
has_changed (inode_changed);
close ();
if (!allow_winsymlinks && pc.is_lnk_symlink ())
SetFileAttributes (newpc, (DWORD) pc
@ -776,16 +813,14 @@ docopy:
__seterrno ();
return -1;
}
/* Set ctime on success, also on the copy. */
has_changed (inode_changed);
/* Set ctime on success (copy gets it automatically). */
if (!wincap.is_winnt ())
has_changed (true);
close ();
fhandler_disk_file fh (newpc);
fh.query_open (query_write_attributes);
if (fh.open (O_BINARY, 0))
{
fh.has_changed (inode_changed);
fh.close ();
}
fh.close ();
return 0;
}
@ -897,10 +932,6 @@ fhandler_base::open_fs (int flags, mode_t mode)
&& !allow_ntsec && allow_ntea)
set_file_attribute (false, NULL, get_win32_name (), mode);
/* O_TRUNC on existing file requires setting ctime. */
if ((flags & (O_CREAT | O_TRUNC)) == O_TRUNC)
has_changed (data_changed);
set_fs_flags (pc.fs_flags ());
out:
@ -912,7 +943,7 @@ out:
int
fhandler_disk_file::close ()
{
/* Changing file data requires setting ctime. */
/* Changing inode data requires setting ctime (only 9x). */
if (has_changed ())
touch_ctime ();
return close_fs ();