* fhandler.h (fhandler_base::get_stat_access): Delete.

* fhandler_disk_file.cc (fhandler_base::fstat_helper): Always check
	executable suffix to get x-bits for .exe files also in notexec case.
	Always reopen file when checking for file header.
	* ntdll.h (wait_pending): Delete.
	* path.cc (symlink_info::check_shortcut): Drop call to wait_pending
	since file is always opened for sync IO.
	(symlink_info::check_sysfile): Ditto.
	(MIN_STAT_ACCESS): Remove.
	(FULL_STAT_ACCESS): Remove.
	(symlink_info::check): Drop access flag.  Revert to open file with
	just read attributes access.  Reorder symlink check to check for
	reparse points first.  Don't check reparse points for anything else,
	even on remote drives.  Open file for GENERIC_READ when trying to
	read shortcuts or system-bit symlinks. Accommodate dropped access
	flag in call to path_conv_handle::set.
	* path.h (class path_conv_handle): Drop access flag and accommodate
	all related methods.
This commit is contained in:
Corinna Vinschen 2010-10-07 14:03:26 +00:00
parent ca11a4f34f
commit dd0821e345
6 changed files with 118 additions and 126 deletions

View File

@ -1,3 +1,24 @@
2010-09-07 Corinna Vinschen <corinna@vinschen.de>
* fhandler.h (fhandler_base::get_stat_access): Delete.
* fhandler_disk_file.cc (fhandler_base::fstat_helper): Always check
executable suffix to get x-bits for .exe files also in notexec case.
Always reopen file when checking for file header.
* ntdll.h (wait_pending): Delete.
* path.cc (symlink_info::check_shortcut): Drop call to wait_pending
since file is always opened for sync IO.
(symlink_info::check_sysfile): Ditto.
(MIN_STAT_ACCESS): Remove.
(FULL_STAT_ACCESS): Remove.
(symlink_info::check): Drop access flag. Revert to open file with
just read attributes access. Reorder symlink check to check for
reparse points first. Don't check reparse points for anything else,
even on remote drives. Open file for GENERIC_READ when trying to
read shortcuts or system-bit symlinks. Accommodate dropped access
flag in call to path_conv_handle::set.
* path.h (class path_conv_handle): Drop access flag and accommodate
all related methods.
2010-09-06 Corinna Vinschen <corinna@vinschen.de>
* posix_ipc.cc (ipc_mutex_init): Call NtCreateMutant to make sure the

View File

@ -198,7 +198,6 @@ class fhandler_base
int get_access () const { return access; }
void set_access (int x) { access = x; }
int get_stat_access () const { return pc.handle () ? pc.access () : access; }
int get_flags () { return openflags; }
void set_flags (int x, int supplied_bin = 0);

View File

@ -591,7 +591,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
{
buf->st_mode |= S_IFREG;
/* Check suffix for executable file. */
if (pc.exec_state () == dont_know_if_executable)
if (pc.exec_state () != is_executable)
{
PUNICODE_STRING path = pc.get_nt_native_path ();
@ -604,34 +604,28 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
shebang scripts. */
if (pc.exec_state () == dont_know_if_executable)
{
LARGE_INTEGER off = { QuadPart:0LL };
char magic[3];
OBJECT_ATTRIBUTES attr;
NTSTATUS status = 0;
IO_STATUS_BLOCK io;
bool opened = false;
if (h == get_handle ())
{
/* We have been opened via fstat. We have to re-open the
file. Either the file is not opened for reading, or the
read will change the file position. */
OBJECT_ATTRIBUTES attr;
pc.init_reopen_attr (&attr, h);
status = NtOpenFile (&h, SYNCHRONIZE | FILE_READ_DATA,
&attr, &io, FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT
| FILE_OPEN_REPARSE_POINT);
if (!NT_SUCCESS (status))
debug_printf ("%p = NtOpenFile(%S)", status,
pc.get_nt_native_path ());
else
opened = true;
}
if (NT_SUCCESS (status))
/* We have to re-open the file. Either the file is not opened
for reading, or the read will change the file position of the
original handle. */
pc.init_reopen_attr (&attr, h);
status = NtOpenFile (&h, SYNCHRONIZE | FILE_READ_DATA,
&attr, &io, FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS (status))
debug_printf ("%p = NtOpenFile(%S)", status,
pc.get_nt_native_path ());
else
{
LARGE_INTEGER off = { QuadPart:0LL };
char magic[3];
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 ());
@ -641,9 +635,8 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
pc.set_exec ();
buf->st_mode |= STD_XBITS;
}
NtClose (h);
}
if (opened)
NtClose (h);
}
}
if (pc.exec_state () == is_executable)

View File

