summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/fhandler_disk_file.cc
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/fhandler_disk_file.cc')
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc446
1 files changed, 142 insertions, 304 deletions
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index f1a9dece4..d68872bec 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -210,90 +210,61 @@ path_conv::isgood_inode (__ino64_t ino) const
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. */
- const DWORD fvi_size = 2 * CYG_MAX_PATH
- + sizeof (FILE_FS_VOLUME_INFORMATION);
- const 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. */
- 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,
- pfvi->VolumeSerialNumber,
- pfai->StandardInformation.EndOfFile.QuadPart,
- pfai->StandardInformation.AllocationSize.QuadPart,
- pfai->InternalInformation.FileId.QuadPart,
- pfai->StandardInformation.NumberOfLinks,
- pfai->BasicInformation.FileAttributes);
- }
+ 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
+ + sizeof (FILE_FS_VOLUME_INFORMATION);
+ const DWORD fai_size = 2 * CYG_MAX_PATH + sizeof (FILE_ALL_INFORMATION);
- debug_printf ("%u = NtQueryInformationFile)",
- RtlNtStatusToDosError (status));
- }
+ PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION)
+ alloca (fvi_size);
+ PFILE_ALL_INFORMATION pfai = (PFILE_ALL_INFORMATION) alloca (fai_size);
- BOOL res = GetFileInformationByHandle (get_handle (), &local);
- debug_printf ("%d = GetFileInformationByHandle (%s, %d)",
- res, get_win32_name (), get_handle ());
- /* GetFileInformationByHandle will fail if it's given stdio handle or pipe.
- It also fails on 9x when trying to access directories on shares. */
- if (!res)
+ status = NtQueryVolumeInformationFile (get_handle (), &io, pfvi, fvi_size,
+ FileFsVolumeInformation);
+ if (!NT_SUCCESS (status))
{
- memset (&local, 0, sizeof (local));
- local.nFileSizeLow = GetFileSize (get_handle (), &local.nFileSizeHigh);
- /* Even GetFileSize fails on 9x when trying to access directories
- on shares. In this case reset filesize to 0. */
- if (local.nFileSizeLow == 0xffffffff && GetLastError ())
- local.nFileSizeLow = 0;
- local.dwFileAttributes = DWORD (pc);
+ debug_printf ("%u = NtQueryVolumeInformationFile)",
+ RtlNtStatusToDosError (status));
+ pfvi->VolumeSerialNumber = 0; /* Set to pc.volser () in helper. */
}
- else
+ 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. */
if (pc.is_rep_symlink ())
- local.dwFileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
- pc.file_attributes (local.dwFileAttributes);
- }
- return fstat_helper (buf,
- local.ftLastWriteTime, /* see fstat_helper comment */
- local.ftLastAccessTime,
- local.ftLastWriteTime,
- local.dwVolumeSerialNumber,
- (ULONGLONG) local.nFileSizeHigh << 32
- | local.nFileSizeLow,
- -1LL,
- (ULONGLONG) local.nFileIndexHigh << 32
- | local.nFileIndexLow,
- local.nNumberOfLinks,
- local.dwFileAttributes);
+ 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,
+ pfvi->VolumeSerialNumber,
+ pfai->StandardInformation.EndOfFile.QuadPart,
+ pfai->StandardInformation.AllocationSize.QuadPart,
+ pfai->InternalInformation.FileId.QuadPart,
+ 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, 0, (ULONGLONG) highfs << 32 | lowfs,
+ -1LL, 0ULL, 1, DWORD (pc));
}
int __stdcall
@@ -556,26 +527,9 @@ 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);
}
-void
-fhandler_disk_file::touch_ctime ()
-{
- FILETIME ft;
-
- 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 (), NULL, NULL, &ft))
- debug_printf ("SetFileTime (%s) failed, %E", get_win32_name ());
- else
- has_changed (false);
-}
-
int __stdcall
fhandler_disk_file::fchmod (mode_t mode)
{
@@ -623,10 +577,6 @@ fhandler_disk_file::fchmod (mode_t mode)
/* Correct NTFS security attributes have higher priority */
res = 0;
- /* Set ctime on success. */
- if (!res && !wincap.is_winnt ())
- has_changed (true);
-
if (oret)
close ();
@@ -783,9 +733,6 @@ fhandler_disk_file::fadvise (_off64_t offset, _off64_t length, int advice)
return -1;
}
- if (!wincap.is_winnt ())
- return 0;
-
/* Windows only supports advice flags for the whole file. We're using
a simplified test here so that we don't have to ask for the actual
file size. Length == 0 means all bytes starting at offset anyway.
@@ -835,6 +782,10 @@ fhandler_disk_file::ftruncate (_off64_t length, bool allow_truncate)
{
_off64_t actual_length;
DWORD size_high = 0;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ FILE_END_OF_FILE_INFORMATION feofi;
+
actual_length = GetFileSize (get_handle (), &size_high);
actual_length += ((_off64_t) size_high) << 32;
@@ -843,49 +794,27 @@ fhandler_disk_file::ftruncate (_off64_t length, bool allow_truncate)
if (!allow_truncate && length < actual_length)
return 0;
- if (wincap.is_winnt ())
+ feofi.EndOfFile.QuadPart = length;
+ /* Create sparse files only when called through ftruncate, not when
+ called through posix_fallocate. */
+ if (allow_truncate
+ && get_fs_flags (FILE_SUPPORTS_SPARSE_FILES)
+ && length >= actual_length + (128 * 1024))
{
- NTSTATUS status;
- IO_STATUS_BLOCK io;
- FILE_END_OF_FILE_INFORMATION feofi;
-
- feofi.EndOfFile.QuadPart = length;
- /* Create sparse files only when called through ftruncate, not when
- called through posix_fallocate. */
- if (allow_truncate
- && get_fs_flags (FILE_SUPPORTS_SPARSE_FILES)
- && length >= actual_length + (128 * 1024))
- {
- DWORD dw;
- BOOL r = DeviceIoControl (get_handle (),
- FSCTL_SET_SPARSE, NULL, 0, NULL,
- 0, &dw, NULL);
- syscall_printf ("%d = DeviceIoControl(%p, FSCTL_SET_SPARSE)",
- r, get_handle ());
- }
- status = NtSetInformationFile (get_handle (), &io,
- &feofi, sizeof feofi,
- FileEndOfFileInformation);
- if (!NT_SUCCESS (status))
- __seterrno_from_nt_status (status);
- else
- res = 0;
+ DWORD dw;
+ BOOL r = DeviceIoControl (get_handle (),
+ FSCTL_SET_SPARSE, NULL, 0, NULL,
+ 0, &dw, NULL);
+ syscall_printf ("%d = DeviceIoControl(%p, FSCTL_SET_SPARSE)",
+ r, get_handle ());
}
+ status = NtSetInformationFile (get_handle (), &io,
+ &feofi, sizeof feofi,
+ FileEndOfFileInformation);
+ if (!NT_SUCCESS (status))
+ __seterrno_from_nt_status (status);
else
- {
- _off64_t prev_loc = lseek (0, SEEK_CUR);
- if (lseek (length, SEEK_SET) >= 0)
- {
- int res_bug = write (&res, 0);
- if (!SetEndOfFile (get_handle ()))
- __seterrno ();
- else
- res = res_bug;
- /* restore original file pointer location */
- lseek (prev_loc, SEEK_SET);
- }
-
- }
+ res = 0;
}
return res;
}
@@ -1050,9 +979,6 @@ docopy:
__seterrno ();
return -1;
}
- /* 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);
@@ -1200,12 +1126,6 @@ out:
int
fhandler_disk_file::close ()
{
- if (!hExeced)
- {
- /* Changing inode data requires setting ctime (only 9x). */
- if (has_changed ())
- touch_ctime ();
- }
return close_fs ();
}
@@ -1462,16 +1382,10 @@ fhandler_disk_file::rmdir ()
(DWORD) pc & ~FILE_ATTRIBUTE_READONLY);
DWORD err, att = 0;
- int rc;
- if (wincap.is_winnt ())
- {
- rc = !(err = unlink_nt (pc, pc.has_attribute (FILE_ATTRIBUTE_READONLY)));
- if (err)
- SetLastError (err);
- }
- else
- rc = RemoveDirectory (get_win32_name ());
+ int rc = !(err = unlink_nt (pc, pc.has_attribute (FILE_ATTRIBUTE_READONLY)));
+ if (err)
+ SetLastError (err);
if (isremote () && exists ())
att = GetFileAttributes (get_win32_name ());
@@ -1503,10 +1417,6 @@ fhandler_disk_file::rmdir ()
__seterrno_from_win_error (err);
- /* Directory still exists, restore its characteristics. */
- if (!wincap.is_winnt () && pc.has_attribute (FILE_ATTRIBUTE_READONLY))
- SetFileAttributes (get_win32_name (), (DWORD) pc);
-
return res;
}
@@ -1547,9 +1457,8 @@ fhandler_disk_file::opendir ()
set_errno (ENAMETOOLONG);
else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
set_errno (ENOMEM);
- else if ((dir->__d_dirname = (char *) malloc (wincap.is_winnt ()
- ? sizeof (struct __DIR_cache)
- : len + 3)) == NULL)
+ else if ((dir->__d_dirname = (char *) malloc ( sizeof (struct __DIR_cache)))
+ == NULL)
{
set_errno (ENOMEM);
goto free_dir;
@@ -1586,47 +1495,45 @@ fhandler_disk_file::opendir ()
&& pc.normalized_path[1] == '\0')
? dirent_isroot : 0;
dir->__d_internal = (unsigned) new __DIR_mounts (pc.normalized_path);
- if (wincap.is_winnt ())
+ d_cachepos (dir) = 0;
+
+ if (!pc.iscygdrive ())
{
- d_cachepos (dir) = 0;
- if (!pc.iscygdrive ())
+ OBJECT_ATTRIBUTES attr;
+ WCHAR wpath[CYG_MAX_PATH + 10];
+ UNICODE_STRING upath = {0, sizeof (wpath), wpath};
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ SECURITY_ATTRIBUTES sa = sec_none;
+ pc.get_nt_native_path (upath);
+ InitializeObjectAttributes (&attr, &upath,
+ OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
+ NULL, sa.lpSecurityDescriptor);
+ status = NtOpenFile (&dir->__handle,
+ SYNCHRONIZE | FILE_LIST_DIRECTORY,
+ &attr, &io, wincap.shared (),
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_OPEN_FOR_BACKUP_INTENT
+ | FILE_DIRECTORY_FILE);
+ if (!NT_SUCCESS (status))
{
- OBJECT_ATTRIBUTES attr;
- WCHAR wpath[CYG_MAX_PATH + 10];
- UNICODE_STRING upath = {0, sizeof (wpath), wpath};
- IO_STATUS_BLOCK io;
- NTSTATUS status;
- SECURITY_ATTRIBUTES sa = sec_none;
- pc.get_nt_native_path (upath);
- InitializeObjectAttributes (&attr, &upath,
- OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
- NULL, sa.lpSecurityDescriptor);
- status = NtOpenFile (&dir->__handle,
- SYNCHRONIZE | FILE_LIST_DIRECTORY,
- &attr, &io, wincap.shared (),
- FILE_SYNCHRONOUS_IO_NONALERT
- | FILE_OPEN_FOR_BACKUP_INTENT
- | FILE_DIRECTORY_FILE);
- if (!NT_SUCCESS (status))
- {
- __seterrno_from_nt_status (status);
- goto free_mounts;
- }
+ __seterrno_from_nt_status (status);
+ goto free_mounts;
+ }
- /* FileIdBothDirectoryInformation is apparently unsupported on
- XP when accessing directories on UDF. When trying to use it
- so, NtQueryDirectoryFile returns with STATUS_ACCESS_VIOLATION.
- It's not clear if the call isn't also unsupported on other
- 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. */
- if (pc.hasgood_inode ())
- {
- dir->__flags |= dirent_set_d_ino;
- if (wincap.has_fileid_dirinfo ())
- dir->__flags |= dirent_get_d_ino;
- }
+ /* FileIdBothDirectoryInformation is apparently unsupported on
+ XP when accessing directories on UDF. When trying to use it
+ so, NtQueryDirectoryFile returns with STATUS_ACCESS_VIOLATION.
+ It's not clear if the call isn't also unsupported on other
+ 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. */
+ if (pc.hasgood_inode ())
+ {
+ dir->__flags |= dirent_set_d_ino;
+ if (wincap.has_fileid_dirinfo ())
+ dir->__flags |= dirent_get_d_ino;
}
}
/* Filling fd with `this' (aka storing this in the file descriptor table
@@ -1755,9 +1662,6 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de)
char fname[CYG_MAX_PATH];
IO_STATUS_BLOCK io;
- if (!wincap.is_winnt ())
- return readdir_9x (dir, de);
-
/* d_cachepos always refers to the next cache entry to use. If it's 0
we must reload the cache. */
if (d_cachepos (dir) == 0)
@@ -1911,55 +1815,6 @@ go_ahead:
return res;
}
-int
-fhandler_disk_file::readdir_9x (DIR *dir, dirent *de)
-{
- WIN32_FIND_DATA buf;
- int res = 0;
-
- if (!dir->__handle)
- {
- res = ENMFILE;
- goto out;
- }
- DWORD lasterr;
- if (dir->__d_position != 0)
- lasterr = FindNextFileA (dir->__handle, &buf) ? 0 : GetLastError ();
- else if (dir->__handle != INVALID_HANDLE_VALUE)
- {
- res = EBADF;
- goto out;
- }
- else
- {
- int len = strlen (dir->__d_dirname);
- strcpy (dir->__d_dirname + len, "*");
- dir->__handle = FindFirstFile (dir->__d_dirname, &buf);
- dir->__d_dirname[len] = '\0';
- if (dir->__handle != INVALID_HANDLE_VALUE)
- lasterr = 0;
- else if ((lasterr = GetLastError ()) != ERROR_NO_MORE_FILES)
- {
- res = geterrno_from_win_error (lasterr);
- goto out;
- }
- }
- if (!lasterr)
- de->d_ino = d_mounts (dir)->check_mount (buf.cFileName, de->d_ino);
- if (!(res = readdir_helper (dir, de, lasterr, buf.dwFileAttributes,
- buf.cFileName)))
- dir->__d_position++;
- else
- {
- FindClose (dir->__handle);
- dir->__handle = NULL;
- }
-
-out:
- syscall_printf ("%d = readdir (%p, %p) (%s)", res, dir, &de, res ? "***" : de->d_name);
- return res;
-}
-
_off64_t
fhandler_disk_file::telldir (DIR *dir)
{
@@ -1978,45 +1833,36 @@ fhandler_disk_file::seekdir (DIR *dir, _off64_t loc)
void
fhandler_disk_file::rewinddir (DIR *dir)
{
- if (wincap.is_winnt ())
- {
- d_cachepos (dir) = 0;
- if (wincap.has_buggy_restart_scan () && isremote ())
+ d_cachepos (dir) = 0;
+ if (wincap.has_buggy_restart_scan () && isremote ())
+ {
+ /* This works around a W2K bug. The RestartScan parameter in calls
+ 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""};
+ OBJECT_ATTRIBUTES attr;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ HANDLE new_dir;
+
+ InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE,
+ dir->__handle, NULL);
+ status = NtOpenFile (&new_dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
+ &attr, &io, wincap.shared (),
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_OPEN_FOR_BACKUP_INTENT
+ | FILE_DIRECTORY_FILE);
+ if (!NT_SUCCESS (stat))
+ debug_printf ("Unable to reopen dir %s, NT error: 0x%08x, "
+ "win32: %lu", get_name (), status,
+ RtlNtStatusToDosError (status));
+ else
{
- /* This works around a W2K bug. The RestartScan parameter in calls
- 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""};
- OBJECT_ATTRIBUTES attr;
- NTSTATUS status;
- IO_STATUS_BLOCK io;
- HANDLE new_dir;
-
- InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE,
- dir->__handle, NULL);
- status = NtOpenFile (&new_dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
- &attr, &io, wincap.shared (),
- FILE_SYNCHRONOUS_IO_NONALERT
- | FILE_OPEN_FOR_BACKUP_INTENT
- | FILE_DIRECTORY_FILE);
- if (!NT_SUCCESS (stat))
- debug_printf ("Unable to reopen dir %s, NT error: 0x%08x, "
- "win32: %lu", get_name (), status,
- RtlNtStatusToDosError (status));
- else
- {
- CloseHandle (dir->__handle);
- dir->__handle = new_dir;
- }
+ CloseHandle (dir->__handle);
+ dir->__handle = new_dir;
}
}
- else if (dir->__handle != INVALID_HANDLE_VALUE)
- {
- if (dir->__handle)
- FindClose (dir->__handle);
- dir->__handle = INVALID_HANDLE_VALUE;
- }
dir->__d_position = 0;
d_mounts (dir)->rewind ();
}
@@ -2033,18 +1879,10 @@ fhandler_disk_file::closedir (DIR *dir)
set_errno (EBADF);
res = -1;
}
- else
+ else if (!NtClose (dir->__handle))
{
- BOOL winres;
- if (wincap.is_winnt ())
- winres = CloseHandle (dir->__handle);
- else
- winres = FindClose (dir->__handle);
- if (!winres)
- {
- __seterrno ();
- res = -1;
- }
+ __seterrno ();
+ res = -1;
}
syscall_printf ("%d = closedir (%p, %s)", res, dir, get_name ());
return res;