Alexandre Julliard : ntdll: Add support for converting file names to Unix when a root directory is specified .
Alexandre Julliard
julliard at winehq.org
Wed Dec 2 10:22:10 CST 2009
Module: wine
Branch: master
Commit: d97149b708ae2df3e0428340103e910513b77103
URL: http://source.winehq.org/git/wine.git/?a=commit;h=d97149b708ae2df3e0428340103e910513b77103
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue Dec 1 17:07:55 2009 +0100
ntdll: Add support for converting file names to Unix when a root directory is specified.
---
dlls/ntdll/directory.c | 89 +++++++++++++++++++++++++++++++++++++++++++---
dlls/ntdll/file.c | 12 ++----
dlls/ntdll/ntdll_misc.h | 2 +
3 files changed, 89 insertions(+), 14 deletions(-)
diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index 7833809..8af2d00 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -2236,17 +2236,20 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
name_len--;
}
- if (ret > 0 && !used_default) /* if we used the default char the name didn't convert properly */
+ if (ret >= 0 && !used_default) /* if we used the default char the name didn't convert properly */
{
char *p;
unix_name[pos + ret] = 0;
for (p = unix_name + pos ; *p; p++) if (*p == '\\') *p = '/';
- if ((!redirect || !strstr( unix_name, "/windows/")) && !stat( unix_name, &st ))
+ if (!redirect || (!strstr( unix_name, "/windows/") && strncmp( unix_name, "windows/", 8 )))
{
- /* creation fails with STATUS_ACCESS_DENIED for the root of the drive */
- if (disposition == FILE_CREATE)
- return name_len ? STATUS_OBJECT_NAME_COLLISION : STATUS_ACCESS_DENIED;
- return STATUS_SUCCESS;
+ if (!stat( unix_name, &st ))
+ {
+ /* creation fails with STATUS_ACCESS_DENIED for the root of the drive */
+ if (disposition == FILE_CREATE)
+ return name_len ? STATUS_OBJECT_NAME_COLLISION : STATUS_ACCESS_DENIED;
+ return STATUS_SUCCESS;
+ }
}
}
@@ -2326,6 +2329,80 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
/******************************************************************************
+ * nt_to_unix_file_name_attr
+ */
+NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, ANSI_STRING *unix_name_ret,
+ UINT disposition )
+{
+ static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 };
+ enum server_fd_type type;
+ int old_cwd, root_fd, needs_close;
+ const WCHAR *name, *p;
+ char *unix_name;
+ int name_len, unix_len;
+ NTSTATUS status;
+ BOOLEAN check_case = !(attr->Attributes & OBJ_CASE_INSENSITIVE);
+
+ if (!attr->RootDirectory) /* without root dir fall back to normal lookup */
+ return wine_nt_to_unix_file_name( attr->ObjectName, unix_name_ret, disposition, check_case );
+
+ name = attr->ObjectName->Buffer;
+ name_len = attr->ObjectName->Length / sizeof(WCHAR);
+
+ if (name_len && IS_SEPARATOR(name[0])) return STATUS_OBJECT_PATH_SYNTAX_BAD;
+
+ /* check for invalid characters */
+ for (p = name; p < name + name_len; p++)
+ if (*p < 32 || strchrW( invalid_charsW, *p )) return STATUS_OBJECT_NAME_INVALID;
+
+ unix_len = ntdll_wcstoumbs( 0, name, name_len, NULL, 0, NULL, NULL );
+ unix_len += MAX_DIR_ENTRY_LEN + 3;
+ if (!(unix_name = RtlAllocateHeap( GetProcessHeap(), 0, unix_len )))
+ return STATUS_NO_MEMORY;
+ unix_name[0] = '.';
+
+ if (!(status = server_get_unix_fd( attr->RootDirectory, FILE_READ_DATA, &root_fd,
+ &needs_close, &type, NULL )))
+ {
+ if (type != FD_TYPE_DIR)
+ {
+ if (needs_close) close( root_fd );
+ status = STATUS_BAD_DEVICE_TYPE;
+ }
+ else
+ {
+ RtlEnterCriticalSection( &dir_section );
+ if ((old_cwd = open( ".", O_RDONLY )) != -1 && fchdir( root_fd ) != -1)
+ {
+ status = lookup_unix_name( name, name_len, &unix_name, unix_len, 1,
+ disposition, check_case );
+ if (fchdir( old_cwd ) == -1) chdir( "/" );
+ }
+ else status = FILE_GetNtStatus();
+ RtlLeaveCriticalSection( &dir_section );
+ if (old_cwd != -1) close( old_cwd );
+ if (needs_close) close( root_fd );
+ }
+ }
+ else if (status == STATUS_OBJECT_TYPE_MISMATCH) status = STATUS_BAD_DEVICE_TYPE;
+
+ if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
+ {
+ TRACE( "%s -> %s\n", debugstr_us(attr->ObjectName), debugstr_a(unix_name) );
+ unix_name_ret->Buffer = unix_name;
+ unix_name_ret->Length = strlen(unix_name);
+ unix_name_ret->MaximumLength = unix_len;
+ }
+ else
+ {
+ TRACE( "%s not found in %s\n", debugstr_w(name), unix_name );
+ RtlFreeHeap( GetProcessHeap(), 0, unix_name );
+ }
+ return status;
+}
+
+
+/******************************************************************************
* wine_nt_to_unix_file_name (NTDLL.@) Not a Windows API
*
* Convert a file name from NT namespace to Unix namespace.
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index a43291e..213d083 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -115,9 +115,7 @@ static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATT
if (alloc_size) FIXME( "alloc_size not supported\n" );
- if (attr->RootDirectory ||
- (io->u.Status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, disposition,
- !(attr->Attributes & OBJ_CASE_INSENSITIVE) )) == STATUS_BAD_DEVICE_TYPE)
+ if ((io->u.Status = nt_to_unix_file_name_attr( attr, &unix_name, disposition )) == STATUS_BAD_DEVICE_TYPE)
{
SERVER_START_REQ( open_file_object )
{
@@ -147,7 +145,7 @@ static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATT
struct security_descriptor *sd = NULL;
struct object_attributes objattr;
- objattr.rootdir = 0;
+ objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
objattr.sd_len = 0;
objattr.name_len = 0;
if (attr)
@@ -2117,8 +2115,7 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
ANSI_STRING unix_name;
NTSTATUS status;
- if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, FILE_OPEN,
- !(attr->Attributes & OBJ_CASE_INSENSITIVE) )))
+ if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
{
struct stat st;
@@ -2160,8 +2157,7 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC
ANSI_STRING unix_name;
NTSTATUS status;
- if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, FILE_OPEN,
- !(attr->Attributes & OBJ_CASE_INSENSITIVE) )))
+ if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
{
struct stat st;
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 1150f47..b1e976c 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -147,6 +147,8 @@ extern BOOL DIR_is_hidden_file( const UNICODE_STRING *name );
extern NTSTATUS DIR_unmount_device( HANDLE handle );
extern NTSTATUS DIR_get_unix_cwd( char **cwd );
extern unsigned int DIR_get_drives_info( struct drive_info info[MAX_DOS_DRIVES] );
+extern NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, ANSI_STRING *unix_name_ret,
+ UINT disposition );
/* virtual memory */
extern void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info );
More information about the wine-cvs
mailing list