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.cc110
1 files changed, 102 insertions, 8 deletions
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index bca5448fa..17e1d55a3 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -23,6 +23,7 @@ details. */
#include "pinfo.h"
#include "ntdll.h"
#include "tls_pbuf.h"
+#include "nfs.h"
#include <winioctl.h>
#define _COMPILING_NEWLIB
@@ -264,11 +265,70 @@ path_conv::isgood_inode (__ino64_t ino) const
return hasgood_inode () && (ino > UINT32_MAX || !isremote () || fs_is_nfs ());
}
+/* For files on NFS shares, we request an EA of type NfsV3Attributes.
+ This returns the content of a struct fattr3 as defined in RFC 1813.
+ The content is the NFS equivalent of struct stat. so there's not much
+ to do here except for copying. */
+int __stdcall
+fhandler_base::fstat_by_nfs_ea (struct __stat64 *buf)
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ struct {
+ FILE_FULL_EA_INFORMATION ffei;
+ char buf[sizeof (NFS_V3_ATTR) + sizeof (fattr3)];
+ } ffei_buf;
+ struct {
+ FILE_GET_EA_INFORMATION fgei;
+ char buf[sizeof (NFS_V3_ATTR)];
+ } fgei_buf;
+
+ fgei_buf.fgei.NextEntryOffset = 0;
+ fgei_buf.fgei.EaNameLength = sizeof (NFS_V3_ATTR) - 1;
+ stpcpy (fgei_buf.fgei.EaName, NFS_V3_ATTR);
+ status = NtQueryEaFile (get_handle (), &io,
+ &ffei_buf.ffei, sizeof ffei_buf, TRUE,
+ &fgei_buf.fgei, sizeof fgei_buf, NULL, TRUE);
+ if (NT_SUCCESS (status))
+ {
+ fattr3 *nfs_attr = (fattr3 *) (ffei_buf.ffei.EaName
+ + ffei_buf.ffei.EaNameLength + 1);
+ buf->st_dev = nfs_attr->fsid;
+ buf->st_ino = nfs_attr->fileid;
+ buf->st_mode = (nfs_attr->mode & 0xfff)
+ | nfs_type_mapping[nfs_attr->type & 7];
+ buf->st_nlink = nfs_attr->nlink;
+ /* FIXME: How to convert UNIX uid/gid to Windows SIDs? */
+#if 0
+ buf->st_uid = nfs_attr->uid;
+ buf->st_gid = nfs_attr->gid;
+#else
+ buf->st_uid = myself->uid;
+ buf->st_gid = myself->gid;
+#endif
+ buf->st_rdev = makedev (nfs_attr->rdev.specdata1,
+ nfs_attr->rdev.specdata2);
+ buf->st_size = nfs_attr->size;
+ buf->st_blksize = PREFERRED_IO_BLKSIZE;
+ buf->st_blocks = nfs_attr->used / 512;
+ buf->st_atim = nfs_attr->atime;
+ buf->st_mtim = nfs_attr->mtime;
+ buf->st_ctim = nfs_attr->ctime;
+ return 0;
+ }
+ debug_printf ("%p = NtQueryEaFile(%S)", status, pc.get_nt_native_path ());
+ return -1;
+}
+
int __stdcall
fhandler_base::fstat_by_handle (struct __stat64 *buf)
{
NTSTATUS status;
IO_STATUS_BLOCK io;
+
+ 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);
@@ -730,6 +790,8 @@ fhandler_disk_file::fchmod (mode_t mode)
extern int chmod_device (path_conv& pc, mode_t mode);
int res = -1;
int oret = 0;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
if (pc.is_fs_special ())
return chmod_device (pc, mode);
@@ -749,6 +811,34 @@ fhandler_disk_file::fchmod (mode_t mode)
}
}
+ if (pc.fs_is_nfs ())
+ {
+ /* chmod on NFS shares works by writing an EA of type NfsV3Attributes.
+ Only type and mode have to be set. Apparently type isn't checked
+ for consistency, so it's sufficent to set it to NF3REG all the time. */
+ struct {
+ FILE_FULL_EA_INFORMATION ffei;
+ char buf[sizeof (NFS_V3_ATTR) + sizeof (fattr3)];
+ } ffei_buf;
+ ffei_buf.ffei.NextEntryOffset = 0;
+ ffei_buf.ffei.Flags = 0;
+ ffei_buf.ffei.EaNameLength = sizeof (NFS_V3_ATTR) - 1;
+ ffei_buf.ffei.EaValueLength = sizeof (fattr3);
+ strcpy (ffei_buf.ffei.EaName, NFS_V3_ATTR);
+ fattr3 *nfs_attr = (fattr3 *) (ffei_buf.ffei.EaName
+ + ffei_buf.ffei.EaNameLength + 1);
+ memset (nfs_attr, 0, sizeof (fattr3));
+ nfs_attr->type = NF3REG;
+ nfs_attr->mode = mode;
+ status = NtSetEaFile (get_handle (), &io,
+ &ffei_buf.ffei, sizeof ffei_buf);
+ if (!NT_SUCCESS (status))
+ __seterrno_from_nt_status (status);
+ else
+ res = 0;
+ goto out;
+ }
+
if (allow_ntsec && pc.has_acls ())
{
if (pc.isdir ())
@@ -767,19 +857,22 @@ fhandler_disk_file::fchmod (mode_t mode)
if (mode & S_IFSOCK)
pc |= (DWORD) FILE_ATTRIBUTE_SYSTEM;
- IO_STATUS_BLOCK io;
FILE_BASIC_INFORMATION fbi;
fbi.CreationTime.QuadPart = fbi.LastAccessTime.QuadPart
= fbi.LastWriteTime.QuadPart = fbi.ChangeTime.QuadPart = 0LL;
fbi.FileAttributes = pc.file_attributes () ?: FILE_ATTRIBUTE_NORMAL;
- NTSTATUS status = NtSetInformationFile (get_handle (), &io, &fbi, sizeof fbi,
- FileBasicInformation);
- if (!NT_SUCCESS (status))
- __seterrno_from_nt_status (status);
- else if (!allow_ntsec || !pc.has_acls ())
- /* Correct NTFS security attributes have higher priority */
- res = 0;
+ status = NtSetInformationFile (get_handle (), &io, &fbi, sizeof fbi,
+ FileBasicInformation);
+ /* Correct NTFS security attributes have higher priority */
+ if (!allow_ntsec || !pc.has_acls ())
+ {
+ if (!NT_SUCCESS (status))
+ __seterrno_from_nt_status (status);
+ else
+ res = 0;
+ }
+out:
if (oret)
close_fs ();
@@ -795,6 +888,7 @@ fhandler_disk_file::fchown (__uid32_t uid, __gid32_t gid)
{
/* fake - if not supported, pretend we're like win95
where it just works */
+ /* FIXME: Could be supported on NFS when user->uid mapping is in place. */
return 0;
}