Implemented RtlDosPathNameToNtPathName_U, RtlGetCurrentDirectory_U,

RtlGetFullPathName_U and RtlSetCurrentDirectory_U (the last one
partially as we can't test whether a path exists or not).
This commit is contained in:
Eric Pouech 2003-05-15 04:20:42 +00:00 committed by Alexandre Julliard
parent caa44e6e0a
commit 35d5d06ac9
5 changed files with 513 additions and 74 deletions

View File

@ -348,9 +348,9 @@
@ stub RtlDestroyProcessParameters
@ stub RtlDestroyQueryDebugBuffer
@ stdcall RtlDetermineDosPathNameType_U(wstr)
@ stub RtlDoesFileExists_U
@ stdcall RtlDosPathNameToNtPathName_U(ptr ptr long long)
@ stub RtlDosSearchPath_U
@ stub RtlDoesFileExists_U #(wstr)
@ stdcall RtlDosPathNameToNtPathName_U(wstr ptr ptr ptr)
@ stub RtlDosSearchPath_U #(wstr wstr wstr long ptr ptr)
@ stdcall RtlDowncaseUnicodeChar(long)
@ stdcall RtlDowncaseUnicodeString(ptr ptr long)
@ stdcall RtlDumpResource(ptr)
@ -408,10 +408,10 @@
@ stub RtlGetCallersAddress
@ stub RtlGetCompressionWorkSpaceSize
@ stdcall RtlGetControlSecurityDescriptor(ptr ptr ptr)
@ stub RtlGetCurrentDirectory_U
@ stdcall RtlGetCurrentDirectory_U(long ptr)
@ stdcall RtlGetDaclSecurityDescriptor(ptr ptr ptr ptr)
@ stub RtlGetElementGenericTable
@ stub RtlGetFullPathName_U
@ stdcall RtlGetFullPathName_U(wstr long ptr ptr)
@ stdcall RtlGetGroupSecurityDescriptor(ptr ptr ptr)
@ stdcall RtlGetLongestNtPathLength()
@ stub RtlGetNtGlobalFlags
@ -511,7 +511,7 @@
@ stub RtlSelfRelativeToAbsoluteSD
@ stdcall RtlSetAllBits(ptr)
@ stdcall RtlSetBits(ptr long long)
@ stub RtlSetCurrentDirectory_U
@ stdcall RtlSetCurrentDirectory_U(ptr)
@ stdcall RtlSetCurrentEnvironment(wstr ptr)
@ stdcall RtlSetDaclSecurityDescriptor(ptr long ptr long)
@ stdcall RtlSetEnvironmentVariable(ptr ptr ptr)

View File

@ -24,9 +24,14 @@
#include "winternl.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "ntdll_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL(file);
static const WCHAR DeviceRootW[] = {'\\','\\','.','\\',0};
static const WCHAR NTDosPrefixW[] = {'\\','?','?','\\',0};
static const WCHAR UncPfxW[] = {'U','N','C','\\',0};
#define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/')
/***********************************************************************
@ -50,7 +55,6 @@ DOS_PATHNAME_TYPE WINAPI RtlDetermineDosPathNameType_U( PCWSTR path )
}
}
/***********************************************************************
* RtlIsDosDeviceName_U (NTDLL.@)
*
@ -129,6 +133,370 @@ ULONG WINAPI RtlIsDosDeviceName_U( PCWSTR dos_name )
}
/**************************************************************************
* RtlDosPathNameToNtPathName_U [NTDLL.@]
*
* dos_path: a DOS path name (fully qualified or not)
* ntpath: pointer to a UNICODE_STRING to hold the converted
* path name
* file_part:will point (in ntpath) to the file part in the path
* cd: directory reference (optional)
*
* FIXME:
* + fill the cd structure
*/
BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(PWSTR dos_path,
PUNICODE_STRING ntpath,
PWSTR* file_part,
CURDIR* cd)
{
static const WCHAR LongFileNamePfxW[4] = {'\\','\\','?','\\'};
ULONG sz, ptr_sz, offset;
WCHAR local[MAX_PATH];
LPWSTR ptr;
TRACE("(%s,%p,%p,%p)\n",
debugstr_w(dos_path), ntpath, file_part, cd);
if (cd)
{
FIXME("Unsupported parameter\n");
memset(cd, 0, sizeof(*cd));
}
if (!dos_path || !*dos_path) return FALSE;
if (!memcmp(dos_path, LongFileNamePfxW, sizeof(LongFileNamePfxW)))
{
dos_path += sizeof(LongFileNamePfxW) / sizeof(WCHAR);
ptr = NULL;
ptr_sz = 0;
}
else
{
ptr = local;
ptr_sz = sizeof(local);
}
sz = RtlGetFullPathName_U(dos_path, ptr_sz, ptr, file_part);
if (sz == 0) return FALSE;
if (sz > ptr_sz)
{
ptr = RtlAllocateHeap(ntdll_get_process_heap(), 0, sz);
sz = RtlGetFullPathName_U(dos_path, sz, ptr, file_part);
}
ntpath->MaximumLength = sz + (4 /* unc\ */ + 4 /* \??\ */) * sizeof(WCHAR);
ntpath->Buffer = RtlAllocateHeap(ntdll_get_process_heap(), 0, ntpath->MaximumLength);
if (!ntpath->Buffer)
{
if (ptr != local) RtlFreeHeap(ntdll_get_process_heap(), 0, ptr);
return FALSE;
}
strcpyW(ntpath->Buffer, NTDosPrefixW);
offset = 0;
switch (RtlDetermineDosPathNameType_U(ptr))
{
case UNC_PATH: /* \\foo */
if (ptr[2] != '?')
{
offset = 2;
strcatW(ntpath->Buffer, UncPfxW);
}
break;
case DEVICE_PATH: /* \\.\foo */
offset = 4;
break;
default: break; /* needed to keep gcc quiet */
}
strcatW(ntpath->Buffer, ptr + offset);
ntpath->Length = strlenW(ntpath->Buffer) * sizeof(WCHAR);
if (file_part && *file_part)
*file_part = ntpath->Buffer + ntpath->Length / sizeof(WCHAR) - lstrlenW(*file_part);
/* FIXME: cd filling */
if (ptr != local) RtlFreeHeap(ntdll_get_process_heap(), 0, ptr);
return TRUE;
}
/******************************************************************
* get_full_path_helper
*
* Helper for RtlGetFullPathName_U
*/
static ULONG get_full_path_helper(LPCWSTR name, LPWSTR buffer, ULONG size)
{
ULONG reqsize, mark = 0;
DOS_PATHNAME_TYPE type;
LPWSTR ptr;
UNICODE_STRING* cd;
reqsize = sizeof(WCHAR); /* '\0' at the end */
RtlAcquirePebLock();
cd = &ntdll_get_process_pmts()->CurrentDirectoryName;
switch (type = RtlDetermineDosPathNameType_U(name))
{
case UNC_PATH: /* \\foo */
case DEVICE_PATH: /* \\.\foo */
if (reqsize <= size) buffer[0] = '\0';
break;
case ABSOLUTE_DRIVE_PATH: /* c:\foo */
reqsize += sizeof(WCHAR);
if (reqsize <= size)
{
buffer[0] = toupperW(name[0]);
buffer[1] = '\0';
}
name++;
break;
case RELATIVE_DRIVE_PATH: /* c:foo */
if (toupperW(name[0]) != toupperW(cd->Buffer[0]) || cd->Buffer[1] != ':')
{
WCHAR drive[4];
UNICODE_STRING var, val;
drive[0] = '=';
drive[1] = name[0];
drive[2] = ':';
drive[3] = '\0';
var.Length = 6;
var.MaximumLength = 8;
var.Buffer = drive;
val.Length = 0;
val.MaximumLength = size;
val.Buffer = buffer;
name += 2;
switch (RtlQueryEnvironmentVariable_U(NULL, &var, &val))
{
case STATUS_SUCCESS:
/* FIXME: Win2k seems to check that the environment variable actually points
* to an existing directory. If not, root of the drive is used
* (this seems also to be the only spot in RtlGetFullPathName that the
* existence of a part of a path is checked)
*/
/* fall thru */
case STATUS_BUFFER_TOO_SMALL:
reqsize += val.Length;
/* append trailing \\ */
reqsize += sizeof(WCHAR);
if (reqsize <= size)
{
buffer[reqsize / sizeof(WCHAR) - 2] = '\\';
buffer[reqsize / sizeof(WCHAR) - 1] = '\0';
}
break;
case STATUS_VARIABLE_NOT_FOUND:
reqsize += 3 * sizeof(WCHAR);
if (reqsize <= size)
{
buffer[0] = drive[1];
buffer[1] = ':';
buffer[2] = '\\';
buffer[3] = '\0';
}
break;
default:
ERR("Unsupported status code\n");
break;
}
break;
}
name += 2;
/* fall through */
case RELATIVE_PATH: /* foo */
reqsize += cd->Length;
mark = cd->Length / sizeof(WCHAR);
if (reqsize <= size)
strcpyW(buffer, cd->Buffer);
break;
case ABSOLUTE_PATH: /* \xxx */
if (cd->Buffer[1] == ':')
{
reqsize += 2 * sizeof(WCHAR);
if (reqsize <= size)
{
buffer[0] = cd->Buffer[0];
buffer[1] = ':';
buffer[2] = '\0';
}
}
else
{
unsigned len;
ptr = strchrW(cd->Buffer + 2, '\\');
if (ptr) ptr = strchrW(ptr + 1, '\\');
if (!ptr) ptr = cd->Buffer + strlenW(cd->Buffer);
len = (ptr - cd->Buffer) * sizeof(WCHAR);
reqsize += len;
mark = len / sizeof(WCHAR);
if (reqsize <= size)
{
memcpy(buffer, cd->Buffer, len);
buffer[len / sizeof(WCHAR)] = '\0';
}
else
buffer[0] = '\0';
}
break;
case UNC_DOT_PATH: /* \\. */
reqsize += 4 * sizeof(WCHAR);
name += 3;
if (reqsize <= size)
{
buffer[0] = '\\';
buffer[1] = '\\';
buffer[2] = '.';
buffer[3] = '\\';
buffer[4] = '\0';
}
break;
case INVALID_PATH:
reqsize = 0;
goto done;
}
reqsize += strlenW(name) * sizeof(WCHAR);
if (reqsize > size) goto done;
strcatW(buffer, name);
/* convert every / into a \ */
for (ptr = buffer; ptr < buffer + size / sizeof(WCHAR); ptr++)
if (*ptr == '/') *ptr = '\\';
reqsize -= sizeof(WCHAR); /* don't count trailing \0 */
/* mark is non NULL for UNC names, so start path collapsing after server & share name
* otherwise, it's a fully qualified DOS name, so start after the drive designation
*/
for (ptr = buffer + (mark ? mark : 2); ptr < buffer + reqsize / sizeof(WCHAR); )
{
WCHAR* p = strchrW(ptr, '\\');
if (!p) break;
p++;
if (p[0] == '.')
{
switch (p[1])
{
case '.':
switch (p[2])
{
case '\\':
{
WCHAR* prev = p - 2;
while (prev >= buffer + mark && *prev != '\\') prev--;
/* either collapse \foo\.. into \ or \.. into \ */
if (prev < buffer + mark) prev = p - 1;
reqsize -= (p + 2 - prev) * sizeof(WCHAR);
memmove(prev, p + 2, buffer + reqsize - prev + sizeof(WCHAR));
}
break;
case '\0':
reqsize -= 2 * sizeof(WCHAR);
*p = 0;
break;
}
break;
case '\\':
reqsize -= 2 * sizeof(WCHAR);
memmove(ptr + 2, ptr, buffer + reqsize - ptr + sizeof(WCHAR));
break;
}
}
ptr = p;
}
done:
RtlReleasePebLock();
return reqsize;
}
/******************************************************************
* RtlGetFullPathName_U (NTDLL.@)
*
* Returns the number of bytes written to buffer (not including the
* terminating NULL) if the function succeeds, or the required number of bytes
* (including the terminating NULL) if the buffer is to small.
*
* file_part will point to the filename part inside buffer (except if we use
* DOS device name, in which case file_in_buf is NULL)
*
*/
DWORD WINAPI RtlGetFullPathName_U(const WCHAR* name, ULONG size, WCHAR* buffer,
WCHAR** file_part)
{
DWORD dosdev;
DWORD reqsize;
TRACE("(%s %lu %p %p)\n", debugstr_w(name), size, buffer, file_part);
if (!name || !*name) return 0;
if (file_part) *file_part = NULL;
/* check for DOS device name */
dosdev = RtlIsDosDeviceName_U(name);
if (dosdev)
{
DWORD offset = HIWORD(dosdev) / sizeof(WCHAR); /* get it in WCHARs, not bytes */
DWORD sz = LOWORD(dosdev); /* in bytes */
if (8 + sz + 2 > size) return sz + 10;
strcpyW(buffer, DeviceRootW);
memmove(buffer + 4, name + offset, sz);
buffer[4 + sz / sizeof(WCHAR)] = '\0';
/* file_part isn't set in this case */
return sz + 8;
}
reqsize = get_full_path_helper(name, buffer, size);
if (reqsize > size)
{
LPWSTR tmp = RtlAllocateHeap(ntdll_get_process_heap(), 0, reqsize);
reqsize = get_full_path_helper(name, tmp, reqsize) + sizeof(WCHAR);
RtlFreeHeap(ntdll_get_process_heap(), 0, tmp);
}
else
{
WCHAR* ptr;
/* find file part */
if (file_part && (ptr = strrchrW(buffer, '\\')) != NULL && ptr >= buffer + 2 && *++ptr)
*file_part = ptr;
}
return reqsize;
}
/*************************************************************************
* RtlGetLongestNtPathLength [NTDLL.@]
*
* Get the longest allowed path length
*
* PARAMS
* None.
*
* RETURNS
* The longest allowed path length (277 characters under Win2k).
*/
DWORD WINAPI RtlGetLongestNtPathLength(void)
{
return 277;
}
/******************************************************************
* RtlIsNameLegalDOS8Dot3 (NTDLL.@)
*
@ -197,3 +565,120 @@ BOOLEAN WINAPI RtlIsNameLegalDOS8Dot3( const UNICODE_STRING *unicode,
if (spaces) *spaces = got_space;
return TRUE;
}
/******************************************************************
* RtlGetCurrentDirectory_U (NTDLL.@)
*
*/
NTSTATUS WINAPI RtlGetCurrentDirectory_U(ULONG buflen, LPWSTR buf)
{
UNICODE_STRING* us;
ULONG len;
TRACE("(%lu %p)\n", buflen, buf);
RtlAcquirePebLock();
us = &ntdll_get_process_pmts()->CurrentDirectoryName;
len = us->Length / sizeof(WCHAR);
if (us->Buffer[len - 1] == '\\' && us->Buffer[len - 2] != ':')
len--;
if (buflen / sizeof(WCHAR) > len)
{
memcpy(buf, us->Buffer, len * sizeof(WCHAR));
buf[len] = '\0';
}
else
{
len++;
}
RtlReleasePebLock();
return len * sizeof(WCHAR);
}
/******************************************************************
* RtlSetCurrentDirectory_U (NTDLL.@)
*
*/
NTSTATUS WINAPI RtlSetCurrentDirectory_U(const UNICODE_STRING* dir)
{
UNICODE_STRING* curdir;
NTSTATUS nts = STATUS_SUCCESS;
ULONG size;
PWSTR buf = NULL;
TRACE("(%s)\n", debugstr_w(dir->Buffer));
RtlAcquirePebLock();
curdir = &ntdll_get_process_pmts()->CurrentDirectoryName;
size = curdir->MaximumLength;
buf = RtlAllocateHeap(ntdll_get_process_heap(), 0, size);
if (buf == NULL)
{
nts = STATUS_NO_MEMORY;
goto out;
}
size = RtlGetFullPathName_U(dir->Buffer, size, buf, 0);
if (!size)
{
nts = STATUS_OBJECT_NAME_INVALID;
goto out;
}
switch (RtlDetermineDosPathNameType_U(buf))
{
case ABSOLUTE_DRIVE_PATH:
case UNC_PATH:
break;
default:
FIXME("Don't support those cases yes\n");
nts = STATUS_NOT_IMPLEMENTED;
goto out;
}
/* FIXME: should check that the directory actually exists,
* and fill CurrentDirectoryHandle accordingly
*/
/* append trailing \ if missing */
if (buf[size / sizeof(WCHAR) - 1] != '\\')
{
buf[size / sizeof(WCHAR)] = '\\';
buf[size / sizeof(WCHAR) + 1] = '\0';
size += sizeof(WCHAR);
}
memmove(curdir->Buffer, buf, size + sizeof(WCHAR));
curdir->Length = size;
#if 0
if (curdir->Buffer[1] == ':')
{
UNICODE_STRING env;
WCHAR var[4];
var[0] = '=';
var[1] = curdir->Buffer[0];
var[2] = ':';
var[3] = 0;
env.Length = 3 * sizeof(WCHAR);
env.MaximumLength = 4 * sizeof(WCHAR);
env.Buffer = var;
RtlSetEnvironmentVariable(NULL, &env, curdir);
}
#endif
out:
if (buf) RtlFreeHeap(ntdll_get_process_heap(), 0, buf);
RtlReleasePebLock();
return nts;
}

View File

@ -370,55 +370,6 @@ void WINAPI NTDLL_alloca_probe( CONTEXT86 *context )
context->Esp -= context->Eax;
}
/**************************************************************************
* RtlDosPathNameToNtPathName_U [NTDLL.@]
*
* szwDosPath: a fully qualified DOS path name
* ntpath: pointer to a UNICODE_STRING to hold the converted
* path name
*
* FIXME: Should we not allocate the ntpath buffer under some
* circumstances?
* Are the conversions static? (always prepend '\??\' ?)
* Not really sure about the last two arguments.
*/
BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(
LPWSTR szwDosPath,PUNICODE_STRING ntpath,
DWORD x2,DWORD x3)
{
ULONG length;
UNICODE_STRING pathprefix;
WCHAR szPrefix[] = { '\\', '?', '?', '\\', 0 };
FIXME("(%s,%p,%08lx,%08lx) partial stub\n",
debugstr_w(szwDosPath),ntpath,x2,x3);
if ( !szwDosPath )
return FALSE;
if ( !szwDosPath[0] )
return FALSE;
if ( szwDosPath[1]!= ':' )
return FALSE;
length = strlenW(szwDosPath) * sizeof (WCHAR) + sizeof szPrefix;
ntpath->Buffer = RtlAllocateHeap(ntdll_get_process_heap(), 0, length);
ntpath->Length = 0;
ntpath->MaximumLength = length;
if ( !ntpath->Buffer )
return FALSE;
RtlInitUnicodeString( &pathprefix, szPrefix );
RtlCopyUnicodeString( ntpath, &pathprefix );
RtlAppendUnicodeToString( ntpath, szwDosPath );
return TRUE;
}
/******************************************************************************
* RtlInitializeGenericTable [NTDLL.@]
*/
@ -606,23 +557,6 @@ VOID WINAPI RtlFillMemoryUlong(ULONG* lpDest, ULONG ulCount, ULONG ulValue)
*lpDest++ = ulValue;
}
/*************************************************************************
* RtlGetLongestNtPathLength [NTDLL.@]
*
* Get the longest allowed path length
*
* PARAMS
* None.
*
* RETURNS
* The longest allowed path length (277 characters under Win2k).
*/
DWORD WINAPI RtlGetLongestNtPathLength(void)
{
TRACE("()\n");
return 277;
}
/*********************************************************************
* RtlComputeCrc32 [NTDLL.@]
*

View File

@ -95,6 +95,12 @@ typedef struct _CLIENT_ID
HANDLE UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
typedef struct _CURDIR
{
UNICODE_STRING DosPath;
PVOID Handle;
} CURDIR, *PCURDIR;
/***********************************************************************
* Enums
*/
@ -965,7 +971,7 @@ DWORD WINAPI RtlDeleteSecurityObject(DWORD);
NTSTATUS WINAPI RtlDestroyEnvironment(PWSTR);
HANDLE WINAPI RtlDestroyHeap(HANDLE);
DOS_PATHNAME_TYPE WINAPI RtlDetermineDosPathNameType_U(PCWSTR);
BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(LPWSTR,PUNICODE_STRING,DWORD,DWORD);
BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(LPWSTR,PUNICODE_STRING,PWSTR*,CURDIR*);
WCHAR WINAPI RtlDowncaseUnicodeChar(WCHAR);
NTSTATUS WINAPI RtlDowncaseUnicodeString(UNICODE_STRING*,const UNICODE_STRING*,BOOLEAN);
void WINAPI RtlDumpResource(LPRTL_RWLOCK);
@ -1014,9 +1020,11 @@ void WINAPI RtlFreeUnicodeString(PUNICODE_STRING);
DWORD WINAPI RtlGetAce(PACL,DWORD,LPVOID *);
NTSTATUS WINAPI RtlGetControlSecurityDescriptor(PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR_CONTROL,LPDWORD);
NTSTATUS WINAPI RtlGetCurrentDirectory_U(ULONG, LPWSTR);
NTSTATUS WINAPI RtlGetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR,PBOOLEAN,PACL *,PBOOLEAN);
ULONG WINAPI RtlGetFullPathName_U(PCWSTR,ULONG,PWSTR,PWSTR*);
NTSTATUS WINAPI RtlGetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR,PSID *,PBOOLEAN);
DWORD WINAPI RtlGetLongestNtPathLength(void);
BOOLEAN WINAPI RtlGetNtProductType(LPDWORD);
NTSTATUS WINAPI RtlGetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR,PSID *,PBOOLEAN);
ULONG WINAPI RtlGetProcessHeaps(ULONG,HANDLE*);
@ -1093,6 +1101,7 @@ void WINAPI RtlSecondsSince1970ToTime(DWORD,LARGE_INTEGER *);
void WINAPI RtlSecondsSince1980ToTime(DWORD,LARGE_INTEGER *);
void WINAPI RtlSetAllBits(PRTL_BITMAP);
void WINAPI RtlSetBits(PRTL_BITMAP,ULONG,ULONG);
NTSTATUS WINAPI RtlSetCurrentDirectory_U(const UNICODE_STRING*);
void WINAPI RtlSetCurrentEnvironment(PWSTR, PWSTR*);
NTSTATUS WINAPI RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR,BOOLEAN,PACL,BOOLEAN);
NTSTATUS WINAPI RtlSetEnvironmentVariable(PWSTR*,PUNICODE_STRING,PUNICODE_STRING);

View File

@ -471,6 +471,17 @@ static BOOL process_init( char *argv[] )
/* Parse command line arguments */
OPTIONS_ParseOptions( !info_size ? argv : NULL );
/* <hack: to be changed later on> */
build_initial_environment();
process_pmts.CurrentDirectoryName.Length = 3 * sizeof(WCHAR);
process_pmts.CurrentDirectoryName.MaximumLength = RtlGetLongestNtPathLength() * sizeof(WCHAR);
process_pmts.CurrentDirectoryName.Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, process_pmts.CurrentDirectoryName.MaximumLength);
process_pmts.CurrentDirectoryName.Buffer[0] = 'C';
process_pmts.CurrentDirectoryName.Buffer[1] = ':';
process_pmts.CurrentDirectoryName.Buffer[2] = '\\';
process_pmts.CurrentDirectoryName.Buffer[3] = '\0';
/* </hack: to be changed later on> */
ret = MAIN_MainInit();
if (TRACE_ON(relay) || TRACE_ON(snoop)) RELAY_InitDebugLists();