diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2010-06-15 12:05:15 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2010-06-15 12:05:15 +0000 |
commit | 5a0d1edba4b31ee2965fdbc86533982eadc91df4 (patch) | |
tree | 829d47f18b4231d8945c660c806f93372db7dbc2 /winsup/cygwin/fhandler_disk_file.cc | |
parent | 51ec3f5c989686130e1edbf1c8d902d5df3ff2e1 (diff) | |
download | cygnal-5a0d1edba4b31ee2965fdbc86533982eadc91df4.tar.gz cygnal-5a0d1edba4b31ee2965fdbc86533982eadc91df4.tar.bz2 cygnal-5a0d1edba4b31ee2965fdbc86533982eadc91df4.zip |
* dtable.cc (dtable::dup_worker): Reset path_conv handle in duplicated
fhandler.
* fhandler.cc (fhandler_base::fstatvfs): Keep handle in created
path_conv.
* fhandler.h (fhandler_base::get_stat_access): New method.
(fhandler_base::get_stat_handle): New method.
* fhandler_disk_file.cc (fhandler_base::fstat_by_handle): Use handle
returned by get_stat_handle. Only request inode from system if it
isn't already set in the fhandler, and only for filesystems supporting
them.
(fhandler_base::fstat_fs): Use handle returned by get_stat_handle.
Change the way open_fs is called. Explain why.
(fhandler_base::fstat_helper): Use handle returned by get_stat_handle.
Never use 0 inode number. Simplify executable recognition by re-using
get_stat_handle if file could be opened with sufficient rights.
(fhandler_disk_file::fstatvfs): Use handle returned by get_stat_handle.
(fhandler_disk_file::facl): Use handle returned by get_stat_handle in
GETACL and GETACLCNT cases.
(fhandler_disk_file::link): Use handle returned by get_stat_handle
instead of opening file here again. Add comment.
(readdir_get_ino): Keep handle in created path_conv and drop
opening file.
* ntdll.h (wait_pending): New helper function.
* path.cc (symlink_info::check): Drop unused 'opt' parameter from
declaration. Add path_conv_handle argument.
(path_conv::check): Make sure conv_handle is closed. Keep
PC_KEEP_HANDLE flag in pflags_or. Accommodate call to sym.check to
new args.
(path_conv::~path_conv): Close conv_handle.
(symlink_info::check_shortcut): Don't re-open file here, just use
incoming handle. Drop goto's and label out.
(symlink_info::check_sysfile): Don't re-open file here, just use
incoming handle. Keep track of file position to accommodate the fact
that file has been opened asynchronously in calling function.
(symlink_info::check_nfs_symlink): Don't re-open file here, just use
incoming handle.
(symlink_info::check): Drop unused 'opt' parameter. Add
path_conv_handle argument. Always try to open file with GENERIC_READ
rights first to allow reading file content w/o having to re-open the
file. Drop back to READ_CONTROL | FILE_READ_ATTRIBUTES otherwise.
Call symlink test functions (except for check_reparse_point) only if
file could be opened with GENERIC_READ. Keep file handle open if
PC_KEEP_HANDLE is set in pflags.
* path.h (enum pathconv_arg): Add PC_KEEP_HANDLE flag.
(class path_conv_handle): New class.
(class path_conv): Add conv_handle member.
(path_conv::operator =): Duplicate conv_handle.
(path_conv::handle): New method.
(path_conv::access): New method.
(path_conv::reset_conv_handle): New method.
(path_conv::close_conv_handle): New method.
Diffstat (limited to 'winsup/cygwin/fhandler_disk_file.cc')
-rw-r--r-- | winsup/cygwin/fhandler_disk_file.cc | 144 |
1 files changed, 62 insertions, 82 deletions
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 55bc30c40..e456b11f7 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -333,6 +333,7 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) { NTSTATUS status; IO_STATUS_BLOCK io; + HANDLE h = get_stat_handle (); if (pc.fs_is_nfs ()) return fstat_by_nfs_ea (buf); @@ -351,22 +352,22 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) if (pc.has_buggy_basic_info ()) { - status = NtQueryInformationFile (get_handle (), &io, &fi, sizeof fi, + status = NtQueryInformationFile (h, &io, &fi, sizeof fi, FileNetworkOpenInformation); /* The timestamps are in the same relative memory location, only the DOS attributes have to be moved. */ fi.fbi.FileAttributes = fi.fnoi.FileAttributes; } else - status = NtQueryInformationFile (get_handle (), &io, &fi.fbi, sizeof fi.fbi, - FileBasicInformation); + status = NtQueryInformationFile (h, &io, &fi.fbi, + sizeof fi.fbi, FileBasicInformation); if (!NT_SUCCESS (status)) { debug_printf ("%p = NtQueryInformationFile(%S, FileBasicInformation)", status, pc.get_nt_native_path ()); return -1; } - status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi, + status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi, FileStandardInformation); if (!NT_SUCCESS (status)) { @@ -374,13 +375,17 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) status, pc.get_nt_native_path ()); return -1; } - status = NtQueryInformationFile (get_handle (), &io, &fii, sizeof fii, - FileInternalInformation); - if (!NT_SUCCESS (status)) + if (!ino && pc.hasgood_inode ()) { - debug_printf ("%p = NtQueryInformationFile(%S, FileInternalInformation)", - status, pc.get_nt_native_path ()); - return -1; + status = NtQueryInformationFile (h, &io, &fii, sizeof fii, + FileInternalInformation); + if (!NT_SUCCESS (status)) + { + debug_printf ("%p = NtQueryInformationFile(%S, FileInternalInformation)", + status, pc.get_nt_native_path ()); + return -1; + } + ino = fii.FileId.QuadPart; } /* If the change time is 0, it's a file system which doesn't support a change timestamp. In that case use the LastWriteTime @@ -397,7 +402,7 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) get_dev (), fsi.EndOfFile.QuadPart, fsi.AllocationSize.QuadPart, - fii.FileId.QuadPart, + ino, fsi.NumberOfLinks, fi.fbi.FileAttributes); } @@ -492,7 +497,7 @@ fhandler_base::fstat_fs (struct __stat64 *buf) int oret; int open_flags = O_RDONLY | O_BINARY; - if (get_handle ()) + if (get_stat_handle ()) { if (!nohandle () && !is_fs_special ()) res = fstat_by_handle (buf); @@ -500,8 +505,16 @@ fhandler_base::fstat_fs (struct __stat64 *buf) res = fstat_by_name (buf); return res; } - query_open (query_read_attributes); + /* 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 + so we try to avoid that. */ oret = open_fs (open_flags, 0); + if (!oret) + { + query_open (query_read_attributes); + oret = open_fs (open_flags, 0); + } if (oret) { /* We now have a valid handle, regardless of the "nohandle" state. @@ -546,6 +559,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf, { IO_STATUS_BLOCK st; FILE_COMPRESSION_INFORMATION fci; + HANDLE h = get_stat_handle (); to_timestruc_t ((PFILETIME) LastAccessTime, &buf->st_atim); to_timestruc_t ((PFILETIME) LastWriteTime, &buf->st_mtim); @@ -563,7 +577,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf, #endif /* Enforce namehash as inode number on untrusted file systems. */ - if (pc.isgood_inode (nFileIndex)) + if (nFileIndex && pc.isgood_inode (nFileIndex)) buf->st_ino = (__ino64_t) nFileIndex; else buf->st_ino = get_ino (); @@ -576,9 +590,9 @@ fhandler_base::fstat_helper (struct __stat64 *buf, buf->st_blocks = (nAllocSize + S_BLKSIZE - 1) / S_BLKSIZE; else if (::has_attribute (dwFileAttributes, FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_SPARSE_FILE) - && get_handle () && !is_fs_special () - && !NtQueryInformationFile (get_handle (), &st, (PVOID) &fci, - sizeof fci, FileCompressionInformation)) + && h && !is_fs_special () + && !NtQueryInformationFile (h, &st, (PVOID) &fci, sizeof fci, + FileCompressionInformation)) /* Otherwise we request the actual amount of bytes allocated for compressed and sparsed files. */ buf->st_blocks = (fci.CompressedFileSize.QuadPart + S_BLKSIZE - 1) @@ -597,15 +611,14 @@ fhandler_base::fstat_helper (struct __stat64 *buf, buf->st_size = pc.get_symlink_length (); /* symlinks are everything for everyone! */ buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; - get_file_attribute (get_handle (), pc, NULL, + get_file_attribute (h, pc, NULL, &buf->st_uid, &buf->st_gid); goto done; } else if (pc.issocket ()) buf->st_mode = S_IFSOCK; - if (!get_file_attribute (is_fs_special () && !pc.issocket () - ? NULL : get_handle (), pc, + if (!get_file_attribute (is_fs_special () && !pc.issocket () ? NULL : h, pc, &buf->st_mode, &buf->st_uid, &buf->st_gid)) { /* If read-only attribute is set, modify ntsec return value */ @@ -659,50 +672,26 @@ fhandler_base::fstat_helper (struct __stat64 *buf, shebang scripts. */ if (pc.exec_state () == dont_know_if_executable) { - OBJECT_ATTRIBUTES attr; + LARGE_INTEGER off = { QuadPart:0LL }; + char magic[3]; NTSTATUS status; - HANDLE h; IO_STATUS_BLOCK io; - /* The NWFS implementation is frighteningly incomplete. When - re-opening a file by handle, the subsequent NtReadFile - returns with the weird status STATUS_FILE_IS_A_DIRECTORY. - We're still using the re-open by handle method for all - other filesystems since it's 8-10% faster than opening - by name. */ - if (pc.fs_is_nwfs ()) - InitializeObjectAttributes (&attr, pc.get_nt_native_path (), - OBJ_CASE_INSENSITIVE, NULL, NULL) - else - InitializeObjectAttributes (&attr, &ro_u_empty, 0, - get_handle (), NULL); - status = NtOpenFile (&h, SYNCHRONIZE | FILE_READ_DATA, - &attr, &io, FILE_SHARE_VALID_FLAGS, - FILE_SYNCHRONOUS_IO_NONALERT); - if (NT_SUCCESS (status)) + if (get_stat_access () & (GENERIC_READ | FILE_READ_DATA)) { - LARGE_INTEGER off = { QuadPart:0LL }; - char magic[3]; - - status = NtReadFile (h, NULL, NULL, NULL, &io, magic, - 3, &off, NULL); - if (NT_SUCCESS (status)) - { - if (has_exec_chars (magic, io.Information)) - { - /* Heureka, it's an executable */ - pc.set_exec (); - buf->st_mode |= STD_XBITS; - } - } - else + status = NtReadFile (h, NULL, NULL, NULL, + &io, magic, 3, &off, NULL); + status = wait_pending (status, h, io); + if (!NT_SUCCESS (status)) debug_printf ("%p = NtReadFile(%S)", status, pc.get_nt_native_path ()); - NtClose (h); + else if (has_exec_chars (magic, io.Information)) + { + /* Heureka, it's an executable */ + pc.set_exec (); + buf->st_mode |= STD_XBITS; + } } - else - debug_printf ("%p = NtOpenFile(%S)", status, - pc.get_nt_native_path ()); } } if (pc.exec_state () == is_executable) @@ -740,7 +729,7 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs) IO_STATUS_BLOCK io; FILE_FS_FULL_SIZE_INFORMATION full_fsi; FILE_FS_SIZE_INFORMATION fsi; - HANDLE fh = get_handle (); + HANDLE fh = get_stat_handle (); if (!fh) { @@ -1050,7 +1039,8 @@ cant_access_acl: } else { - if (!get_handle ()) + if ((cmd == SETACL && !get_handle ()) + || (cmd != SETACL && !get_stat_handle ())) { query_open (cmd == SETACL ? query_write_control : query_read_control); if (!(oret = open (O_BINARY, 0))) @@ -1087,10 +1077,10 @@ cant_access_acl: if (!aclbufp) set_errno(EFAULT); else - res = getacl (get_handle (), pc, nentries, aclbufp); + res = getacl (get_stat_handle (), pc, nentries, aclbufp); break; case GETACLCNT: - res = getacl (get_handle (), pc, 0, NULL); + res = getacl (get_stat_handle (), pc, 0, NULL); break; default: set_errno (EINVAL); @@ -1277,17 +1267,13 @@ fhandler_disk_file::link (const char *newpath) } } - HANDLE fh; - NTSTATUS status; - OBJECT_ATTRIBUTES attr; - IO_STATUS_BLOCK io; - status = NtOpenFile (&fh, READ_CONTROL, - pc.get_object_attr (attr, sec_none_nih), &io, - FILE_SHARE_VALID_FLAGS, - FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT); - if (!NT_SUCCESS (status)) + /* We only need READ_CONTROL access so the handle returned in pc is + sufficient. And if the file couldn't be opened with READ_CONTROL + access in path_conv, we won't be able to do it here anyway. */ + HANDLE fh = get_stat_handle (); + if (!fh) { - __seterrno_from_nt_status (status); + set_errno (EACCES); return -1; } PUNICODE_STRING tgt = newpc.get_nt_native_path (); @@ -1296,8 +1282,10 @@ fhandler_disk_file::link (const char *newpath) pfli->ReplaceIfExists = FALSE; pfli->RootDirectory = NULL; memcpy (pfli->FileName, tgt->Buffer, pfli->FileNameLength = tgt->Length); + + NTSTATUS status; + IO_STATUS_BLOCK io; status = NtSetInformationFile (fh, &io, pfli, size, FileLinkInformation); - NtClose (fh); if (!NT_SUCCESS (status)) { if (status == STATUS_INVALID_DEVICE_REQUEST) @@ -1764,8 +1752,6 @@ readdir_get_ino (const char *path, bool dot_dot) char *fname; struct __stat64 st; HANDLE hdl; - OBJECT_ATTRIBUTES attr; - IO_STATUS_BLOCK io; __ino64_t ino = 0; if (dot_dot) @@ -1777,7 +1763,7 @@ readdir_get_ino (const char *path, bool dot_dot) strcpy (c, ".."); path = fname; } - path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX | PC_NOWARN); + path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX | PC_NOWARN | PC_KEEP_HANDLE); if (pc.isspecial ()) { if (!stat_worker (pc, &st)) @@ -1785,17 +1771,11 @@ readdir_get_ino (const char *path, bool dot_dot) } else if (!pc.hasgood_inode ()) ino = hash_path_name (0, pc.get_nt_native_path ()); - else if (NT_SUCCESS (NtOpenFile (&hdl, READ_CONTROL, - pc.get_object_attr (attr, sec_none_nih), - &io, FILE_SHARE_VALID_FLAGS, - FILE_OPEN_FOR_BACKUP_INTENT - | (pc.is_rep_symlink () - ? FILE_OPEN_REPARSE_POINT : 0)))) + else if ((hdl = pc.handle ()) != NULL) { ino = pc.get_ino_by_handle (hdl); if (!ino) ino = hash_path_name (0, pc.get_nt_native_path ()); - NtClose (hdl); } return ino; } |