* 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.
This commit is contained in:
parent
51ec3f5c98
commit
5a0d1edba4
|
@ -1,3 +1,57 @@
|
||||||
|
2010-06-15 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
2010-06-15 Corinna Vinschen <corinna@vinschen.de>
|
2010-06-15 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* fhandler_disk_file.cc (fhandler_disk_file::fstatvfs): Fix indentation.
|
* fhandler_disk_file.cc (fhandler_disk_file::fstatvfs): Fix indentation.
|
||||||
|
|
|
@ -582,6 +582,7 @@ dtable::dup_worker (fhandler_base *oldfh, int flags)
|
||||||
{
|
{
|
||||||
*newfh = *oldfh;
|
*newfh = *oldfh;
|
||||||
newfh->set_io_handle (NULL);
|
newfh->set_io_handle (NULL);
|
||||||
|
newfh->pc.reset_conv_handle ();
|
||||||
if (oldfh->dup (newfh))
|
if (oldfh->dup (newfh))
|
||||||
{
|
{
|
||||||
delete newfh;
|
delete newfh;
|
||||||
|
|
|
@ -1124,7 +1124,7 @@ fhandler_base::fstatvfs (struct statvfs *sfs)
|
||||||
{
|
{
|
||||||
/* If we hit this base implementation, it's some device in /dev.
|
/* If we hit this base implementation, it's some device in /dev.
|
||||||
Just call statvfs on /dev for simplicity. */
|
Just call statvfs on /dev for simplicity. */
|
||||||
path_conv pc ("/dev");
|
path_conv pc ("/dev", PC_KEEP_HANDLE);
|
||||||
fhandler_disk_file fh (pc);
|
fhandler_disk_file fh (pc);
|
||||||
return fh.fstatvfs (sfs);
|
return fh.fstatvfs (sfs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,6 +181,7 @@ class fhandler_base
|
||||||
|
|
||||||
int get_access () const { return access; }
|
int get_access () const { return access; }
|
||||||
void set_access (int x) { access = x; }
|
void set_access (int x) { access = x; }
|
||||||
|
int get_stat_access () const { return pc.handle () ? pc.access () : access; }
|
||||||
|
|
||||||
int get_flags () { return openflags; }
|
int get_flags () { return openflags; }
|
||||||
void set_flags (int x, int supplied_bin = 0);
|
void set_flags (int x, int supplied_bin = 0);
|
||||||
|
@ -355,6 +356,7 @@ class fhandler_base
|
||||||
virtual HANDLE& get_handle () { return io_handle; }
|
virtual HANDLE& get_handle () { return io_handle; }
|
||||||
virtual HANDLE& get_io_handle () { return io_handle; }
|
virtual HANDLE& get_io_handle () { return io_handle; }
|
||||||
virtual HANDLE& get_output_handle () { return io_handle; }
|
virtual HANDLE& get_output_handle () { return io_handle; }
|
||||||
|
virtual HANDLE get_stat_handle () { return pc.handle () ?: io_handle; }
|
||||||
virtual bool hit_eof () {return false;}
|
virtual bool hit_eof () {return false;}
|
||||||
virtual select_record *select_read (select_stuff *);
|
virtual select_record *select_read (select_stuff *);
|
||||||
virtual select_record *select_write (select_stuff *);
|
virtual select_record *select_write (select_stuff *);
|
||||||
|
|
|
@ -333,6 +333,7 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
|
HANDLE h = get_stat_handle ();
|
||||||
|
|
||||||
if (pc.fs_is_nfs ())
|
if (pc.fs_is_nfs ())
|
||||||
return fstat_by_nfs_ea (buf);
|
return fstat_by_nfs_ea (buf);
|
||||||
|
@ -351,22 +352,22 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
|
||||||
|
|
||||||
if (pc.has_buggy_basic_info ())
|
if (pc.has_buggy_basic_info ())
|
||||||
{
|
{
|
||||||
status = NtQueryInformationFile (get_handle (), &io, &fi, sizeof fi,
|
status = NtQueryInformationFile (h, &io, &fi, sizeof fi,
|
||||||
FileNetworkOpenInformation);
|
FileNetworkOpenInformation);
|
||||||
/* The timestamps are in the same relative memory location, only
|
/* The timestamps are in the same relative memory location, only
|
||||||
the DOS attributes have to be moved. */
|
the DOS attributes have to be moved. */
|
||||||
fi.fbi.FileAttributes = fi.fnoi.FileAttributes;
|
fi.fbi.FileAttributes = fi.fnoi.FileAttributes;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
status = NtQueryInformationFile (get_handle (), &io, &fi.fbi, sizeof fi.fbi,
|
status = NtQueryInformationFile (h, &io, &fi.fbi,
|
||||||
FileBasicInformation);
|
sizeof fi.fbi, FileBasicInformation);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
debug_printf ("%p = NtQueryInformationFile(%S, FileBasicInformation)",
|
debug_printf ("%p = NtQueryInformationFile(%S, FileBasicInformation)",
|
||||||
status, pc.get_nt_native_path ());
|
status, pc.get_nt_native_path ());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi,
|
status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi,
|
||||||
FileStandardInformation);
|
FileStandardInformation);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
|
@ -374,13 +375,17 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
|
||||||
status, pc.get_nt_native_path ());
|
status, pc.get_nt_native_path ());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
status = NtQueryInformationFile (get_handle (), &io, &fii, sizeof fii,
|
if (!ino && pc.hasgood_inode ())
|
||||||
FileInternalInformation);
|
|
||||||
if (!NT_SUCCESS (status))
|
|
||||||
{
|
{
|
||||||
debug_printf ("%p = NtQueryInformationFile(%S, FileInternalInformation)",
|
status = NtQueryInformationFile (h, &io, &fii, sizeof fii,
|
||||||
status, pc.get_nt_native_path ());
|
FileInternalInformation);
|
||||||
return -1;
|
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
|
/* If the change time is 0, it's a file system which doesn't
|
||||||
support a change timestamp. In that case use the LastWriteTime
|
support a change timestamp. In that case use the LastWriteTime
|
||||||
|
@ -397,7 +402,7 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
|
||||||
get_dev (),
|
get_dev (),
|
||||||
fsi.EndOfFile.QuadPart,
|
fsi.EndOfFile.QuadPart,
|
||||||
fsi.AllocationSize.QuadPart,
|
fsi.AllocationSize.QuadPart,
|
||||||
fii.FileId.QuadPart,
|
ino,
|
||||||
fsi.NumberOfLinks,
|
fsi.NumberOfLinks,
|
||||||
fi.fbi.FileAttributes);
|
fi.fbi.FileAttributes);
|
||||||
}
|
}
|
||||||
|
@ -492,7 +497,7 @@ fhandler_base::fstat_fs (struct __stat64 *buf)
|
||||||
int oret;
|
int oret;
|
||||||
int open_flags = O_RDONLY | O_BINARY;
|
int open_flags = O_RDONLY | O_BINARY;
|
||||||
|
|
||||||
if (get_handle ())
|
if (get_stat_handle ())
|
||||||
{
|
{
|
||||||
if (!nohandle () && !is_fs_special ())
|
if (!nohandle () && !is_fs_special ())
|
||||||
res = fstat_by_handle (buf);
|
res = fstat_by_handle (buf);
|
||||||
|
@ -500,8 +505,16 @@ fhandler_base::fstat_fs (struct __stat64 *buf)
|
||||||
res = fstat_by_name (buf);
|
res = fstat_by_name (buf);
|
||||||
return res;
|
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);
|
oret = open_fs (open_flags, 0);
|
||||||
|
if (!oret)
|
||||||
|
{
|
||||||
|
query_open (query_read_attributes);
|
||||||
|
oret = open_fs (open_flags, 0);
|
||||||
|
}
|
||||||
if (oret)
|
if (oret)
|
||||||
{
|
{
|
||||||
/* We now have a valid handle, regardless of the "nohandle" state.
|
/* 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;
|
IO_STATUS_BLOCK st;
|
||||||
FILE_COMPRESSION_INFORMATION fci;
|
FILE_COMPRESSION_INFORMATION fci;
|
||||||
|
HANDLE h = get_stat_handle ();
|
||||||
|
|
||||||
to_timestruc_t ((PFILETIME) LastAccessTime, &buf->st_atim);
|
to_timestruc_t ((PFILETIME) LastAccessTime, &buf->st_atim);
|
||||||
to_timestruc_t ((PFILETIME) LastWriteTime, &buf->st_mtim);
|
to_timestruc_t ((PFILETIME) LastWriteTime, &buf->st_mtim);
|
||||||
|
@ -563,7 +577,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Enforce namehash as inode number on untrusted file systems. */
|
/* 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;
|
buf->st_ino = (__ino64_t) nFileIndex;
|
||||||
else
|
else
|
||||||
buf->st_ino = get_ino ();
|
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;
|
buf->st_blocks = (nAllocSize + S_BLKSIZE - 1) / S_BLKSIZE;
|
||||||
else if (::has_attribute (dwFileAttributes, FILE_ATTRIBUTE_COMPRESSED
|
else if (::has_attribute (dwFileAttributes, FILE_ATTRIBUTE_COMPRESSED
|
||||||
| FILE_ATTRIBUTE_SPARSE_FILE)
|
| FILE_ATTRIBUTE_SPARSE_FILE)
|
||||||
&& get_handle () && !is_fs_special ()
|
&& h && !is_fs_special ()
|
||||||
&& !NtQueryInformationFile (get_handle (), &st, (PVOID) &fci,
|
&& !NtQueryInformationFile (h, &st, (PVOID) &fci, sizeof fci,
|
||||||
sizeof fci, FileCompressionInformation))
|
FileCompressionInformation))
|
||||||
/* Otherwise we request the actual amount of bytes allocated for
|
/* Otherwise we request the actual amount of bytes allocated for
|
||||||
compressed and sparsed files. */
|
compressed and sparsed files. */
|
||||||
buf->st_blocks = (fci.CompressedFileSize.QuadPart + S_BLKSIZE - 1)
|
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 ();
|
buf->st_size = pc.get_symlink_length ();
|
||||||
/* symlinks are everything for everyone! */
|
/* symlinks are everything for everyone! */
|
||||||
buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
|
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);
|
&buf->st_uid, &buf->st_gid);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (pc.issocket ())
|
else if (pc.issocket ())
|
||||||
buf->st_mode = S_IFSOCK;
|
buf->st_mode = S_IFSOCK;
|
||||||
|
|
||||||
if (!get_file_attribute (is_fs_special () && !pc.issocket ()
|
if (!get_file_attribute (is_fs_special () && !pc.issocket () ? NULL : h, pc,
|
||||||
? NULL : get_handle (), pc,
|
|
||||||
&buf->st_mode, &buf->st_uid, &buf->st_gid))
|
&buf->st_mode, &buf->st_uid, &buf->st_gid))
|
||||||
{
|
{
|
||||||
/* If read-only attribute is set, modify ntsec return value */
|
/* If read-only attribute is set, modify ntsec return value */
|
||||||
|
@ -659,50 +672,26 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
|
||||||
shebang scripts. */
|
shebang scripts. */
|
||||||
if (pc.exec_state () == dont_know_if_executable)
|
if (pc.exec_state () == dont_know_if_executable)
|
||||||
{
|
{
|
||||||
OBJECT_ATTRIBUTES attr;
|
LARGE_INTEGER off = { QuadPart:0LL };
|
||||||
|
char magic[3];
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
HANDLE h;
|
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
|
|
||||||
/* The NWFS implementation is frighteningly incomplete. When
|
if (get_stat_access () & (GENERIC_READ | FILE_READ_DATA))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
LARGE_INTEGER off = { QuadPart:0LL };
|
status = NtReadFile (h, NULL, NULL, NULL,
|
||||||
char magic[3];
|
&io, magic, 3, &off, NULL);
|
||||||
|
status = wait_pending (status, h, io);
|
||||||
status = NtReadFile (h, NULL, NULL, NULL, &io, magic,
|
if (!NT_SUCCESS (status))
|
||||||
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
|
|
||||||
debug_printf ("%p = NtReadFile(%S)", status,
|
debug_printf ("%p = NtReadFile(%S)", status,
|
||||||
pc.get_nt_native_path ());
|
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)
|
if (pc.exec_state () == is_executable)
|
||||||
|
@ -740,7 +729,7 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs)
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
FILE_FS_FULL_SIZE_INFORMATION full_fsi;
|
FILE_FS_FULL_SIZE_INFORMATION full_fsi;
|
||||||
FILE_FS_SIZE_INFORMATION fsi;
|
FILE_FS_SIZE_INFORMATION fsi;
|
||||||
HANDLE fh = get_handle ();
|
HANDLE fh = get_stat_handle ();
|
||||||
|
|
||||||
if (!fh)
|
if (!fh)
|
||||||
{
|
{
|
||||||
|
@ -1050,7 +1039,8 @@ cant_access_acl:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!get_handle ())
|
if ((cmd == SETACL && !get_handle ())
|
||||||
|
|| (cmd != SETACL && !get_stat_handle ()))
|
||||||
{
|
{
|
||||||
query_open (cmd == SETACL ? query_write_control : query_read_control);
|
query_open (cmd == SETACL ? query_write_control : query_read_control);
|
||||||
if (!(oret = open (O_BINARY, 0)))
|
if (!(oret = open (O_BINARY, 0)))
|
||||||
|
@ -1087,10 +1077,10 @@ cant_access_acl:
|
||||||
if (!aclbufp)
|
if (!aclbufp)
|
||||||
set_errno(EFAULT);
|
set_errno(EFAULT);
|
||||||
else
|
else
|
||||||
res = getacl (get_handle (), pc, nentries, aclbufp);
|
res = getacl (get_stat_handle (), pc, nentries, aclbufp);
|
||||||
break;
|
break;
|
||||||
case GETACLCNT:
|
case GETACLCNT:
|
||||||
res = getacl (get_handle (), pc, 0, NULL);
|
res = getacl (get_stat_handle (), pc, 0, NULL);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
set_errno (EINVAL);
|
set_errno (EINVAL);
|
||||||
|
@ -1277,17 +1267,13 @@ fhandler_disk_file::link (const char *newpath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE fh;
|
/* We only need READ_CONTROL access so the handle returned in pc is
|
||||||
NTSTATUS status;
|
sufficient. And if the file couldn't be opened with READ_CONTROL
|
||||||
OBJECT_ATTRIBUTES attr;
|
access in path_conv, we won't be able to do it here anyway. */
|
||||||
IO_STATUS_BLOCK io;
|
HANDLE fh = get_stat_handle ();
|
||||||
status = NtOpenFile (&fh, READ_CONTROL,
|
if (!fh)
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
__seterrno_from_nt_status (status);
|
set_errno (EACCES);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
PUNICODE_STRING tgt = newpc.get_nt_native_path ();
|
PUNICODE_STRING tgt = newpc.get_nt_native_path ();
|
||||||
|
@ -1296,8 +1282,10 @@ fhandler_disk_file::link (const char *newpath)
|
||||||
pfli->ReplaceIfExists = FALSE;
|
pfli->ReplaceIfExists = FALSE;
|
||||||
pfli->RootDirectory = NULL;
|
pfli->RootDirectory = NULL;
|
||||||
memcpy (pfli->FileName, tgt->Buffer, pfli->FileNameLength = tgt->Length);
|
memcpy (pfli->FileName, tgt->Buffer, pfli->FileNameLength = tgt->Length);
|
||||||
|
|
||||||
|
NTSTATUS status;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
status = NtSetInformationFile (fh, &io, pfli, size, FileLinkInformation);
|
status = NtSetInformationFile (fh, &io, pfli, size, FileLinkInformation);
|
||||||
NtClose (fh);
|
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
if (status == STATUS_INVALID_DEVICE_REQUEST)
|
if (status == STATUS_INVALID_DEVICE_REQUEST)
|
||||||
|
@ -1764,8 +1752,6 @@ readdir_get_ino (const char *path, bool dot_dot)
|
||||||
char *fname;
|
char *fname;
|
||||||
struct __stat64 st;
|
struct __stat64 st;
|
||||||
HANDLE hdl;
|
HANDLE hdl;
|
||||||
OBJECT_ATTRIBUTES attr;
|
|
||||||
IO_STATUS_BLOCK io;
|
|
||||||
__ino64_t ino = 0;
|
__ino64_t ino = 0;
|
||||||
|
|
||||||
if (dot_dot)
|
if (dot_dot)
|
||||||
|
@ -1777,7 +1763,7 @@ readdir_get_ino (const char *path, bool dot_dot)
|
||||||
strcpy (c, "..");
|
strcpy (c, "..");
|
||||||
path = fname;
|
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 (pc.isspecial ())
|
||||||
{
|
{
|
||||||
if (!stat_worker (pc, &st))
|
if (!stat_worker (pc, &st))
|
||||||
|
@ -1785,17 +1771,11 @@ readdir_get_ino (const char *path, bool dot_dot)
|
||||||
}
|
}
|
||||||
else if (!pc.hasgood_inode ())
|
else if (!pc.hasgood_inode ())
|
||||||
ino = hash_path_name (0, pc.get_nt_native_path ());
|
ino = hash_path_name (0, pc.get_nt_native_path ());
|
||||||
else if (NT_SUCCESS (NtOpenFile (&hdl, READ_CONTROL,
|
else if ((hdl = pc.handle ()) != NULL)
|
||||||
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))))
|
|
||||||
{
|
{
|
||||||
ino = pc.get_ino_by_handle (hdl);
|
ino = pc.get_ino_by_handle (hdl);
|
||||||
if (!ino)
|
if (!ino)
|
||||||
ino = hash_path_name (0, pc.get_nt_native_path ());
|
ino = hash_path_name (0, pc.get_nt_native_path ());
|
||||||
NtClose (hdl);
|
|
||||||
}
|
}
|
||||||
return ino;
|
return ino;
|
||||||
}
|
}
|
||||||
|
|
|
@ -868,6 +868,16 @@ typedef enum _EVENT_INFORMATION_CLASS
|
||||||
#define NtCurrentProcess() ((HANDLE) 0xffffffff)
|
#define NtCurrentProcess() ((HANDLE) 0xffffffff)
|
||||||
#define NtCurrentThread() ((HANDLE) 0xfffffffe)
|
#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"
|
extern "C"
|
||||||
{
|
{
|
||||||
NTSTATUS NTAPI NtAdjustPrivilegesToken (HANDLE, BOOLEAN, PTOKEN_PRIVILEGES,
|
NTSTATUS NTAPI NtAdjustPrivilegesToken (HANDLE, BOOLEAN, PTOKEN_PRIVILEGES,
|
||||||
|
|
|
@ -96,8 +96,8 @@ struct symlink_info
|
||||||
_major_t major;
|
_major_t major;
|
||||||
_minor_t minor;
|
_minor_t minor;
|
||||||
_mode_t mode;
|
_mode_t mode;
|
||||||
int check (char *path, const suffix_info *suffixes, unsigned opt,
|
int check (char *path, const suffix_info *suffixes, fs_info &fs,
|
||||||
fs_info &fs);
|
path_conv_handle &conv_hdl);
|
||||||
int set (char *path);
|
int set (char *path);
|
||||||
bool parse_device (const char *);
|
bool parse_device (const char *);
|
||||||
int check_sysfile (HANDLE h);
|
int check_sysfile (HANDLE h);
|
||||||
|
@ -639,6 +639,7 @@ path_conv::check (const char *src, unsigned opt,
|
||||||
cfree (modifiable_path ());
|
cfree (modifiable_path ());
|
||||||
path = NULL;
|
path = NULL;
|
||||||
}
|
}
|
||||||
|
close_conv_handle ();
|
||||||
memset (&dev, 0, sizeof (dev));
|
memset (&dev, 0, sizeof (dev));
|
||||||
fs.clear ();
|
fs.clear ();
|
||||||
if (normalized_path)
|
if (normalized_path)
|
||||||
|
@ -695,7 +696,9 @@ path_conv::check (const char *src, unsigned opt,
|
||||||
|
|
||||||
int symlen = 0;
|
int symlen = 0;
|
||||||
|
|
||||||
for (unsigned pflags_or = opt & PC_NO_ACCESS_CHECK; ; pflags_or = 0)
|
for (unsigned pflags_or = opt & (PC_NO_ACCESS_CHECK | PC_KEEP_HANDLE);
|
||||||
|
;
|
||||||
|
pflags_or = 0)
|
||||||
{
|
{
|
||||||
const suffix_info *suff;
|
const suffix_info *suff;
|
||||||
char *full_path;
|
char *full_path;
|
||||||
|
@ -823,7 +826,7 @@ path_conv::check (const char *src, unsigned opt,
|
||||||
if (is_msdos)
|
if (is_msdos)
|
||||||
sym.pflags |= PATH_NOPOSIX | PATH_NOACL;
|
sym.pflags |= PATH_NOPOSIX | PATH_NOACL;
|
||||||
|
|
||||||
symlen = sym.check (full_path, suff, opt, fs);
|
symlen = sym.check (full_path, suff, fs, conv_handle);
|
||||||
|
|
||||||
is_virtual_symlink:
|
is_virtual_symlink:
|
||||||
|
|
||||||
|
@ -1124,6 +1127,7 @@ path_conv::~path_conv ()
|
||||||
cfree (wide_path);
|
cfree (wide_path);
|
||||||
wide_path = NULL;
|
wide_path = NULL;
|
||||||
}
|
}
|
||||||
|
close_conv_handle ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1683,55 +1687,50 @@ cmp_shortcut_header (win_shortcut_hdr *file_header)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
symlink_info::check_shortcut (HANDLE in_h)
|
symlink_info::check_shortcut (HANDLE h)
|
||||||
{
|
{
|
||||||
tmp_pathbuf tp;
|
tmp_pathbuf tp;
|
||||||
win_shortcut_hdr *file_header;
|
win_shortcut_hdr *file_header;
|
||||||
char *buf, *cp;
|
char *buf, *cp;
|
||||||
unsigned short len;
|
unsigned short len;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
OBJECT_ATTRIBUTES attr;
|
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
HANDLE h;
|
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
FILE_STANDARD_INFORMATION fsi;
|
FILE_STANDARD_INFORMATION fsi;
|
||||||
|
LARGE_INTEGER off = { QuadPart:0LL };
|
||||||
|
|
||||||
InitializeObjectAttributes (&attr, &ro_u_empty, 0, in_h, NULL);
|
|
||||||
status = NtOpenFile (&h, FILE_READ_DATA | SYNCHRONIZE,
|
|
||||||
&attr, &io, FILE_SHARE_VALID_FLAGS,
|
|
||||||
FILE_OPEN_FOR_BACKUP_INTENT
|
|
||||||
| FILE_SYNCHRONOUS_IO_NONALERT);
|
|
||||||
if (!NT_SUCCESS (status))
|
|
||||||
return 0;
|
|
||||||
status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi,
|
status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi,
|
||||||
FileStandardInformation);
|
FileStandardInformation);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
set_error (EIO);
|
set_error (EIO);
|
||||||
goto out;
|
return 0;
|
||||||
}
|
}
|
||||||
if (fsi.EndOfFile.QuadPart <= sizeof (win_shortcut_hdr)
|
if (fsi.EndOfFile.QuadPart <= sizeof (win_shortcut_hdr)
|
||||||
|| fsi.EndOfFile.QuadPart > 4 * 65536)
|
|| fsi.EndOfFile.QuadPart > 4 * 65536)
|
||||||
goto out;
|
return 0;
|
||||||
if (fsi.EndOfFile.LowPart < NT_MAX_PATH * sizeof (WCHAR))
|
if (fsi.EndOfFile.LowPart < NT_MAX_PATH * sizeof (WCHAR))
|
||||||
buf = (char *) tp.w_get ();
|
buf = (char *) tp.w_get ();
|
||||||
else
|
else
|
||||||
buf = (char *) alloca (fsi.EndOfFile.LowPart + 1);
|
buf = (char *) alloca (fsi.EndOfFile.LowPart + 1);
|
||||||
if (!NT_SUCCESS (NtReadFile (h, NULL, NULL, NULL,
|
status = NtReadFile (h, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
|
||||||
&io, buf, fsi.EndOfFile.LowPart, NULL, NULL)))
|
&off, NULL);
|
||||||
|
status = wait_pending (status, h, io);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
set_error (EIO);
|
if (status != STATUS_END_OF_FILE)
|
||||||
goto out;
|
set_error (EIO);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
file_header = (win_shortcut_hdr *) buf;
|
file_header = (win_shortcut_hdr *) buf;
|
||||||
if (io.Information != fsi.EndOfFile.LowPart
|
if (io.Information != fsi.EndOfFile.LowPart
|
||||||
|| !cmp_shortcut_header (file_header))
|
|| !cmp_shortcut_header (file_header))
|
||||||
goto out;
|
return 0;
|
||||||
cp = buf + sizeof (win_shortcut_hdr);
|
cp = buf + sizeof (win_shortcut_hdr);
|
||||||
if (file_header->flags & WSH_FLAG_IDLIST) /* Skip ITEMIDLIST */
|
if (file_header->flags & WSH_FLAG_IDLIST) /* Skip ITEMIDLIST */
|
||||||
cp += *(unsigned short *) cp + 2;
|
cp += *(unsigned short *) cp + 2;
|
||||||
if (!(len = *(unsigned short *) cp))
|
if (!(len = *(unsigned short *) cp))
|
||||||
goto out;
|
return 0;
|
||||||
cp += 2;
|
cp += 2;
|
||||||
/* Check if this is a device file - these start with the sequence :\\ */
|
/* Check if this is a device file - these start with the sequence :\\ */
|
||||||
if (strncmp (cp, ":\\", 2) == 0)
|
if (strncmp (cp, ":\\", 2) == 0)
|
||||||
|
@ -1751,11 +1750,11 @@ symlink_info::check_shortcut (HANDLE in_h)
|
||||||
char *tmpbuf = tp.c_get ();
|
char *tmpbuf = tp.c_get ();
|
||||||
if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) (cp + 2))
|
if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) (cp + 2))
|
||||||
> SYMLINK_MAX + 1)
|
> SYMLINK_MAX + 1)
|
||||||
goto out;
|
return 0;
|
||||||
res = posixify (tmpbuf);
|
res = posixify (tmpbuf);
|
||||||
}
|
}
|
||||||
else if (len > SYMLINK_MAX)
|
else if (len > SYMLINK_MAX)
|
||||||
goto out;
|
return 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cp[len] = '\0';
|
cp[len] = '\0';
|
||||||
|
@ -1764,41 +1763,33 @@ symlink_info::check_shortcut (HANDLE in_h)
|
||||||
}
|
}
|
||||||
if (res) /* It's a symlink. */
|
if (res) /* It's a symlink. */
|
||||||
pflags |= PATH_SYMLINK | PATH_LNK;
|
pflags |= PATH_SYMLINK | PATH_LNK;
|
||||||
|
|
||||||
out:
|
|
||||||
NtClose (h);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
symlink_info::check_sysfile (HANDLE in_h)
|
symlink_info::check_sysfile (HANDLE h)
|
||||||
{
|
{
|
||||||
tmp_pathbuf tp;
|
tmp_pathbuf tp;
|
||||||
char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
|
char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
|
||||||
char *srcbuf = tp.c_get ();
|
char *srcbuf = tp.c_get ();
|
||||||
int res = 0;
|
int res = 0;
|
||||||
OBJECT_ATTRIBUTES attr;
|
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
HANDLE h;
|
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
bool interix_symlink = false;
|
bool interix_symlink = false;
|
||||||
|
LARGE_INTEGER off = { QuadPart:0LL };
|
||||||
|
|
||||||
InitializeObjectAttributes (&attr, &ro_u_empty, 0, in_h, NULL);
|
status = NtReadFile (h, NULL, NULL, NULL, &io, cookie_buf,
|
||||||
status = NtOpenFile (&h, FILE_READ_DATA | SYNCHRONIZE,
|
sizeof (cookie_buf), &off, NULL);
|
||||||
&attr, &io, FILE_SHARE_VALID_FLAGS,
|
status = wait_pending (status, h, io);
|
||||||
FILE_OPEN_FOR_BACKUP_INTENT
|
|
||||||
| FILE_SYNCHRONOUS_IO_NONALERT);
|
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
return 0;
|
|
||||||
else if (!NT_SUCCESS (status = NtReadFile (h, NULL, NULL, NULL, &io,
|
|
||||||
cookie_buf, sizeof (cookie_buf),
|
|
||||||
NULL, NULL)))
|
|
||||||
{
|
{
|
||||||
debug_printf ("ReadFile1 failed %p", status);
|
debug_printf ("ReadFile1 failed %p", status);
|
||||||
if (status != STATUS_END_OF_FILE)
|
if (status != STATUS_END_OF_FILE)
|
||||||
set_error (EIO);
|
set_error (EIO);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
else if (io.Information == sizeof (cookie_buf)
|
off.QuadPart = io.Information;
|
||||||
|
if (io.Information == sizeof (cookie_buf)
|
||||||
&& memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
|
&& memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
|
||||||
{
|
{
|
||||||
/* It's a symlink. */
|
/* It's a symlink. */
|
||||||
|
@ -1817,14 +1808,13 @@ symlink_info::check_sysfile (HANDLE in_h)
|
||||||
/* Interix symlink cookies are shorter than Cygwin symlink cookies, so
|
/* Interix symlink cookies are shorter than Cygwin symlink cookies, so
|
||||||
in case of an Interix symlink cooky we have read too far into the
|
in case of an Interix symlink cooky we have read too far into the
|
||||||
file. Set file pointer back to the position right after the cookie. */
|
file. Set file pointer back to the position right after the cookie. */
|
||||||
FILE_POSITION_INFORMATION fpi;
|
off.QuadPart = sizeof (INTERIX_SYMLINK_COOKIE) - 1;
|
||||||
fpi.CurrentByteOffset.QuadPart = sizeof (INTERIX_SYMLINK_COOKIE) - 1;
|
|
||||||
NtSetInformationFile (h, &io, &fpi, sizeof fpi, FilePositionInformation);
|
|
||||||
}
|
}
|
||||||
if (pflags & PATH_SYMLINK)
|
if (pflags & PATH_SYMLINK)
|
||||||
{
|
{
|
||||||
status = NtReadFile (h, NULL, NULL, NULL, &io, srcbuf,
|
status = NtReadFile (h, NULL, NULL, NULL, &io, srcbuf,
|
||||||
NT_MAX_PATH, NULL, NULL);
|
NT_MAX_PATH, &off, NULL);
|
||||||
|
status = wait_pending (status, h, io);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
debug_printf ("ReadFile2 failed");
|
debug_printf ("ReadFile2 failed");
|
||||||
|
@ -1852,7 +1842,6 @@ symlink_info::check_sysfile (HANDLE in_h)
|
||||||
else
|
else
|
||||||
res = posixify (srcbuf);
|
res = posixify (srcbuf);
|
||||||
}
|
}
|
||||||
NtClose (h);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1916,7 +1905,6 @@ symlink_info::check_nfs_symlink (HANDLE h)
|
||||||
{
|
{
|
||||||
tmp_pathbuf tp;
|
tmp_pathbuf tp;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
OBJECT_ATTRIBUTES attr;
|
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
struct {
|
struct {
|
||||||
FILE_GET_EA_INFORMATION fgei;
|
FILE_GET_EA_INFORMATION fgei;
|
||||||
|
@ -1925,11 +1913,6 @@ symlink_info::check_nfs_symlink (HANDLE h)
|
||||||
PFILE_FULL_EA_INFORMATION pffei;
|
PFILE_FULL_EA_INFORMATION pffei;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
InitializeObjectAttributes (&attr, &ro_u_empty, 0, h, NULL);
|
|
||||||
status = NtOpenFile (&h, FILE_READ_EA, &attr, &io, FILE_SHARE_VALID_FLAGS,
|
|
||||||
FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT);
|
|
||||||
if (!NT_SUCCESS (status))
|
|
||||||
return 0;
|
|
||||||
/* To find out if the file is a symlink and to get the symlink target,
|
/* To find out if the file is a symlink and to get the symlink target,
|
||||||
try to fetch the NfsSymlinkTargetName EA. */
|
try to fetch the NfsSymlinkTargetName EA. */
|
||||||
fgei_buf.fgei.NextEntryOffset = 0;
|
fgei_buf.fgei.NextEntryOffset = 0;
|
||||||
|
@ -1938,13 +1921,12 @@ symlink_info::check_nfs_symlink (HANDLE h)
|
||||||
pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
|
pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
|
||||||
status = NtQueryEaFile (h, &io, pffei, NT_MAX_PATH * sizeof (WCHAR), TRUE,
|
status = NtQueryEaFile (h, &io, pffei, NT_MAX_PATH * sizeof (WCHAR), TRUE,
|
||||||
&fgei_buf.fgei, sizeof fgei_buf, NULL, TRUE);
|
&fgei_buf.fgei, sizeof fgei_buf, NULL, TRUE);
|
||||||
NtClose (h);
|
|
||||||
if (NT_SUCCESS (status) && pffei->EaValueLength > 0)
|
if (NT_SUCCESS (status) && pffei->EaValueLength > 0)
|
||||||
{
|
{
|
||||||
PWCHAR spath = (PWCHAR)
|
PWCHAR spath = (PWCHAR)
|
||||||
(pffei->EaName + pffei->EaNameLength + 1);
|
(pffei->EaName + pffei->EaNameLength + 1);
|
||||||
res = sys_wcstombs (contents, SYMLINK_MAX + 1,
|
res = sys_wcstombs (contents, SYMLINK_MAX + 1,
|
||||||
spath, pffei->EaValueLength);
|
spath, pffei->EaValueLength) - 1;
|
||||||
pflags |= PATH_SYMLINK;
|
pflags |= PATH_SYMLINK;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -2197,8 +2179,8 @@ symlink_info::parse_device (const char *contents)
|
||||||
stored into BUF if PATH is a symlink. */
|
stored into BUF if PATH is a symlink. */
|
||||||
|
|
||||||
int
|
int
|
||||||
symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt,
|
symlink_info::check (char *path, const suffix_info *suffixes, fs_info &fs,
|
||||||
fs_info &fs)
|
path_conv_handle &conv_hdl)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
|
@ -2238,6 +2220,10 @@ restart:
|
||||||
PVOID eabuf = &nfs_aol_ffei;
|
PVOID eabuf = &nfs_aol_ffei;
|
||||||
ULONG easize = sizeof 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;
|
bool had_ext = !!*ext_here;
|
||||||
while (suffix.next ())
|
while (suffix.next ())
|
||||||
{
|
{
|
||||||
|
@ -2255,14 +2241,22 @@ restart:
|
||||||
symlink (which would spoil the task of this method quite a bit).
|
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
|
Fortunately it's ignored on most other file systems so we don't have
|
||||||
to special case NFS too much. */
|
to special case NFS too much. */
|
||||||
status = NtCreateFile (&h,
|
status = NtCreateFile (&h, access = FULL_STAT_ACCESS, &attr, &io, NULL,
|
||||||
READ_CONTROL | FILE_READ_ATTRIBUTES,
|
0, FILE_SHARE_VALID_FLAGS, FILE_OPEN,
|
||||||
&attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS,
|
|
||||||
FILE_OPEN,
|
|
||||||
FILE_OPEN_REPARSE_POINT
|
FILE_OPEN_REPARSE_POINT
|
||||||
| FILE_OPEN_FOR_BACKUP_INTENT,
|
| FILE_OPEN_FOR_BACKUP_INTENT,
|
||||||
eabuf, easize);
|
eabuf, easize);
|
||||||
debug_printf ("%p = NtCreateFile (%S)", status, &upath);
|
if (status == STATUS_ACCESS_DENIED)
|
||||||
|
{
|
||||||
|
status = NtCreateFile (&h, access = MIN_STAT_ACCESS, &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);
|
||||||
/* No right to access EAs or EAs not supported? */
|
/* No right to access EAs or EAs not supported? */
|
||||||
if (!NT_SUCCESS (status)
|
if (!NT_SUCCESS (status)
|
||||||
&& (status == STATUS_ACCESS_DENIED
|
&& (status == STATUS_ACCESS_DENIED
|
||||||
|
@ -2282,11 +2276,20 @@ restart:
|
||||||
eabuf = NULL;
|
eabuf = NULL;
|
||||||
easize = 0;
|
easize = 0;
|
||||||
}
|
}
|
||||||
status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
|
status = NtOpenFile (&h, access = FULL_STAT_ACCESS, &attr, &io,
|
||||||
&attr, &io, FILE_SHARE_VALID_FLAGS,
|
FILE_SHARE_VALID_FLAGS,
|
||||||
FILE_OPEN_REPARSE_POINT
|
FILE_OPEN_REPARSE_POINT
|
||||||
| FILE_OPEN_FOR_BACKUP_INTENT);
|
| FILE_OPEN_FOR_BACKUP_INTENT);
|
||||||
debug_printf ("%p = NtOpenFile (no-EA, %S)", status, &upath);
|
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);
|
||||||
}
|
}
|
||||||
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
|
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
|
||||||
{
|
{
|
||||||
|
@ -2478,7 +2481,10 @@ restart:
|
||||||
if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY))
|
if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY))
|
||||||
== FILE_ATTRIBUTE_READONLY && suffix.lnk_match ())
|
== FILE_ATTRIBUTE_READONLY && suffix.lnk_match ())
|
||||||
{
|
{
|
||||||
res = check_shortcut (h);
|
if (!(access & GENERIC_READ))
|
||||||
|
res = 0;
|
||||||
|
else
|
||||||
|
res = check_shortcut (h);
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
/* If searching for `foo' and then finding a `foo.lnk' which is
|
/* If searching for `foo' and then finding a `foo.lnk' which is
|
||||||
|
@ -2538,17 +2544,23 @@ restart:
|
||||||
else if ((fileattr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY))
|
else if ((fileattr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY))
|
||||||
== FILE_ATTRIBUTE_SYSTEM)
|
== FILE_ATTRIBUTE_SYSTEM)
|
||||||
{
|
{
|
||||||
res = check_sysfile (h);
|
if (!(access & GENERIC_READ))
|
||||||
|
res = 0;
|
||||||
|
else
|
||||||
|
res = check_sysfile (h);
|
||||||
if (res)
|
if (res)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the file could be opened with FILE_READ_EA, and if it's on a
|
/* If the file is on an NFS share and could be opened with extended
|
||||||
NFS share, check if it's a symlink. Only files can be symlinks
|
attributes, check if it's a symlink. Only files can be symlinks
|
||||||
(which can be symlinks to directories). */
|
(which can be symlinks to directories). */
|
||||||
else if (fs.is_nfs () && !no_ea && !(fileattr & FILE_ATTRIBUTE_DIRECTORY))
|
else if (fs.is_nfs () && !no_ea && !(fileattr & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
{
|
{
|
||||||
res = check_nfs_symlink (h);
|
if (!(access & GENERIC_READ))
|
||||||
|
res = 0;
|
||||||
|
else
|
||||||
|
res = check_nfs_symlink (h);
|
||||||
if (res)
|
if (res)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2562,7 +2574,12 @@ restart:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h)
|
if (h)
|
||||||
NtClose (h);
|
{
|
||||||
|
if (pflags & PC_KEEP_HANDLE)
|
||||||
|
conv_hdl.set (h, access);
|
||||||
|
else
|
||||||
|
NtClose (h);
|
||||||
|
}
|
||||||
|
|
||||||
syscall_printf ("%d = symlink.check (%s, %p) (%p)",
|
syscall_printf ("%d = symlink.check (%s, %p) (%p)",
|
||||||
res, suffix.path, contents, pflags);
|
res, suffix.path, contents, pflags);
|
||||||
|
|
|
@ -57,6 +57,7 @@ enum pathconv_arg
|
||||||
PC_CHECK_EA = 0x0040,
|
PC_CHECK_EA = 0x0040,
|
||||||
PC_POSIX = 0x0080,
|
PC_POSIX = 0x0080,
|
||||||
PC_NOWARN = 0x0100,
|
PC_NOWARN = 0x0100,
|
||||||
|
PC_KEEP_HANDLE = 0x00400000,
|
||||||
PC_NO_ACCESS_CHECK = 0x00800000
|
PC_NO_ACCESS_CHECK = 0x00800000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,6 +87,33 @@ enum path_types
|
||||||
PATH_SOCKET = 0x40000000
|
PATH_SOCKET = 0x40000000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class path_conv_handle
|
||||||
|
{
|
||||||
|
HANDLE hdl;
|
||||||
|
ACCESS_MASK acc;
|
||||||
|
public:
|
||||||
|
path_conv_handle () : hdl (NULL), acc (0) {}
|
||||||
|
inline void set (HANDLE h, ACCESS_MASK a) { hdl = h; acc = a; }
|
||||||
|
inline void close ()
|
||||||
|
{
|
||||||
|
if (hdl)
|
||||||
|
CloseHandle (hdl);
|
||||||
|
set (NULL, 0);
|
||||||
|
}
|
||||||
|
inline void dup (path_conv_handle &pch)
|
||||||
|
{
|
||||||
|
if (!DuplicateHandle (GetCurrentProcess (), pch.handle (),
|
||||||
|
GetCurrentProcess (), &hdl,
|
||||||
|
0, TRUE, DUPLICATE_SAME_ACCESS))
|
||||||
|
{
|
||||||
|
hdl = NULL;
|
||||||
|
acc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline HANDLE handle () const { return hdl; }
|
||||||
|
inline ACCESS_MASK access () const { return acc; }
|
||||||
|
};
|
||||||
|
|
||||||
class symlink_info;
|
class symlink_info;
|
||||||
|
|
||||||
class path_conv
|
class path_conv
|
||||||
|
@ -98,6 +126,7 @@ class path_conv
|
||||||
void add_ext_from_sym (symlink_info&);
|
void add_ext_from_sym (symlink_info&);
|
||||||
DWORD symlink_length;
|
DWORD symlink_length;
|
||||||
const char *path;
|
const char *path;
|
||||||
|
path_conv_handle conv_handle;
|
||||||
public:
|
public:
|
||||||
unsigned path_flags;
|
unsigned path_flags;
|
||||||
const char *known_suffix;
|
const char *known_suffix;
|
||||||
|
@ -220,6 +249,7 @@ class path_conv
|
||||||
{
|
{
|
||||||
memcpy (this, &pc, sizeof pc);
|
memcpy (this, &pc, sizeof pc);
|
||||||
path = cstrdup (pc.path);
|
path = cstrdup (pc.path);
|
||||||
|
conv_handle.dup (pc.conv_handle);
|
||||||
normalized_path = cstrdup(pc.normalized_path);
|
normalized_path = cstrdup(pc.normalized_path);
|
||||||
wide_path = NULL;
|
wide_path = NULL;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -250,6 +280,11 @@ class path_conv
|
||||||
}
|
}
|
||||||
bool is_binary ();
|
bool is_binary ();
|
||||||
|
|
||||||
|
HANDLE handle () const { return conv_handle.handle (); }
|
||||||
|
ACCESS_MASK access () const { return conv_handle.access (); }
|
||||||
|
void reset_conv_handle () { conv_handle.set (NULL, 0); }
|
||||||
|
void close_conv_handle () { conv_handle.close (); }
|
||||||
|
|
||||||
__ino64_t get_ino_by_handle (HANDLE h);
|
__ino64_t get_ino_by_handle (HANDLE h);
|
||||||
#if 0 /* obsolete, method still exists in fhandler_disk_file.cc */
|
#if 0 /* obsolete, method still exists in fhandler_disk_file.cc */
|
||||||
unsigned __stdcall ndisk_links (DWORD);
|
unsigned __stdcall ndisk_links (DWORD);
|
||||||
|
|
|
@ -419,7 +419,8 @@ acl_worker (const char *path, int cmd, int nentries, __aclent32_t *aclbufp,
|
||||||
unsigned fmode)
|
unsigned fmode)
|
||||||
{
|
{
|
||||||
int res = -1;
|
int res = -1;
|
||||||
fhandler_base *fh = build_fh_name (path, fmode, stat_suffixes);
|
fhandler_base *fh = build_fh_name (path, fmode | PC_KEEP_HANDLE,
|
||||||
|
stat_suffixes);
|
||||||
if (fh->error ())
|
if (fh->error ())
|
||||||
{
|
{
|
||||||
debug_printf ("got %d error from build_fh_name", fh->error ());
|
debug_printf ("got %d error from build_fh_name", fh->error ());
|
||||||
|
|
|
@ -1169,7 +1169,8 @@ link (const char *oldpath, const char *newpath)
|
||||||
int res = -1;
|
int res = -1;
|
||||||
fhandler_base *fh;
|
fhandler_base *fh;
|
||||||
|
|
||||||
if (!(fh = build_fh_name (oldpath, PC_SYM_NOFOLLOW, stat_suffixes)))
|
if (!(fh = build_fh_name (oldpath, PC_SYM_NOFOLLOW | PC_KEEP_HANDLE,
|
||||||
|
stat_suffixes)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (fh->error ())
|
if (fh->error ())
|
||||||
|
@ -1542,7 +1543,7 @@ extern "C" int
|
||||||
stat64 (const char *name, struct __stat64 *buf)
|
stat64 (const char *name, struct __stat64 *buf)
|
||||||
{
|
{
|
||||||
syscall_printf ("entering");
|
syscall_printf ("entering");
|
||||||
path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
|
path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX | PC_KEEP_HANDLE, stat_suffixes);
|
||||||
return stat_worker (pc, buf);
|
return stat_worker (pc, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1581,7 +1582,8 @@ extern "C" int
|
||||||
lstat64 (const char *name, struct __stat64 *buf)
|
lstat64 (const char *name, struct __stat64 *buf)
|
||||||
{
|
{
|
||||||
syscall_printf ("entering");
|
syscall_printf ("entering");
|
||||||
path_conv pc (name, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
|
path_conv pc (name, PC_SYM_NOFOLLOW | PC_POSIX | PC_KEEP_HANDLE,
|
||||||
|
stat_suffixes);
|
||||||
return stat_worker (pc, buf);
|
return stat_worker (pc, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2561,7 +2563,8 @@ statvfs (const char *name, struct statvfs *sfs)
|
||||||
if (efault.faulted (EFAULT))
|
if (efault.faulted (EFAULT))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!(fh = build_fh_name (name, PC_SYM_FOLLOW, stat_suffixes)))
|
if (!(fh = build_fh_name (name, PC_SYM_FOLLOW | PC_KEEP_HANDLE,
|
||||||
|
stat_suffixes)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (fh->error ())
|
if (fh->error ())
|
||||||
|
|
Loading…
Reference in New Issue