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.cc112
1 files changed, 109 insertions, 3 deletions
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index f5dfe33aa..3e2e059f9 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -14,6 +14,7 @@ details. */
#include <stdlib.h>
#include <sys/cygwin.h>
#include <sys/acl.h>
+#include <sys/statvfs.h>
#include <signal.h>
#include "cygerrno.h"
#include "perprocess.h"
@@ -340,7 +341,7 @@ fhandler_base::fstat_fs (struct __stat64 *buf)
/* If we couldn't open the file, try a query open with no permissions.
This allows us to determine *some* things about the file, at least. */
pc.set_exec (0);
- query_open (query_read_control);
+ query_open (query_read_attributes);
oret = open_fs (open_flags, 0);
}
@@ -531,6 +532,111 @@ fhandler_disk_file::fstat (struct __stat64 *buf)
}
int __stdcall
+fhandler_disk_file::fstatvfs (struct statvfs *sfs)
+{
+ int ret = -1, oret = 0;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ const size_t fvi_size = sizeof (FILE_FS_VOLUME_INFORMATION)
+ + 256 * sizeof (WCHAR);
+ PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION)
+ alloca (fvi_size);
+ const size_t fai_size = sizeof (FILE_FS_ATTRIBUTE_INFORMATION)
+ + 256 * 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;
+
+ if (!get_io_handle ())
+ {
+ query_open (query_read_control);
+ oret = open_fs (O_RDONLY | O_BINARY, 0);
+ if (!oret)
+ {
+ /* Can't open file. Try again with rootdir. */
+ char root[CYG_MAX_PATH];
+ if (!rootdir (get_win32_name (), root))
+ goto out;
+ pc.check (root, PC_SYM_NOFOLLOW);
+ oret = open_fs (O_RDONLY | O_BINARY, 0);
+ if (!oret)
+ goto out;
+ }
+ }
+
+ /* Get basic volume information. */
+ status = NtQueryVolumeInformationFile (get_handle (), &io, pfvi, fvi_size,
+ FileFsVolumeInformation);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ goto out;
+ }
+ status = NtQueryVolumeInformationFile (get_handle (), &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;
+ /* 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. */
+ status = NtQueryVolumeInformationFile (get_handle (), &io, &full_fsi,
+ sizeof full_fsi,
+ FileFsFullSizeInformation);
+ if (NT_SUCCESS (status))
+ {
+ sfs->f_bsize = full_fsi.BytesPerSector * full_fsi.SectorsPerAllocationUnit;
+ sfs->f_frsize = sfs->f_bsize;
+ sfs->f_blocks = full_fsi.TotalAllocationUnits.LowPart;
+ sfs->f_bfree = full_fsi.ActualAvailableAllocationUnits.LowPart;
+ sfs->f_bavail = full_fsi.CallerAvailableAllocationUnits.LowPart;
+ if (sfs->f_bfree > sfs->f_bavail)
+ {
+ /* Quotas active. We can't trust TotalAllocationUnits. */
+ NTFS_VOLUME_DATA_BUFFER nvdb;
+ DWORD bytes;
+
+ if (!DeviceIoControl (get_handle (), FSCTL_GET_NTFS_VOLUME_DATA, NULL,
+ 0, &nvdb, sizeof nvdb, &bytes, NULL))
+ debug_printf ("DeviceIoControl (%s) failed, %E", get_name ());
+ else
+ sfs->f_blocks = nvdb.TotalClusters.QuadPart;
+ }
+ ret = 0;
+ }
+ else
+ {
+ status = NtQueryVolumeInformationFile (get_handle (), &io, &fsi,
+ sizeof fsi, FileFsSizeInformation);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ goto out;
+ }
+ sfs->f_bsize = fsi.BytesPerSector * fsi.SectorsPerAllocationUnit;
+ sfs->f_frsize = sfs->f_bsize;
+ sfs->f_blocks = fsi.TotalAllocationUnits.LowPart;
+ sfs->f_bfree = fsi.AvailableAllocationUnits.LowPart;
+ sfs->f_bavail = sfs->f_bfree;
+ ret = 0;
+ }
+out:
+ if (oret)
+ close_fs ();
+ syscall_printf ("%d = fstatvfs (%s, %p)", ret, get_name (), sfs);
+ return ret;
+}
+
+int __stdcall
fhandler_disk_file::fchmod (mode_t mode)
{
extern int chmod_device (path_conv& pc, mode_t mode);
@@ -653,7 +759,7 @@ fhandler_disk_file::facl (int cmd, int nentries, __aclent32_t *aclbufp)
{
if (!get_io_handle ())
{
- query_open (query_read_control);
+ query_open (query_read_attributes);
if (!(oret = open (O_BINARY, 0)))
return -1;
}
@@ -687,7 +793,7 @@ fhandler_disk_file::facl (int cmd, int nentries, __aclent32_t *aclbufp)
{
if (!get_io_handle ())
{
- query_open (cmd == SETACL ? query_write_control : query_read_control);
+ query_open (cmd == SETACL ? query_write_control : query_read_attributes);
if (!(oret = open (O_BINARY, 0)))
return -1;
}