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