Index: winsup/cygwin/cygtls.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/cygtls.cc,v retrieving revision 1.72 diff -u -p -r1.72 cygtls.cc --- winsup/cygwin/cygtls.cc 28 Feb 2010 15:54:25 -0000 1.72 +++ winsup/cygwin/cygtls.cc 13 Sep 2010 11:41:58 -0000 @@ -161,6 +161,9 @@ _cygtls::remove (DWORD wait) free_local (protoent_buf); free_local (servent_buf); free_local (hostent_buf); +#ifdef USE_FAST_SECURITY + free_local (security_buf); +#endif } /* Free temporary TLS path buffers. */ Index: winsup/cygwin/cygtls.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/cygtls.h,v retrieving revision 1.66 diff -u -p -r1.66 cygtls.h --- winsup/cygwin/cygtls.h 2 Mar 2010 00:49:15 -0000 1.66 +++ winsup/cygwin/cygtls.h 13 Sep 2010 11:41:58 -0000 @@ -144,6 +144,12 @@ struct _local_storage /* All functions requiring temporary path buffers. */ tls_pathbuf pathbufs; + +#ifdef USE_FAST_SECURITY + /* security.cc */ + void *security_buf; + int security_buf_len; +#endif }; typedef struct struct_waitq Index: winsup/cygwin/environ.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/environ.cc,v retrieving revision 1.183 diff -u -p -r1.183 environ.cc --- winsup/cygwin/environ.cc 18 May 2010 14:30:50 -0000 1.183 +++ winsup/cygwin/environ.cc 13 Sep 2010 11:41:58 -0000 @@ -34,6 +34,21 @@ details. */ extern bool dos_file_warning; extern bool ignore_case_with_glob; extern bool allow_winsymlinks; +#ifdef FAST_SYMLINK_CHECK +extern bool fast_symlink_check; +#endif +#ifdef FAST_SECUTIRY_CHECK +extern bool fast_security_info; +#endif +#ifdef USE_ACL +extern bool use_acl; +#endif +#ifdef USE_FS_INFO_CACHE +extern bool use_fs_info_cache; +#endif +#ifdef USE_INODE_FROM_HASH +extern bool inode_from_hash; +#endif bool reset_com = false; static bool envcache = true; static bool create_upcaseenv = false; @@ -605,6 +620,21 @@ static struct parse_thing {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}}, {"upcaseenv", {&create_upcaseenv}, justset, NULL, {{false}, {true}}}, {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}}, +#ifdef FAST_SYMLINK_CHECK + {"fast_symlink_check", {&fast_symlink_check}, justset, NULL, {{false}, {true}}}, +#endif +#ifdef USE_ACL + {"use_acl", {&use_acl}, justset, NULL, {{false}, {true}}}, +#endif +#ifdef USE_FS_INFO_CACHE + {"use_fs_info_cache", {&use_fs_info_cache}, justset, NULL, {{false}, {true}}}, +#endif +#ifdef USE_INODE_FROM_HASH + {"inode_from_hash", {&inode_from_hash}, justset, NULL, {{false}, {true}}}, +#endif +#ifdef FAST_SECUTIRY_CHECK + {"fast_security_info", {&fast_security_info}, justset, NULL, {{false}, {true}}}, +#endif {NULL, {0}, justset, 0, {{0}, {0}}} }; @@ -616,6 +646,9 @@ parse_options (char *buf) int istrue; char *p, *lasts; parse_thing *k; +#ifdef USE_ACL + TCHAR exe_name[MAX_PATH]; +#endif if (buf == NULL) { @@ -694,6 +727,17 @@ parse_options (char *buf) break; } } +#ifdef USE_ACL + if (GetModuleFileName(0, exe_name, MAX_PATH) && (strstr(exe_name, "chmod") || + strstr(exe_name, "chown") || strstr(exe_name, "chgrp"))) + { + use_acl = 1; + } +#endif +#if defined(USE_ACL) && defined(USE_INODE_FROM_HASH) + if (!inode_from_hash) + use_acl = 1; +#endif debug_printf ("returning"); } Index: winsup/cygwin/fhandler_disk_file.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_disk_file.cc,v retrieving revision 1.334 diff -u -p -r1.334 fhandler_disk_file.cc --- winsup/cygwin/fhandler_disk_file.cc 20 Aug 2010 11:18:58 -0000 1.334 +++ winsup/cygwin/fhandler_disk_file.cc 13 Sep 2010 11:41:59 -0000 @@ -30,6 +30,13 @@ details. */ #define _COMPILING_NEWLIB #include +#ifdef USE_INODE_FROM_HASH +bool inode_from_hash = true; +#endif +#ifdef CACHE_FI +bool cache_fi = true; +#endif + class __DIR_mounts { int count; @@ -140,6 +147,10 @@ public: inline bool path_conv::isgood_inode (__ino64_t ino) const { +#ifdef USE_INODE_FROM_HASH + if (inode_from_hash) + return 0; +#endif /* We can't trust remote inode numbers of only 32 bit. That means, all remote inode numbers when running under NT4, as well as remote NT4 NTFS, as well as shares of Samba version < 3.0. @@ -417,11 +428,35 @@ fhandler_base::fstat_by_handle (struct _ get_dev (), fsi.EndOfFile.QuadPart, fsi.AllocationSize.QuadPart, +#ifdef USE_INODE_FROM_HASH + inode_from_hash ? 0 : fii.FileId.QuadPart, +#else ino, +#endif fsi.NumberOfLinks, fi.fbi.FileAttributes); } +#if defined(CACHE_FI) || defined (FAST_SYMLINK_CHECK) +int path_conv_update_fi(path_conv *pc, PUNICODE_STRING path) +{ + WCHAR _path[MAX_PATH]; + if (path->Length>MAX_PATH) + return 0; + memcpy(_path, path->Buffer, path->Length); + _path[path->Length/sizeof(WCHAR)] = 0; + if (pc->fi_updated > 0 && !wcscmp(pc->fi_path, _path)) + return pc->fi_updated; + wcscpy(pc->fi_path, _path); + OBJECT_ATTRIBUTES attr; + InitializeObjectAttributes(&attr, path, + pc->objcaseinsensitive() , NULL, NULL); + pc->fi_updated = NtQueryFullAttributesFile(&attr, + (PFILE_NETWORK_OPEN_INFORMATION)&pc->fi) ? -1 : 1; + return pc->fi_updated; +} +#endif + int __stdcall fhandler_base::fstat_by_name (struct __stat64 *buf) { @@ -437,6 +472,22 @@ fhandler_base::fstat_by_name (struct __s } fdi_buf; LARGE_INTEGER FileId; +#ifdef CACHE_FI + if (cache_fi) + { + debug_printf ("start fstat_by_name"); + if (path_conv_update_fi(&pc, pc.get_nt_native_path())<0) + goto too_bad; + if (pc.is_rep_symlink()) + pc.fi.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; + pc.file_attributes(pc.fi.FileAttributes); + return fstat_helper (buf, + &pc.fi.ChangeTime, &pc.fi.LastAccessTime, &pc.fi.LastWriteTime, + &pc.fi.CreationTime, pc.fs_serial_number (), + pc.fi.EndOfFile.QuadPart, pc.fi.AllocationSize.QuadPart, 0, 1, + pc.fi.FileAttributes); + } +#endif RtlSplitUnicodePath (pc.get_nt_native_path (), &dirname, &basename); InitializeObjectAttributes (&attr, &dirname, pc.objcaseinsensitive (), NULL, NULL); @@ -509,7 +560,9 @@ int __stdcall fhandler_base::fstat_fs (struct __stat64 *buf) { int res = -1; +#ifndef CACHE_FI int oret; +#endif int open_flags = O_RDONLY | O_BINARY; if (get_stat_handle ()) @@ -520,6 +573,11 @@ fhandler_base::fstat_fs (struct __stat64 res = fstat_by_name (buf); return res; } +#ifdef CACHE_FI + query_open (query_read_attributes); + res = fstat_by_name (buf); + if (res && open_fs (open_flags, 0)) +#else /* First try to open with generic read access. This allows to read the file in fstat_helper (when checking for executability) without having to re-open it. Opening a file can take a lot of time on network drives @@ -531,6 +589,7 @@ fhandler_base::fstat_fs (struct __stat64 oret = open_fs (open_flags, 0); } if (oret) +#endif { /* We now have a valid handle, regardless of the "nohandle" state. Since fhandler_base::open only calls CloseHandle if !nohandle, @@ -543,8 +602,10 @@ fhandler_base::fstat_fs (struct __stat64 nohandle (no_handle); set_io_handle (NULL); } +#ifndef CACHE_FI if (res) res = fstat_by_name (buf); +#endif return res; } @@ -592,7 +653,11 @@ fhandler_base::fstat_helper (struct __st #endif /* Enforce namehash as inode number on untrusted file systems. */ +#ifdef USE_INODE_FROM_HASH + if (!inode_from_hash && nFileIndex && pc.isgood_inode (nFileIndex)) +#else if (nFileIndex && pc.isgood_inode (nFileIndex)) +#endif buf->st_ino = (__ino64_t) nFileIndex; else buf->st_ino = get_ino (); Index: winsup/cygwin/mount.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/mount.cc,v retrieving revision 1.64 diff -u -p -r1.64 mount.cc --- winsup/cygwin/mount.cc 25 Aug 2010 09:20:11 -0000 1.64 +++ winsup/cygwin/mount.cc 13 Sep 2010 11:42:00 -0000 @@ -48,6 +48,10 @@ details. */ bool NO_COPY mount_info::got_usr_bin; bool NO_COPY mount_info::got_usr_lib; int NO_COPY mount_info::root_idx = -1; +#if defined(USE_ACL) || defined(USE_FS_INFO_CACHE) +bool use_acl = false; +bool use_fs_info_cache = true; +#endif /* is_unc_share: Return non-zero if PATH begins with //server/share or with one of the native prefixes //./ or //?/ @@ -105,6 +109,113 @@ struct smb_extended_info { }; #pragma pack(pop) +#ifdef USE_FS_INFO_CACHE +typedef struct fs_info_list_t { + struct fs_info_list_t *next; + fs_info fsi; + wchar_t path[MAX_PATH]; + int path_len; +} fs_info_list_t; + +static fs_info_list_t *fs_info_list; +static int in_fs_info_update; + +int fs_info_lookup(fs_info *fsi, PUNICODE_STRING upath) +{ + int shortest = 0; + fs_info_list_t *f, *found = NULL; + if (in_fs_info_update) + return 0; + /* find first (longest match) */ + for (f = fs_info_list; f != NULL; f=f->next) + { + if (!wcsncmp(f->path, upath->Buffer, f->path_len)) + { + if (!shortest || shortest > f->path_len) + { + shortest = f->path_len; + found = f; + } + } + } + if (!found) + return 0; + memcpy(fsi, &found->fsi, sizeof(fsi)); + return 1; +} + +static inline int fs_info_eq(fs_info *a, fs_info *b) +{ + return a->serial_number()==b->serial_number() && + !memcmp(&a->status, &b->status, sizeof(a->status)); +} + +static void fs_info_update(fs_info *fsi, PUNICODE_STRING upath) +{ + wchar_t scan_path[MAX_PATH], save, *p; + fs_info *_fsi, *scan = NULL; + fs_info_list_t *f; + UNICODE_STRING ustr; + if (in_fs_info_update) + return; + in_fs_info_update++; + _fsi = new fs_info(); + _fsi->update(upath, NULL); + /* sanity check */ + if (!fs_info_eq(_fsi, fsi)) + { + debug_printf("fs_info_update: strange: got different volume"); + delete _fsi; + goto Exit; + } + /* scan up the path to find the base directory of the mount */ + wcscpy(scan_path, upath->Buffer); + while ((p=wcsrchr(scan_path, '\\'))) + { + save = *p; + *p = 0; + if (p==scan_path) + { + *p = save; + break; + } + if (scan) + delete scan; + scan = new fs_info(); + ustr.Buffer = scan_path; + ustr.Length = wcslen(scan_path); + ustr.MaximumLength = sizeof(scan_path); + if (!scan->update(&ustr, NULL) || !fs_info_eq(scan, fsi)) + { + *p = save; + break; + } + } + if (scan) + delete scan; + f = (fs_info_list_t*)calloc(sizeof(*f), 1); + memcpy(&f->fsi, _fsi, sizeof(_fsi)); + f->path_len = wcslen(scan_path); + wcscpy(f->path, scan_path); + f->next = fs_info_list; + fs_info_list = f; +Exit: + in_fs_info_update--; +} +#endif + +#ifdef USE_ACL +bool fs_info::has_acls(bool val) +{ + return (bool) (status.has_acls = val); +} + +bool fs_info::has_acls() const +{ + return use_acl ? status.has_acls : 0; +} +#endif + bool fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) { @@ -125,6 +236,10 @@ fs_info::update (PUNICODE_STRING upath, } ffvi_buf; UNICODE_STRING fsname; +#ifdef USE_FS_INFO_CACHE + if (use_fs_info_cache && !use_acl && fs_info_lookup(this, upath)) + return true; +#endif clear (); if (in_vol) vol = in_vol; @@ -355,6 +470,11 @@ fs_info::update (PUNICODE_STRING upath, if (!in_vol) NtClose (vol); + +#ifdef USE_FS_INFO_CACHE + if (use_fs_info_cache && !use_acl) + fs_info_update(this, upath); +#endif return true; } Index: winsup/cygwin/mount.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/mount.h,v retrieving revision 1.14 diff -u -p -r1.14 mount.h --- winsup/cygwin/mount.h 9 Aug 2010 08:18:30 -0000 1.14 +++ winsup/cygwin/mount.h 13 Sep 2010 11:42:00 -0000 @@ -43,6 +43,13 @@ extern struct fs_names_t { class fs_info { +#ifdef USE_FS_INFO_CACHE + ULONG sernum; /* Volume Serial Number */ + char fsn[80]; /* Windows filesystem name */ + unsigned long got_fs () const { return status.fs_type != none; } + + public: +#endif struct status_flags { ULONG flags; /* Volume flags */ @@ -58,11 +65,13 @@ class fs_info unsigned has_buggy_basic_info : 1; unsigned has_dos_filenames_only : 1; } status; +#ifndef USE_FS_INFO_CACHE ULONG sernum; /* Volume Serial Number */ char fsn[80]; /* Windows filesystem name */ unsigned long got_fs () const { return status.fs_type != none; } public: +#endif void clear () { memset (&status, 0 , sizeof status); @@ -75,7 +84,12 @@ class fs_info IMPLEMENT_STATUS_FLAG (ULONG, samba_version) IMPLEMENT_STATUS_FLAG (ULONG, name_len) IMPLEMENT_STATUS_FLAG (bool, is_remote_drive) +#ifdef USE_ACL + bool has_acls(bool val); + bool has_acls() const; +#else IMPLEMENT_STATUS_FLAG (bool, has_acls) +#endif IMPLEMENT_STATUS_FLAG (bool, hasgood_inode) IMPLEMENT_STATUS_FLAG (bool, caseinsensitive) IMPLEMENT_STATUS_FLAG (bool, has_buggy_open) Index: winsup/cygwin/path.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/path.cc,v retrieving revision 1.604 diff -u -p -r1.604 path.cc --- winsup/cygwin/path.cc 27 Aug 2010 17:58:43 -0000 1.604 +++ winsup/cygwin/path.cc 13 Sep 2010 11:42:03 -0000 @@ -73,7 +73,14 @@ #include #include +#ifdef DISABLE_DOS_FILE_WARNING +bool dos_file_warning = false; +#else bool dos_file_warning = true; +#endif +#ifdef FAST_SYMLINK_CHECK +bool fast_symlink_check = true; +#endif suffix_info stat_suffixes[] = { @@ -97,7 +104,11 @@ struct symlink_info _minor_t minor; _mode_t mode; int check (char *path, const suffix_info *suffixes, fs_info &fs, +#ifdef FAST_SYMLINK_CHECK + path_conv_handle &conv_hdl, path_conv *pc); +#else path_conv_handle &conv_hdl); +#endif int set (char *path); bool parse_device (const char *); int check_sysfile (HANDLE h); @@ -826,7 +837,11 @@ path_conv::check (const char *src, unsig if (is_msdos) sym.pflags |= PATH_NOPOSIX | PATH_NOACL; +#ifdef FAST_SYMLINK_CHECK + symlen = sym.check (full_path, suff, fs, conv_handle, this); +#else symlen = sym.check (full_path, suff, fs, conv_handle); +#endif is_virtual_symlink: @@ -2183,11 +2198,20 @@ symlink_info::parse_device (const char * int symlink_info::check (char *path, const suffix_info *suffixes, fs_info &fs, +#ifdef FAST_SYMLINK_CHECK + path_conv_handle &conv_hdl, path_conv *pc) +#else path_conv_handle &conv_hdl) +#endif { int res; HANDLE h; +#ifdef FAST_SYMLINK_CHECK + NTSTATUS status = -1; + LARGE_INTEGER filesize = { QuadPart:0LL }; +#else NTSTATUS status; +#endif UNICODE_STRING upath; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; @@ -2225,6 +2249,30 @@ restart: # define MIN_STAT_ACCESS (READ_CONTROL | FILE_READ_ATTRIBUTES) # define FULL_STAT_ACCESS (SYNCHRONIZE | GENERIC_READ) + +#ifdef FAST_SYMLINK_CHECK +#define FILE_CREATE_FLAGS (FILE_OPEN_REPARSE_POINT | FILE_RANDOM_ACCESS) + +#define OPEN_IF_NEEDED() \ + if (!h) \ + { \ + status = NtCreateFile (&h, \ + access = FULL_STAT_ACCESS, &attr, &io, NULL, 0, \ + FILE_SHARE_VALID_FLAGS, FILE_OPEN, \ + FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT, \ + eabuf, easize); \ + if (status == STATUS_ACCESS_DENIED) \ + { \ + status = NtCreateFile (&h, access = MIN_STAT_ACCESS, &attr, &io, \ + NULL, 0, FILE_SHARE_VALID_FLAGS, FILE_OPEN, \ + FILE_CREATE_FLAGS, \ + eabuf, easize); \ + debug_printf ("%p = NtCreateFile (2:%S)", status, &upath); \ + } \ + else \ + debug_printf ("%p = NtCreateFile (1:%S)", status, &upath); \ + } +#endif ACCESS_MASK access = 0; bool had_ext = !!*ext_here; @@ -2239,6 +2287,22 @@ restart: NtClose (h); h = NULL; } +#ifdef FAST_SYMLINK_CHECK + if (fast_symlink_check) + { + filesize.QuadPart = 0LL; + if (path_conv_update_fi(pc, &upath)>0) + { + status = 0; + fileattr = pc->fi.FileAttributes; + filesize = pc->fi.AllocationSize; + } + else + OPEN_IF_NEEDED(); + } + else + { +#endif /* The EA given to NtCreateFile allows to get a handle to a symlink on an NFS share, rather than getting a handle to the target of the symlink (which would spoil the task of this method quite a bit). @@ -2246,20 +2310,31 @@ restart: to special case NFS too much. */ status = NtCreateFile (&h, access = FULL_STAT_ACCESS, &attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS, FILE_OPEN, +#ifdef FAST_SYMLINK_CHECK + FILE_CREATE_FLAGS, +#else FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT, +#endif eabuf, easize); if (status == STATUS_ACCESS_DENIED) { status = NtCreateFile (&h, access = MIN_STAT_ACCESS, &attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS, FILE_OPEN, +#ifdef FAST_SYMLINK_CHECK + FILE_CREATE_FLAGS, +#else FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT, +#endif eabuf, easize); debug_printf ("%p = NtCreateFile (2:%S)", status, &upath); } else debug_printf ("%p = NtCreateFile (1:%S)", status, &upath); +#ifdef FAST_SYMLINK_CHECK + } +#endif /* No right to access EAs or EAs not supported? */ if (!NT_SUCCESS (status) && (status == STATUS_ACCESS_DENIED @@ -2281,14 +2356,22 @@ restart: } status = NtOpenFile (&h, access = FULL_STAT_ACCESS, &attr, &io, FILE_SHARE_VALID_FLAGS, +#ifdef FAST_SYMLINK_CHECK + FILE_CREATE_FLAGS); +#else FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT); +#endif if (status == STATUS_ACCESS_DENIED) { status = NtOpenFile (&h, access = MIN_STAT_ACCESS, &attr, &io, FILE_SHARE_VALID_FLAGS, +#ifdef FAST_SYMLINK_CHECK + FILE_CREATE_FLAGS); +#else FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT); +#endif debug_printf ("%p = NtOpenFile (no-EAs 2:%S)", status, &upath); } else @@ -2306,8 +2389,12 @@ restart: attr.Attributes = OBJ_CASE_INSENSITIVE; status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES, &attr, &io, FILE_SHARE_VALID_FLAGS, +#ifdef FAST_SYMLINK_CHECK + FILE_CREATE_FLAGS); +#else FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT); +#endif debug_printf ("%p = NtOpenFile (broken-UDF, %S)", status, &upath); attr.Attributes = 0; if (NT_SUCCESS (status)) @@ -2366,11 +2453,28 @@ restart: /* Check file system while we're having the file open anyway. This speeds up path_conv noticably (~10%). */ && (fs.inited () || fs.update (&upath, h)) +#ifdef FAST_SYMLINK_CHECK + && (fast_symlink_check ? path_conv_update_fi(pc, &upath)>0 : + NT_SUCCESS (status = fs.has_buggy_basic_info () + ? NtQueryAttributesFile (&attr, &fbi) + : NtQueryInformationFile (h, &io, &fbi, sizeof fbi, + FileBasicInformation)))) + { + if (fast_symlink_check) + { + fileattr = pc->fi.FileAttributes; + filesize = pc->fi.AllocationSize; + } + else + fileattr = fbi.FileAttributes; + } +#else && NT_SUCCESS (status = fs.has_buggy_basic_info () ? NtQueryAttributesFile (&attr, &fbi) : NtQueryInformationFile (h, &io, &fbi, sizeof fbi, FileBasicInformation))) fileattr = fbi.FileAttributes; +#endif else { debug_printf ("%p = NtQueryInformationFile (%S)", status, &upath); @@ -2484,6 +2588,9 @@ restart: if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY)) == FILE_ATTRIBUTE_READONLY && suffix.lnk_match ()) { +#ifdef FAST_SYMLINK_CHECK + OPEN_IF_NEEDED(); +#endif if (!(access & GENERIC_READ)) res = 0; else @@ -2526,6 +2633,9 @@ restart: else if ((fileattr & FILE_ATTRIBUTE_REPARSE_POINT) && !fs.is_remote_drive()) { +#ifdef FAST_SYMLINK_CHECK + OPEN_IF_NEEDED(); +#endif res = check_reparse_point (h); if (res == -1) { @@ -2550,8 +2660,17 @@ restart: have the `system' file attribute. Only files can be symlinks (which can be symlinks to directories). */ else if ((fileattr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) +#ifdef FAST_SYMLINK_CHECK + == FILE_ATTRIBUTE_SYSTEM && + (!fast_symlink_check ? 1 : + (filesize.QuadPart>strlen("!") && filesize.QuadPart<512))) +#else == FILE_ATTRIBUTE_SYSTEM) +#endif { +#ifdef FAST_SYMLINK_CHECK + OPEN_IF_NEEDED(); +#endif if (!(access & GENERIC_READ)) res = 0; else @@ -2565,6 +2684,9 @@ restart: (which can be symlinks to directories). */ else if (fs.is_nfs () && !no_ea && !(fileattr & FILE_ATTRIBUTE_DIRECTORY)) { +#ifdef FAST_SYMLINK_CHECK + OPEN_IF_NEEDED(); +#endif if (!(access & GENERIC_READ)) res = 0; else @@ -2581,6 +2703,10 @@ restart: break; } +#ifdef FAST_SYMLINK_CHECK + if (pflags & PC_KEEP_HANDLE) + OPEN_IF_NEEDED(); +#endif if (h) { if (pflags & PC_KEEP_HANDLE) Index: winsup/cygwin/path.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/path.h,v retrieving revision 1.145 diff -u -p -r1.145 path.h --- winsup/cygwin/path.h 4 Jul 2010 17:12:26 -0000 1.145 +++ winsup/cygwin/path.h 13 Sep 2010 11:42:06 -0000 @@ -115,7 +115,20 @@ public: }; class symlink_info; +#if defined(FAST_SYMLINK_CHECK) || defined(CACHE_FI) +struct FILE_NETWORK_OPEN_INFORMATION2 { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; +}; +extern bool inode_from_hash; +int path_conv_update_fi(path_conv *pc, PUNICODE_STRING path); +#endif class path_conv { DWORD fileattr; @@ -133,11 +146,21 @@ class path_conv const char *normalized_path; int error; device dev; +#if defined(FAST_SYMLINK_CHECK) || defined(CACHE_FI) + int fi_updated; + wchar_t fi_path[MAX_PATH]; + FILE_NETWORK_OPEN_INFORMATION2 fi; +#endif bool isremote () const {return fs.is_remote_drive ();} ULONG objcaseinsensitive () const {return caseinsensitive;} bool has_acls () const {return !(path_flags & PATH_NOACL) && fs.has_acls (); } +#ifdef INODE_FROM_HASH + bool hasgood_inode () const {return inode_from_hash ? 0 : + !(path_flags & PATH_IHASH); } +#else bool hasgood_inode () const {return !(path_flags & PATH_IHASH); } +#endif bool isgood_inode (__ino64_t ino) const; int has_symlinks () const {return path_flags & PATH_HAS_SYMLINKS;} int has_dos_filenames_only () const {return path_flags & PATH_DOS;} @@ -200,7 +223,11 @@ class path_conv path_conv (const device& in_dev) : fileattr (INVALID_FILE_ATTRIBUTES), wide_path (NULL), path (NULL), path_flags (0), known_suffix (NULL), normalized_path (NULL), error (0), +#if defined(FAST_SYMLINK_CHECK) || defined(CACHE_FI) + dev (in_dev), fi_updated (0) +#else dev (in_dev) +#endif { set_path (in_dev.native); } @@ -209,6 +236,9 @@ class path_conv const suffix_info *suffixes = NULL) : fileattr (INVALID_FILE_ATTRIBUTES), wide_path (NULL), path (NULL), path_flags (0), known_suffix (NULL), normalized_path (NULL), error (0) +#if defined(FAST_SYMLINK_CHECK) || defined(CACHE_FI) + , fi_updated (0) +#endif { check (src, opt, suffixes); } @@ -217,6 +247,9 @@ class path_conv const suffix_info *suffixes = NULL) : fileattr (INVALID_FILE_ATTRIBUTES), wide_path (NULL), path (NULL), path_flags (0), known_suffix (NULL), normalized_path (NULL), error (0) +#if defined(FAST_SYMLINK_CHECK) || defined(CACHE_FI) + , fi_updated (0) +#endif { check (src, opt | PC_NULLEMPTY, suffixes); } @@ -225,6 +258,9 @@ class path_conv const suffix_info *suffixes = NULL) : fileattr (INVALID_FILE_ATTRIBUTES), wide_path (NULL), path (NULL), path_flags (0), known_suffix (NULL), normalized_path (NULL), error (0) +#if defined(FAST_SYMLINK_CHECK) || defined(CACHE_FI) + , fi_updated (0) +#endif { check (src, opt | PC_NULLEMPTY, suffixes); } @@ -232,6 +268,9 @@ class path_conv path_conv () : fileattr (INVALID_FILE_ATTRIBUTES), wide_path (NULL), path (NULL), path_flags (0), known_suffix (NULL), normalized_path (NULL), error (0) +#if defined(FAST_SYMLINK_CHECK) || defined(CACHE_FI) + , fi_updated (0) +#endif {} ~path_conv (); Index: winsup/cygwin/security.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/security.cc,v retrieving revision 1.242 diff -u -p -r1.242 security.cc --- winsup/cygwin/security.cc 22 Jun 2010 09:54:36 -0000 1.242 +++ winsup/cygwin/security.cc 13 Sep 2010 11:42:07 -0000 @@ -26,6 +26,166 @@ details. */ #include "pwdgrp.h" #include +#ifdef FAST_SECUTIRY_CHECK +bool fast_security_info = true; + +extern "C" { +NTSTATUS WINAPI RtlGetOwnerSecurityDescriptor( + PSECURITY_DESCRIPTOR SecurityDescriptor, PSID *Owner, + PBOOLEAN OwnerDefaulted); +NTSTATUS WINAPI RtlGetGroupSecurityDescriptor( + PSECURITY_DESCRIPTOR SecurityDescriptor, PSID *Group, + PBOOLEAN GroupDefaulted); +NTSTATUS WINAPI RtlGetDaclSecurityDescriptor( + PSECURITY_DESCRIPTOR SecurityDescriptor, + PBOOLEAN DaclPresent, PACL *Dacl, PBOOLEAN DaclDefaulted); +NTSTATUS WINAPI RtlGetSaclSecurityDescriptor( + PSECURITY_DESCRIPTOR SecurityDescriptor, PBOOLEAN SaclPresent, PACL *Sacl, + PBOOLEAN SaclDefaulted); +ULONG WINAPI RtlLengthSecurityDescriptor( + PSECURITY_DESCRIPTOR SecurityDescriptor); +NTSTATUS WINAPI RtlCreateSecurityDescriptor( + PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG Revision); +NTSTATUS WINAPI RtlCopySid(ULONG DestinationSidLength, PSID DestinationSid, + PSID SourceSid); +ULONG WINAPI RtlLengthSid (PSID Sid); +NTSTATUS WINAPI RtlSetOwnerSecurityDescriptor( + PSECURITY_DESCRIPTOR SecurityDescriptor, PSID Owner, + BOOLEAN OwnerDefaulted); +NTSTATUS WINAPI RtlSetGroupSecurityDescriptor( + PSECURITY_DESCRIPTOR SecurityDescriptor, PSID Group, + BOOLEAN GroupDefaulted); +NTSTATUS WINAPI RtlSetDaclSecurityDescriptor( + PSECURITY_DESCRIPTOR SecurityDescriptor, BOOLEAN DaclPresent, PACL Dacl, + BOOLEAN DaclDefaulted); +NTSTATUS WINAPI RtlSetSaclSecurityDescriptor( + PSECURITY_DESCRIPTOR SecurityDescriptor, BOOLEAN SaclPresent, PACL Sacl, + BOOLEAN SaclDefaulted); +} + +#define IF_PTR_SET(ptr, val) \ +do { \ + if (ptr) \ + *(ptr) = val; \ +} while (0) +DWORD zGetSecurityDescriptorParts(PISECURITY_DESCRIPTOR sd, + SECURITY_INFORMATION si, PSID *sido, PSID *sidg, + PACL *dacl, PACL *sacl, PSECURITY_DESCRIPTOR *out_sd) +{ + NTSTATUS stat = 0; + PISECURITY_DESCRIPTOR _out_sd = NULL; + PACL _dacl = NULL, _sacl = NULL; + BOOLEAN unused, have_param; + DWORD ret = NO_ERROR; + char *buf; + PSID owner = NULL, group = NULL; + IF_PTR_SET(sido, NULL); + IF_PTR_SET(sidg, NULL); + IF_PTR_SET(dacl, NULL); + IF_PTR_SET(sacl, NULL); + *out_sd = NULL; + if ((stat = RtlGetOwnerSecurityDescriptor(sd, &owner, &unused))) + goto Exit; + if ((stat = RtlGetGroupSecurityDescriptor(sd, &group, &unused))) + goto Exit; + if ((stat = RtlGetDaclSecurityDescriptor(sd, &have_param, &_dacl, + &unused))) + { + goto Exit; + } + if (!have_param) + _dacl = NULL; + if ((stat = RtlGetSaclSecurityDescriptor(sd, &have_param, &_sacl, + &unused))) + { + goto Exit; + } + if (!have_param) + _sacl = NULL; + _out_sd = (PISECURITY_DESCRIPTOR)LocalAlloc(LPTR, + RtlLengthSecurityDescriptor(sd)); + RtlCreateSecurityDescriptor(_out_sd, SECURITY_DESCRIPTOR_REVISION); + buf = (char *)_out_sd + sizeof(SECURITY_DESCRIPTOR); + if (si & OWNER_SECURITY_INFORMATION) + { + if (!owner) + { + ret = ERROR_NO_SECURITY_ON_OBJECT; + goto Exit; + } + RtlCopySid(RtlLengthSid(owner), (PSID)buf, owner); + RtlSetOwnerSecurityDescriptor(_out_sd, (PSID)buf, 0); + buf += RtlLengthSid(owner); + IF_PTR_SET(sido, _out_sd->Owner); + } + if (si & GROUP_SECURITY_INFORMATION) + { + if (!group) + { + ret = ERROR_NO_SECURITY_ON_OBJECT; + goto Exit; + } + RtlCopySid(RtlLengthSid(group), (PSID)buf, group); + RtlSetGroupSecurityDescriptor(_out_sd, (PSID)buf, 0); + buf += RtlLengthSid(group); + IF_PTR_SET(sidg, _out_sd->Group); + } + if ((si & DACL_SECURITY_INFORMATION) && _dacl) + { + memcpy(buf, _dacl, _dacl->AclSize); + RtlSetDaclSecurityDescriptor(_out_sd, 1, (ACL *)buf, 0); + IF_PTR_SET(dacl, _out_sd->Dacl); + } + if ((si & SACL_SECURITY_INFORMATION) && _sacl) + { + memcpy(buf, _sacl, _sacl->AclSize); + RtlSetSaclSecurityDescriptor(_out_sd, 1, (ACL *)buf, 0); + IF_PTR_SET(sacl, _out_sd->Sacl); + } + *out_sd = _out_sd; + _out_sd = NULL; +Exit: + if (stat) + ret = RtlNtStatusToDosError(stat); + if (_out_sd) + LocalFree(_out_sd); + return ret; +} + +#define PSD_BASE_LENGTH 1024 +DWORD zGetSecurityInfo(HANDLE fh, SE_OBJECT_TYPE ObjectType, + SECURITY_INFORMATION SecurityInfo, PSID *ppsidOwner, PSID *ppsidGroup, + PACL *ppDacl, PACL *ppSacl, PSECURITY_DESCRIPTOR *ppSecurityDescriptor) +{ + ULONG bytes_needed = 0; + int ret; + if ((ret = NtQuerySecurityObject(fh, SecurityInfo, + (PISECURITY_DESCRIPTOR)_my_tls.locals.security_buf, + _my_tls.locals.security_buf_len, &bytes_needed))) + { + if (ret!=STATUS_BUFFER_TOO_SMALL) + return RtlNtStatusToDosError(ret); + _my_tls.locals.security_buf = realloc(_my_tls.locals.security_buf, + bytes_needed); + _my_tls.locals.security_buf_len = bytes_needed; + if ((ret = NtQuerySecurityObject(fh, SecurityInfo, + (PISECURITY_DESCRIPTOR)_my_tls.locals.security_buf, + _my_tls.locals.security_buf_len, &bytes_needed))) + { + return ret; + } + } + if (ret==NO_ERROR) + { + return zGetSecurityDescriptorParts( + (PISECURITY_DESCRIPTOR)_my_tls.locals.security_buf, + SecurityInfo, ppsidOwner, ppsidGroup, ppDacl, ppSacl, + ppSecurityDescriptor); + } + return ret; +} +#endif + #define ALL_SECURITY_INFORMATION (DACL_SECURITY_INFORMATION \ | GROUP_SECURITY_INFORMATION \ | OWNER_SECURITY_INFORMATION) @@ -47,8 +207,21 @@ get_file_sd (HANDLE fh, path_conv &pc, s INHERITED_ACE flag is never set. Only by calling GetSecurityInfo you get this information. Oh well. */ PSECURITY_DESCRIPTOR psd; +#ifdef FAST_SECUTIRY_CHECK + if (fast_security_info) + { + error = zGetSecurityInfo (fh, SE_FILE_OBJECT, + ALL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &psd); + } + else + { + error = GetSecurityInfo (fh, SE_FILE_OBJECT, + ALL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &psd); + } +#else error = GetSecurityInfo (fh, SE_FILE_OBJECT, ALL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &psd); +#endif if (error == ERROR_SUCCESS) { sd = psd;