@ -879,16 +879,6 @@ typedef enum _EVENT_INFORMATION_CLASS
#define NtCurrentProcess() ((HANDLE) 0xffffffff)
#define NtCurrentThread() ((HANDLE) 0xfffffffe)
/* Helper macro for sync I/O with async handle. */
inline NTSTATUS
wait_pending (NTSTATUS status, HANDLE h, IO_STATUS_BLOCK &io)
{
if (status != STATUS_PENDING)
return status;
WaitForSingleObject (h, INFINITE);
return io.Status;
}
extern "C"
{
NTSTATUS NTAPI NtAdjustPrivilegesToken (HANDLE, BOOLEAN, PTOKEN_PRIVILEGES,

View File

@ -1752,7 +1752,6 @@ symlink_info::check_shortcut (HANDLE h)
buf = (char *) alloca (fsi.EndOfFile.LowPart + 1);
status = NtReadFile (h, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
&off, NULL);
status = wait_pending (status, h, io);
if (!NT_SUCCESS (status))
{
if (status != STATUS_END_OF_FILE)
@ -1817,7 +1816,6 @@ symlink_info::check_sysfile (HANDLE h)
status = NtReadFile (h, NULL, NULL, NULL, &io, cookie_buf,
sizeof (cookie_buf), &off, NULL);
status = wait_pending (status, h, io);
if (!NT_SUCCESS (status))
{
debug_printf ("ReadFile1 failed %p", status);
@ -1851,7 +1849,6 @@ symlink_info::check_sysfile (HANDLE h)
{
status = NtReadFile (h, NULL, NULL, NULL, &io, srcbuf,
NT_MAX_PATH, &off, NULL);
status = wait_pending (status, h, io);
if (!NT_SUCCESS (status))
{
debug_printf ("ReadFile2 failed");
@ -2257,10 +2254,6 @@ restart:
PVOID eabuf = &nfs_aol_ffei;
ULONG easize = sizeof nfs_aol_ffei;
# define MIN_STAT_ACCESS (READ_CONTROL | FILE_READ_ATTRIBUTES)
# define FULL_STAT_ACCESS (SYNCHRONIZE | GENERIC_READ)
ACCESS_MASK access = 0;
bool had_ext = !!*ext_here;
while (suffix.next ())
{
@ -2278,23 +2271,14 @@ restart:
symlink (which would spoil the task of this method quite a bit).
Fortunately it's ignored on most other file systems so we don't have
to special case NFS too much. */
status = NtCreateFile (&h, access = FULL_STAT_ACCESS, &attr, &io, NULL,
0, FILE_SHARE_VALID_FLAGS, FILE_OPEN,
status = NtCreateFile (&h,
READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA,
&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 && eabuf)
{
status = NtCreateFile (&h, access = MIN_STAT_ACCESS | FILE_READ_EA,
&attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS,
FILE_OPEN,
FILE_OPEN_REPARSE_POINT
| FILE_OPEN_FOR_BACKUP_INTENT,
eabuf, easize);
debug_printf ("%p = NtCreateFile (2:%S)", status, &upath);
}
else
debug_printf ("%p = NtCreateFile (1:%S)", status, &upath);
debug_printf ("%p = NtCreateFile (%S)", status, &upath);
/* No right to access EAs or EAs not supported? */
if (!NT_SUCCESS (status)
&& (status == STATUS_ACCESS_DENIED
@ -2314,20 +2298,11 @@ restart:
eabuf = NULL;
easize = 0;
}
status = NtOpenFile (&h, access = FULL_STAT_ACCESS, &attr, &io,
FILE_SHARE_VALID_FLAGS,
status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
&attr, &io, FILE_SHARE_VALID_FLAGS,
FILE_OPEN_REPARSE_POINT
| FILE_OPEN_FOR_BACKUP_INTENT);
if (status == STATUS_ACCESS_DENIED)
{
status = NtOpenFile (&h, access = MIN_STAT_ACCESS, &attr, &io,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_REPARSE_POINT
| FILE_OPEN_FOR_BACKUP_INTENT);
debug_printf ("%p = NtOpenFile (no-EAs 2:%S)", status, &upath);
}
else
debug_printf ("%p = NtOpenFile (no-EA 1:%S)", status, &upath);
debug_printf ("%p = NtOpenFile (no-EAs %S)", status, &upath);
}
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
{
@ -2559,54 +2534,21 @@ restart:
res = -1;
/* Windows shortcuts are potentially treated as symlinks. Valid Cygwin
& U/WIN shortcuts are R/O, but definitely not directories. */
if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY))
== FILE_ATTRIBUTE_READONLY && suffix.lnk_match ())
{
if (!(access & GENERIC_READ))
res = 0;
else
res = check_shortcut (h);
if (!res)
{
/* If searching for `foo' and then finding a `foo.lnk' which is
no shortcut, return the same as if file not found. */
if (ext_tacked_on)
{
fileattr = INVALID_FILE_ATTRIBUTES;
set_error (ENOENT);
continue;
}
}
else if (contents[0] != ':' || contents[1] != '\\'
|| !parse_device (contents))
break;
}
/* If searching for `foo' and then finding a `foo.lnk' which is
no shortcut, return the same as if file not found. */
else if (suffix.lnk_match () && ext_tacked_on)
{
fileattr = INVALID_FILE_ATTRIBUTES;
set_error (ENOENT);
continue;
}
/* Reparse points are potentially symlinks. This check must be
performed before checking the SYSTEM attribute for sysfile
symlinks, since reparse points can have this flag set, too.
For instance, Vista starts to create a couple of reparse points
with SYSTEM and HIDDEN flags set.
Also don't check reparse points on remote filesystems.
A reparse point pointing to another file on the remote system will be
mistreated as pointing to a local file on the local system. This
breaks the way reparse points are transparently handled on remote
systems. */
else if ((fileattr & FILE_ATTRIBUTE_REPARSE_POINT)
&& !fs.is_remote_drive())
with SYSTEM and HIDDEN flags set. */
if ((fileattr & FILE_ATTRIBUTE_REPARSE_POINT))
{
res = check_reparse_point (h);
/* Don't check reparse points on remote filesystems. A reparse point
pointing to another file on the remote system will be mistreated
as pointing to a local file on the local system. This breaks the
way reparse points are transparently handled on remote systems. */
if (fs.is_remote_drive())
res = 0;
else
res = check_reparse_point (h);
if (res == -1)
{
/* Volume mount point. The filesystem information for the top
@ -2630,16 +2572,69 @@ restart:
}
}
/* Windows shortcuts are potentially treated as symlinks. Valid Cygwin
& U/WIN shortcuts are R/O, but definitely not directories. */
else if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY))
== FILE_ATTRIBUTE_READONLY && suffix.lnk_match ())
{
HANDLE sym_h;
status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS (status))
res = 0;
else
{
res = check_shortcut (sym_h);
NtClose (sym_h);
}
if (!res)
{
/* If searching for `foo' and then finding a `foo.lnk' which
is no shortcut, return the same as if file not found. */
if (ext_tacked_on)
{
fileattr = INVALID_FILE_ATTRIBUTES;
set_error (ENOENT);
continue;
}
}
else if (contents[0] != ':' || contents[1] != '\\'
|| !parse_device (contents))
break;
}
/* If searching for `foo' and then finding a `foo.lnk' which is
no shortcut, return the same as if file not found. */
else if (suffix.lnk_match () && ext_tacked_on)
{
fileattr = INVALID_FILE_ATTRIBUTES;
set_error (ENOENT);
continue;
}
/* This is the old Cygwin method creating symlinks. A symlink will
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))
== FILE_ATTRIBUTE_SYSTEM)
{
if (!(access & GENERIC_READ))
HANDLE sym_h;
status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS (status))
res = 0;
else
res = check_sysfile (h);
{
res = check_sysfile (sym_h);
NtClose (sym_h);
}
if (res)
break;
}
@ -2665,7 +2660,7 @@ restart:
if (h)
{
if (pflags & PC_KEEP_HANDLE)
conv_hdl.set (h, access);
conv_hdl.set (h);
else
NtClose (h);
}

View File

@ -95,7 +95,6 @@ struct _FILE_NETWORK_OPEN_INFORMATION;
class path_conv_handle
{
HANDLE hdl;
ACCESS_MASK acc;
union {
/* Identical to FILE_NETWORK_OPEN_INFORMATION. We don't want to pull in
ntdll.h here, though. */
@ -112,26 +111,22 @@ class path_conv_handle
fattr3 _fattr3;
} attribs;
public:
path_conv_handle () : hdl (NULL), acc (0) {}
inline void set (HANDLE h, ACCESS_MASK a) { hdl = h; acc = a; }
path_conv_handle () : hdl (NULL) {}
inline void set (HANDLE h) { hdl = h; }
inline void close ()
{
if (hdl)
CloseHandle (hdl);
set (NULL, 0);
set (NULL);
}
inline void dup (path_conv_handle &pch)
{
if (!DuplicateHandle (GetCurrentProcess (), pch.handle (),
GetCurrentProcess (), &hdl,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
hdl = NULL;
acc = 0;
}
hdl = NULL;
}
inline HANDLE handle () const { return hdl; }
inline ACCESS_MASK access () const { return acc; }
inline struct _FILE_NETWORK_OPEN_INFORMATION *fnoi ()
{ return (struct _FILE_NETWORK_OPEN_INFORMATION *) &attribs._fnoi; }
inline struct fattr3 *nfsattr ()
@ -325,10 +320,9 @@ class path_conv
bool is_binary ();
HANDLE handle () const { return conv_handle.handle (); }
ACCESS_MASK access () const { return conv_handle.access (); }
struct _FILE_NETWORK_OPEN_INFORMATION *fnoi () { return conv_handle.fnoi (); }
struct fattr3 *nfsattr () { return conv_handle.nfsattr (); }
void reset_conv_handle () { conv_handle.set (NULL, 0); }
void reset_conv_handle () { conv_handle.set (NULL); }
void close_conv_handle () { conv_handle.close (); }
__ino64_t get_ino_by_handle (HANDLE h);