* ntdll.h (STATUS_NO_SUCH_FILE): Define.

* path.cc (get_nt_native_path): Reset upath.Length to 0 on each
	invocation.
	(symlink_info::check): Use NT native functions.
This commit is contained in:
Corinna Vinschen 2007-08-23 07:43:24 +00:00
parent e1e4b104b6
commit a888c0799c
3 changed files with 85 additions and 32 deletions

View File

@ -1,3 +1,10 @@
2007-08-23 Corinna Vinschen <corinna@vinschen.de>
* ntdll.h (STATUS_NO_SUCH_FILE): Define.
* path.cc (get_nt_native_path): Reset upath.Length to 0 on each
invocation.
(symlink_info::check): Use NT native functions.
2007-08-21 Corinna Vinschen <corinna@vinschen.de>
* uinfo.cc (pwdgrp::load): Use NT native functions.

View File

@ -15,6 +15,7 @@
#endif
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xc0000004)
#define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xc000000d)
#define STATUS_NO_SUCH_FILE ((NTSTATUS) 0xc000000f)
#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xc0000010)
#define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xc0000013)
#define STATUS_ACCESS_DENIED ((NTSTATUS) 0xc0000022)

View File

@ -545,6 +545,7 @@ path_conv::set_normalized_path (const char *path_copy, bool strip_tail)
PUNICODE_STRING
get_nt_native_path (const char *path, UNICODE_STRING &upath)
{
upath.Length = 0;
if (path[0] == '/') /* special path w/o NT path representation. */
str2uni_cat (upath, path);
else if (path[0] != '\\') /* X:\... or NUL, etc. */
@ -3511,47 +3512,91 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
pflags &= ~(PATH_SYMLINK | PATH_LNK | PATH_REP);
case_clash = false;
/* TODO: Temporarily do all char->UNICODE conversion here. This should
already be slightly faster than using Ascii functions. */
UNICODE_STRING upath;
OBJECT_ATTRIBUTES attr;
size_t len = (strlen (path) + 8 + 8 + 1) * sizeof (WCHAR);
RtlInitEmptyUnicodeString (&upath, (PCWSTR) alloca (len), len);
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
while (suffix.next ())
{
error = 0;
fileattr = GetFileAttributes (suffix.path);
if (fileattr == INVALID_FILE_ATTRIBUTES)
{
/* The GetFileAttributes call can fail for reasons that don't
matter, so we just return 0. For example, getting the
attributes of \\HOST will typically fail. */
debug_printf ("GetFileAttributes (%s) failed", suffix.path);
FILE_BASIC_INFORMATION fbi;
NTSTATUS status;
/* The above comment is not *quite* right. When calling
GetFileAttributes for a non-existant file an a Win9x share,
GetLastError returns ERROR_INVALID_FUNCTION. Go figure!
Also, GetFileAttributes fails with ERROR_SHARING_VIOLATION
if the file is locked exclusively by another process, or with
ERROR_ACCESS_DENIED if the file exists but the user has no right
to open the file with FILE_READ_ATTRIBUTES.
If we don't special handle this here, the file is accidentally
treated as non-existant. */
DWORD win_error = GetLastError ();
if (win_error == ERROR_INVALID_FUNCTION)
win_error = ERROR_FILE_NOT_FOUND;
else if (win_error == ERROR_SHARING_VIOLATION
|| win_error == ERROR_ACCESS_DENIED)
error = 0;
get_nt_native_path (suffix.path, upath);
status = NtQueryAttributesFile (&attr, &fbi);
if (NT_SUCCESS (status))
fileattr = fbi.FileAttributes;
else
{
debug_printf ("%p = NtQueryAttributesFile (%S)", status, &upath);
fileattr = INVALID_FILE_ATTRIBUTES;
/* One of the inner path components is invalid. Bail out. */
if (status == STATUS_OBJECT_PATH_NOT_FOUND)
{
/* This is easily converted to NT functions at one point,
see fhandler_base::fstat_by_name. */
WIN32_FIND_DATA data;
HANDLE f = FindFirstFile (suffix.path, &data);
if (f != INVALID_HANDLE_VALUE)
{
FindClose (f);
fileattr = data.dwFileAttributes;
set_error (ENOENT);
break;
}
if (status != STATUS_OBJECT_NAME_NOT_FOUND
&& status != STATUS_NO_SUCH_FILE) /* File not found on 9x share */
{
/* The file exists, but the user can't access it for one reason
or the other. To get the file attributes we try to access the
information by opening the parent directory and getting the
file attributes using a matching NtQueryDirectoryFile call. */
UNICODE_STRING dirname, basename;
OBJECT_ATTRIBUTES dattr;
HANDLE dir;
IO_STATUS_BLOCK io;
FILE_DIRECTORY_INFORMATION fdi;
RtlSplitUnicodePath (&upath, &dirname, &basename);
InitializeObjectAttributes (&dattr, &dirname,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
&dattr, &io, FILE_SHARE_VALID_FLAGS,
FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
| FILE_DIRECTORY_FILE);
if (!NT_SUCCESS (status))
{
debug_printf ("%p = NtOpenFile(%S)", status, &dirname);
fileattr = 0;
}
else
fileattr = 0;
{
status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io,
&fdi, sizeof fdi,
FileDirectoryInformation,
TRUE, &basename, TRUE);
NtClose (dir);
/* Per MSDN, ZwQueryDirectoryFile allows to specify a buffer
which only fits the static parts of the structure (without
filename that is) in the first call. The buffer actually
contains valid data, even though ZwQueryDirectoryFile
returned STATUS_BUFFER_OVERFLOW.
Please note that this doesn't work for the info class
FileIdBothDirectoryInformation, unfortunately, so we don't
use this technique in fhandler_base::fstat_by_name, */
if (!NT_SUCCESS (status) && status != STATUS_BUFFER_OVERFLOW)
{
debug_printf ("%p = NtQueryDirectoryFile(%S)",
status, &dirname);
fileattr = 0;
}
else
fileattr = fdi.FileAttributes;
}
ext_tacked_on = !!*ext_here;
goto file_not_symlink;
}
if (set_error (geterrno_from_win_error (win_error, EACCES)))
if (set_error (geterrno_from_win_error
(RtlNtStatusToDosError (status), EACCES)))
continue;
}