From 149da470f31c237d82903e106f029d1e0b392542 Mon Sep 17 00:00:00 2001 From: Egor Duda Date: Tue, 5 Jun 2001 10:45:52 +0000 Subject: [PATCH] * security.h (NTWriteEA): Change prototype. * ntea.cc (NTReadEA): Don't check for global ntea setting, now it's caller responsibility. (NTWriteEA): Ditto. * security.cc (get_file_attribute): Read attribute from EA only if 'ntea' is enabled. (set_file_attribute): Ditto. * path.h: (class path_conv): Add members to store file system information. (path_conv::get_drive_type): New function. * syscalls.cc (stat_worker): Use it. * path.cc (path_conv::update_fs_info): New functions. (path_conv::check): Get file system information from device where file resides. On NTFS, try to read symlink contents from EA. (get_symlink_ea): New function. (set_symlink_ea): Ditto. (symlink): Store symlink in extended attribute, if possible. --- winsup/cygwin/ChangeLog | 20 +++++++ winsup/cygwin/ntea.cc | 10 +--- winsup/cygwin/path.cc | 114 +++++++++++++++++++++++++++++++------- winsup/cygwin/path.h | 17 ++++-- winsup/cygwin/security.cc | 13 +++-- winsup/cygwin/security.h | 2 +- winsup/cygwin/syscalls.cc | 2 +- 7 files changed, 140 insertions(+), 38 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 3e15d5ee8..0a3a2082b 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,23 @@ +2001-06-05 Egor Duda + + * security.h (NTWriteEA): Change prototype. + * ntea.cc (NTReadEA): Don't check for global ntea setting, now + it's caller responsibility. + (NTWriteEA): Ditto. + * security.cc (get_file_attribute): Read attribute from EA only + if 'ntea' is enabled. + (set_file_attribute): Ditto. + * path.h: (class path_conv): Add members to store file system + information. + (path_conv::get_drive_type): New function. + * syscalls.cc (stat_worker): Use it. + * path.cc (path_conv::update_fs_info): New functions. + (path_conv::check): Get file system information from device where + file resides. On NTFS, try to read symlink contents from EA. + (get_symlink_ea): New function. + (set_symlink_ea): Ditto. + (symlink): Store symlink in extended attribute, if possible. + Tue Jun 5 11:18:00 2001 Corinna Vinschen * fhandler.cc (fhandler_disk_file::fstat): Always reset file position diff --git a/winsup/cygwin/ntea.cc b/winsup/cygwin/ntea.cc index 85cc4187f..1d5c77cd4 100644 --- a/winsup/cygwin/ntea.cc +++ b/winsup/cygwin/ntea.cc @@ -85,10 +85,6 @@ BOOL NTWriteEA(const char *file, const char *attrname, char *buf, int len); int __stdcall NTReadEA (const char *file, const char *attrname, char *attrbuf, int len) { - /* return immediately if NTEA usage is turned off */ - if (!allow_ntea) - return FALSE; - HANDLE hFileSource; int eafound = 0; PFILE_FULL_EA_INFORMATION ea, sea; @@ -254,12 +250,8 @@ NTReadEARaw (HANDLE hFileSource, int *len) */ BOOL __stdcall -NTWriteEA (const char *file, const char *attrname, char *buf, int len) +NTWriteEA (const char *file, const char *attrname, const char *buf, int len) { - /* return immediately if NTEA usage is turned off */ - if (!allow_ntea) - return TRUE; - HANDLE hFileSource; WIN32_STREAM_ID StreamId; DWORD dwBytesWritten; diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 4f40db818..76a009854 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -306,6 +306,52 @@ mkrelpath (char *path) strcpy (path, "."); } +void +path_conv::update_fs_info (const char* win32_path) +{ + char tmp_buf [MAX_PATH]; + strncpy (tmp_buf, win32_path, MAX_PATH); + + if (!rootdir (tmp_buf) && + (!GetCurrentDirectory (sizeof (tmp_buf), tmp_buf) <= sizeof (tmp_buf) || + !rootdir (tmp_buf))) + { + debug_printf ("Cannot get root component of path %s", win32_path); + root_dir [0] = fs_name [0] = '\0'; + fs_flags = fs_serial = 0; + sym_opt = 0; + return; + } + + if (strcmp (tmp_buf, root_dir) != 0) + { + drive_type = GetDriveType (root_dir); + if (drive_type == DRIVE_REMOTE || (drive_type == DRIVE_UNKNOWN && (root_dir[0] == '\\' && root_dir[1] == '\\'))) + is_remote_drive = 1; + else + is_remote_drive = 0; + + strncpy (root_dir, tmp_buf, MAX_PATH); + if (!GetVolumeInformation (root_dir, NULL, 0, &fs_serial, NULL, &fs_flags, + fs_name, sizeof (fs_name))) + { + debug_printf ("Cannot get volume information (%s), %E", root_dir); + fs_name [0] = '\0'; + fs_flags = fs_serial = 0; + sym_opt = 0; + } + else + { + /* FIXME: Samba by default returns "NTFS" in file system name, but + * doesn't support Extended Attributes. If there's some fast way to + * distinguish between samba and real ntfs, it should be implemented + * here. + */ + sym_opt = (strcmp (fs_name, "NTFS") == 0 ? PC_CHECK_EA : 0); + } + } +} + /* Convert an arbitrary path SRC to a pure Win32 path, suitable for passing to Win32 API routines. @@ -350,7 +396,10 @@ path_conv::check (const char *src, unsigned opt, fileattr = (DWORD) -1; case_clash = FALSE; devn = unit = 0; - vol_flags = 0; + root_dir[0] = '\0'; + fs_name[0] = '\0'; + fs_flags = fs_serial = 0; + sym_opt = 0; drive_type = 0; is_remote_drive = 0; @@ -423,6 +472,8 @@ path_conv::check (const char *src, unsigned opt, if (error) return; + update_fs_info (full_path); + /* devn should not be a device. If it is, then stop parsing now. */ if (devn != FH_BAD) { @@ -451,7 +502,7 @@ path_conv::check (const char *src, unsigned opt, goto out; } - int len = sym.check (full_path, suff, opt); + int len = sym.check (full_path, suff, opt | sym_opt ); if (sym.case_clash) { @@ -616,31 +667,21 @@ out: return; } - char fs_name[16]; - - strcpy (tmp_buf, this->path); - - if (!rootdir (tmp_buf) || - !GetVolumeInformation (tmp_buf, NULL, 0, &vol_serial, NULL, - &vol_flags, fs_name, 16)) + update_fs_info (path); + if (!fs_name[0]) { - debug_printf ("GetVolumeInformation(%s) = ERR, this->path(%s), set_has_acls(FALSE)", - tmp_buf, this->path, GetLastError ()); set_has_acls (FALSE); set_has_buggy_open (FALSE); } else { set_isdisk (); - debug_printf ("GetVolumeInformation(%s) = OK, this->path(%s), set_has_acls(%d)", - tmp_buf, this->path, vol_flags & FS_PERSISTENT_ACLS); - drive_type = GetDriveType (tmp_buf); - if (drive_type == DRIVE_REMOTE || (drive_type == DRIVE_UNKNOWN && (tmp_buf[0] == '\\' && tmp_buf[1] == '\\'))) - is_remote_drive = 1; + debug_printf ("root_dir(%s), this->path(%s), set_has_acls(%d)", + root_dir, this->path, fs_flags & FS_PERSISTENT_ACLS); if (!allow_smbntsec && is_remote_drive) set_has_acls (FALSE); else - set_has_acls (vol_flags & FS_PERSISTENT_ACLS); + set_has_acls (fs_flags & FS_PERSISTENT_ACLS); /* Known file systems with buggy open calls. Further explanation in fhandler.cc (fhandler_disk_file::open). */ set_has_buggy_open (strcmp (fs_name, "SUNWNFS") == 0); @@ -2316,6 +2357,28 @@ endmntent (FILE *) /********************** Symbolic Link Support **************************/ +/* Read symlink from Extended Attribute */ +int +get_symlink_ea (const char* frompath, char* buf, int buf_size) +{ + int res = NTReadEA (frompath, SYMLINK_EA_NAME, buf, buf_size); + if (res == 0) + debug_printf ("Cannot read symlink from EA"); + return (res - 1); +} + +/* Save symlink to Extended Attribute */ +BOOL +set_symlink_ea (const char* frompath, const char* topath) +{ + if (!NTWriteEA (frompath, SYMLINK_EA_NAME, topath, strlen (topath) + 1)) + { + debug_printf ("Cannot save symlink in EA"); + return FALSE; + } + return TRUE; +} + /* Create a symlink from FROMPATH to TOPATH. */ /* If TRUE create symlinks as Windows shortcuts, if FALSE create symlinks @@ -2441,8 +2504,10 @@ symlink (const char *topath, const char *frompath) win32_path.get_win32 (), S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO); SetFileAttributesA (win32_path.get_win32 (), - allow_winsymlinks ? FILE_ATTRIBUTE_READONLY - : FILE_ATTRIBUTE_SYSTEM); + allow_winsymlinks ? FILE_ATTRIBUTE_READONLY + : FILE_ATTRIBUTE_SYSTEM); + if (win32_path.fs_fast_ea ()) + set_symlink_ea (win32_path, topath); res = 0; } else @@ -2706,6 +2771,14 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt) if (!sym_check) goto file_not_symlink; + if (sym_check > 0 && opt & PC_CHECK_EA && + (res = get_symlink_ea (suffix.path, contents, sizeof (contents))) > 0) + { + pflags = PATH_SYMLINK; + debug_printf ("Got symlink from EA: %s", contents); + break; + } + /* Open the file. */ h = CreateFileA (suffix.path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING, @@ -2714,6 +2787,9 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt) if (h == INVALID_HANDLE_VALUE) goto file_not_symlink; + /* FIXME: if symlink isn't present in EA, but EAs are supported, + * should we write it there? + */ switch (sym_check) { case 1: diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 9bc36c01c..b72a20c14 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -22,7 +22,8 @@ enum pathconv_arg PC_SYM_IGNORE = 0x0004, PC_SYM_CONTENTS = 0x0008, PC_FULL = 0x0010, - PC_NULLEMPTY = 0x0020 + PC_NULLEMPTY = 0x0020, + PC_CHECK_EA = 0x0040 }; enum case_checking @@ -56,14 +57,18 @@ class symlink_info; class path_conv { char path[MAX_PATH]; + char root_dir[MAX_PATH]; + char fs_name[MAX_PATH]; + DWORD fs_flags; + DWORD fs_serial; + DWORD sym_opt; /* additional options to pass to symlink_info resolver */ void add_ext_from_sym (symlink_info&); + void update_fs_info (const char*); + DWORD drive_type; bool is_remote_drive; public: unsigned path_flags; - DWORD vol_flags; - DWORD drive_type; - DWORD vol_serial; int isdisk () const { return path_flags & PATH_ISDISK;} int isremote () const {return is_remote_drive;} @@ -128,11 +133,15 @@ class path_conv DWORD get_devn () {return devn == FH_BAD ? (DWORD) FH_DISK : devn;} short get_unitn () {return devn == FH_BAD ? 0 : unit;} DWORD file_attributes () {return fileattr;} + DWORD get_drive_type () {return drive_type;} + BOOL fs_fast_ea () {return sym_opt & PC_CHECK_EA;} }; /* Symlink marker */ #define SYMLINK_COOKIE "!" +#define SYMLINK_EA_NAME ".CYGSYMLINK" + /* Socket marker */ #define SOCKET_COOKIE "!" diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index 82f1dd8e6..155b0d934 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -1199,9 +1199,14 @@ get_file_attribute (int use_ntsec, const char *file, if (!attribute) return 0; - int oatt = *attribute; - res = NTReadEA (file, ".UNIXATTR", (char *) attribute, sizeof (*attribute)); - *attribute |= oatt; + if (allow_ntea) + { + int oatt = *attribute; + res = NTReadEA (file, ".UNIXATTR", (char *) attribute, sizeof (*attribute)); + *attribute |= oatt; + } + else + res = 0; /* symlinks are everything for everyone!*/ if ((*attribute & S_IFLNK) == S_IFLNK) @@ -1523,7 +1528,7 @@ set_file_attribute (int use_ntsec, const char *file, if ((attribute & S_IFLNK) == S_IFLNK) attribute |= S_IRWXU | S_IRWXG | S_IRWXO; - if (!use_ntsec || !allow_ntsec) + if (allow_ntea && (!use_ntsec || !allow_ntsec)) { if (!NTWriteEA (file, ".UNIXATTR", (char *) &attribute, sizeof (attribute))) diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index ef39fabd6..f307ac013 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -198,4 +198,4 @@ extern SECURITY_ATTRIBUTES *__stdcall sec_user (PVOID sa_buf, PSID sid2 = NULL, extern SECURITY_ATTRIBUTES *__stdcall sec_user_nih (PVOID sa_buf, PSID sid2 = NULL); int __stdcall NTReadEA (const char *file, const char *attrname, char *buf, int len); -BOOL __stdcall NTWriteEA (const char *file, const char *attrname, char *buf, int len); +BOOL __stdcall NTWriteEA (const char *file, const char *attrname, const char *buf, int len); diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index f4fcb464c..788adc1e8 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1040,7 +1040,7 @@ stat_worker (const char *caller, const char *name, struct stat *buf, debug_printf ("%d = file_attributes for '%s'", atts, real_path.get_win32 ()); - dtype = real_path.drive_type; + dtype = real_path.get_drive_type (); if ((atts == -1 || ! (atts & FILE_ATTRIBUTE_DIRECTORY) || (os_being_run == winNT