summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/fhandler_disk_file.cc
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2008-05-20 15:11:23 +0000
committerCorinna Vinschen <corinna@vinschen.de>2008-05-20 15:11:23 +0000
commitfe6934da140da55db628d5f940e4bddbfd06a960 (patch)
tree5b69355ddcd6e6469f1f7b0be1022105d3be677c /winsup/cygwin/fhandler_disk_file.cc
parent2f33b79950a24de3307e62aaa678ade9a9c11089 (diff)
downloadcygnal-fe6934da140da55db628d5f940e4bddbfd06a960.tar.gz
cygnal-fe6934da140da55db628d5f940e4bddbfd06a960.tar.bz2
cygnal-fe6934da140da55db628d5f940e4bddbfd06a960.zip
* Makefile.in (DLL_OFILES): Add nfs.o.
* fhandler.cc (fhandler_base::open): Open files on NFS shares with correct access flags and EAs. * fhandler.h (fhandler_base::fstat_by_nfs_ea): Declare. * fhandler_disk_file.cc (fhandler_base::fstat_by_nfs_ea): New method. (fhandler_base::fstat_by_handle): Call fstat_by_nfs_ea for files on NFS shares. (fhandler_disk_file::fchmod): Use NFS specific method to set mode for files on NFS shares. Don't overrule errno from call to set_file_attribute with errno from NtSetInformationFile call. (fhandler_disk_file::fchown): Add comment. * mount.cc (fillout_mntent): Accommodate change in second parameter to fs_info::update. * nfs.cc: New file. * nfs.h: New file. * path.cc (fs_info::update): Take handle instead of bool as second parameter. Use that handle if it's not NULL. Only close handle if it has been opened here. Use static defined buffers instead of alloca'd buffers. (path_conv::check): Call symlink_info::check with reference to fs. Don't call fs.update here if file exists. (conv_path_list): Prefer tmp_pathbuf buffer over using alloca. (symlink_worker): Use NFS specific method to create symlinks on NFS shares. Prefer tmp_pathbuf buffer over using alloca. (symlink_info::check_shortcut): Reopen file from incoming handle with necessary FILE_GENERIC_READ flag. Prefer tmp_pathbuf buffer over using alloca. (symlink_info::check_sysfile): Ditto. (symlink_info::check_reparse_point): Use tmp_pathbuf buffer to allocate REPARSE_DATA_BUFFER. (symlink_info::check_nfs_symlink): New method. (enum symlink_t): Remove. (symlink_info::check): Don't use NtQueryAttributesFile. Rather, open file with necessary access flags and call NtQueryInformationFile. Fix error handling in case file can't be opened. For existing files, call fs_info::update here. Restructure symlink checking to accommodate the fact that the file is already open. Add case for NFS symlinks. * path.h (fs_info::update): Take handle instead of bool as second parameter.
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;
}