From 4bb759e8ad84c00569d8ab3586afb2944d525d73 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 21 Apr 2004 22:26:44 +0000 Subject: [PATCH] Properly set IO_STATUS_BLOCK.Information in NtCreateFile. --- dlls/ntdll/directory.c | 48 +++++++++++++++++++++++++----------------- dlls/ntdll/file.c | 39 +++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 22 deletions(-) diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index f22f574e94f..9820de6a50d 100644 --- a/dlls/ntdll/directory.c +++ b/dlls/ntdll/directory.c @@ -650,7 +650,7 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event, * There must be at least MAX_DIR_ENTRY_LEN+2 chars available at pos. */ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, int length, - int is_last, int check_last, int check_case ) + int check_case ) { WCHAR buffer[MAX_DIR_ENTRY_LEN]; UNICODE_STRING str; @@ -771,19 +771,8 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i goto not_found; /* avoid warning */ not_found: - if (is_last && !check_last) /* return the name anyway */ - { - int used_default; - ret = ntdll_wcstoumbs( 0, name, length, unix_name + pos, - MAX_DIR_ENTRY_LEN, NULL, &used_default ); - if (ret > 0 && !used_default) - { - unix_name[pos + ret] = 0; - return STATUS_SUCCESS; - } - } unix_name[pos - 1] = 0; - return is_last ? STATUS_OBJECT_NAME_NOT_FOUND : STATUS_OBJECT_PATH_NOT_FOUND; + return STATUS_OBJECT_PATH_NOT_FOUND; } @@ -809,6 +798,10 @@ static inline int get_dos_prefix_len( const UNICODE_STRING *name ) * DIR_nt_to_unix * * Convert a file name from NT namespace to Unix namespace. + * + * If check_last is 0, the last path element doesn't have to exist; + * in that case STATUS_OBJECT_NAME_NOT_FOUND is returned, but the + * unix name is still filled in properly. */ NTSTATUS DIR_nt_to_unix( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret, int check_last, int check_case ) @@ -816,7 +809,7 @@ NTSTATUS DIR_nt_to_unix( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret static const WCHAR uncW[] = {'U','N','C','\\'}; static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 }; - NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; + NTSTATUS status = STATUS_SUCCESS; const char *config_dir = wine_get_config_dir(); const WCHAR *name, *p; struct stat st; @@ -908,6 +901,7 @@ NTSTATUS DIR_nt_to_unix( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret while (end < name + name_len && !IS_SEPARATOR(*end)) end++; next = end; while (next < name + name_len && IS_SEPARATOR(*next)) next++; + name_len -= next - name; /* grow the buffer if needed */ @@ -923,8 +917,25 @@ NTSTATUS DIR_nt_to_unix( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret unix_name = new_name; } - status = find_file_in_dir( unix_name, pos, name, end - name, - (next - name == name_len), check_last, check_case ); + status = find_file_in_dir( unix_name, pos, name, end - name, check_case ); + + /* if this is the last element, not finding it is not necessarily fatal */ + if (!name_len && status == STATUS_OBJECT_PATH_NOT_FOUND) + { + status = STATUS_OBJECT_NAME_NOT_FOUND; + if (!check_last) + { + ret = ntdll_wcstoumbs( 0, name, end - name, unix_name + pos + 1, + MAX_DIR_ENTRY_LEN, NULL, &used_default ); + if (ret > 0 && !used_default) + { + unix_name[pos] = '/'; + unix_name[pos + 1 + ret] = 0; + break; + } + } + } + if (status != STATUS_SUCCESS) { /* couldn't find it at all, fail */ @@ -934,7 +945,6 @@ NTSTATUS DIR_nt_to_unix( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret } pos += strlen( unix_name + pos ); - name_len -= next - name; name = next; } @@ -946,7 +956,7 @@ done: unix_name_ret->Buffer = unix_name; unix_name_ret->Length = strlen(unix_name); unix_name_ret->MaximumLength = unix_len; - return STATUS_SUCCESS; + return status; } @@ -965,7 +975,7 @@ char *wine_get_unix_file_name( LPCWSTR dosW ) if (!RtlDosPathNameToNtPathName_U( dosW, &nt_name, NULL, NULL )) return NULL; status = DIR_nt_to_unix( &nt_name, &unix_name, FALSE, FALSE ); RtlFreeUnicodeString( &nt_name ); - if (status) return NULL; + if (status && status != STATUS_OBJECT_NAME_NOT_FOUND) return NULL; return unix_name.Buffer; } diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 4e21aee0827..3164c405cbe 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -131,6 +131,7 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB ULONG options, PVOID ea_buffer, ULONG ea_length ) { ANSI_STRING unix_name; + int check_last, created = FALSE; TRACE("handle=%p access=%08lx name=%s objattr=%08lx root=%p sec=%p io=%p alloc_size=%p\n" "attr=%08lx sharing=%08lx disp=%ld options=%08lx ea=%p.0x%08lx\n", @@ -145,9 +146,18 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB } if (alloc_size) FIXME( "alloc_size not supported\n" ); - if (!(io->u.Status = DIR_nt_to_unix( attr->ObjectName, &unix_name, - (disposition == FILE_OPEN || disposition == FILE_OVERWRITE), - !(attr->Attributes & OBJ_CASE_INSENSITIVE) ))) + check_last = (disposition == FILE_OPEN || disposition == FILE_OVERWRITE); + + io->u.Status = DIR_nt_to_unix( attr->ObjectName, &unix_name, check_last, + !(attr->Attributes & OBJ_CASE_INSENSITIVE) ); + + if (!check_last && io->u.Status == STATUS_OBJECT_NAME_NOT_FOUND) + { + created = TRUE; + io->u.Status = STATUS_SUCCESS; + } + + if (io->u.Status == STATUS_SUCCESS) { SERVER_START_REQ( create_file ) { @@ -165,6 +175,29 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB RtlFreeAnsiString( &unix_name ); } else WARN("%s not found (%lx)\n", debugstr_us(attr->ObjectName), io->u.Status ); + + if (io->u.Status == STATUS_SUCCESS) + { + if (created) io->Information = FILE_CREATED; + else switch(disposition) + { + case FILE_SUPERSEDE: + io->Information = FILE_SUPERSEDED; + break; + case FILE_CREATE: + io->Information = FILE_CREATED; + break; + case FILE_OPEN: + case FILE_OPEN_IF: + io->Information = FILE_OPENED; + break; + case FILE_OVERWRITE: + case FILE_OVERWRITE_IF: + io->Information = FILE_OVERWRITTEN; + break; + } + } + return io->u.Status; }