/* GLOBALS ********************************************************************/
-UNICODE_STRING BaseDllDirectory;
UNICODE_STRING NoDefaultCurrentDirectoryInExePath = RTL_CONSTANT_STRING(L"NoDefaultCurrentDirectoryInExePath");
+UNICODE_STRING BaseWindowsSystemDirectory, BaseWindowsDirectory;
+UNICODE_STRING BaseDefaultPathAppend, BaseDefaultPath, BaseDllDirectory;
+
+PVOID gpTermsrvGetWindowsDirectoryA;
+PVOID gpTermsrvGetWindowsDirectoryW;
+
/* This is bitmask for each illegal filename character */
/* If someone has time, please feel free to use 0b notation */
DWORD IllegalMask[4] =
0x10000000 // 7C not allowed
};
-/* FUNCTIONS ******************************************************************/
+BASE_SEARCH_PATH_TYPE BaseDllOrderCurrent[BaseCurrentDirPlacementMax][BaseSearchPathMax] =
+{
+ {
+ BaseSearchPathApp,
+ BaseSearchPathCurrent,
+ BaseSearchPathDefault,
+ BaseSearchPathEnv,
+ BaseSearchPathInvalid
+ },
+ {
+ BaseSearchPathApp,
+ BaseSearchPathDefault,
+ BaseSearchPathCurrent,
+ BaseSearchPathEnv,
+ BaseSearchPathInvalid
+ }
+};
+
+BASE_SEARCH_PATH_TYPE BaseProcessOrderNoCurrent[BaseSearchPathMax] =
+{
+ BaseSearchPathApp,
+ BaseSearchPathDefault,
+ BaseSearchPathEnv,
+ BaseSearchPathInvalid,
+ BaseSearchPathInvalid
+};
+
+BASE_SEARCH_PATH_TYPE BaseDllOrderNoCurrent[BaseSearchPathMax] =
+{
+ BaseSearchPathApp,
+ BaseSearchPathDll,
+ BaseSearchPathDefault,
+ BaseSearchPathEnv,
+ BaseSearchPathInvalid
+};
+
+BASE_SEARCH_PATH_TYPE BaseProcessOrder[BaseSearchPathMax] =
+{
+ BaseSearchPathApp,
+ BaseSearchPathCurrent,
+ BaseSearchPathDefault,
+ BaseSearchPathEnv,
+ BaseSearchPathInvalid
+};
+
+BASE_CURRENT_DIR_PLACEMENT BasepDllCurrentDirPlacement = BaseCurrentDirPlacementInvalid;
+
+extern UNICODE_STRING BasePathVariableName;
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+PWCHAR
+WINAPI
+BasepEndOfDirName(IN PWCHAR FileName)
+{
+ PWCHAR FileNameEnd, FileNameSeparator;
+
+ /* Find the first slash */
+ FileNameSeparator = wcschr(FileName, OBJ_NAME_PATH_SEPARATOR);
+ if (FileNameSeparator)
+ {
+ /* Find the last one */
+ FileNameEnd = wcsrchr(FileNameSeparator, OBJ_NAME_PATH_SEPARATOR);
+ ASSERT(FileNameEnd);
+
+ /* Handle the case where they are one and the same */
+ if (FileNameEnd == FileNameSeparator) FileNameEnd++;
+ }
+ else
+ {
+ /* No directory was specified */
+ FileNameEnd = NULL;
+ }
+
+ /* Return where the directory ends and the filename starts */
+ return FileNameEnd;
+}
+
+LPWSTR
+WINAPI
+BasepComputeProcessPath(IN PBASE_SEARCH_PATH_TYPE PathOrder,
+ IN LPWSTR AppName,
+ IN LPVOID Environment)
+{
+ PWCHAR PathBuffer, Buffer, AppNameEnd, PathCurrent;
+ ULONG PathLengthInBytes;
+ NTSTATUS Status;
+ UNICODE_STRING EnvPath;
+ PBASE_SEARCH_PATH_TYPE Order;
+
+ /* Initialize state */
+ AppNameEnd = Buffer = PathBuffer = NULL;
+ Status = STATUS_SUCCESS;
+ PathLengthInBytes = 0;
+
+ /* Loop the ordering array */
+ for (Order = PathOrder; *Order != BaseSearchPathInvalid; Order++) {
+ switch (*Order)
+ {
+ /* Compute the size of the DLL path */
+ case BaseSearchPathDll:
+
+ /* This path only gets called if SetDllDirectory was called */
+ ASSERT(BaseDllDirectory.Buffer != NULL);
+
+ /* Make sure there's a DLL directory size */
+ if (BaseDllDirectory.Length)
+ {
+ /* Add it, plus the separator */
+ PathLengthInBytes += BaseDllDirectory.Length + sizeof(L';');
+ }
+ break;
+
+ /* Compute the size of the current path */
+ case BaseSearchPathCurrent:
+
+ /* Add ".;" */
+ PathLengthInBytes += (2 * sizeof(WCHAR));
+ break;
+
+ /* Compute the size of the "PATH" environment variable */
+ case BaseSearchPathEnv:
+
+ /* Grab PEB lock if one wasn't passed in */
+ if (!Environment) RtlAcquirePebLock();
+
+ /* Query the size first */
+ EnvPath.MaximumLength = 0;
+ Status = RtlQueryEnvironmentVariable_U(Environment,
+ &BasePathVariableName,
+ &EnvPath);
+ if (Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ /* Compute the size we'll need for the environment */
+ EnvPath.MaximumLength = EnvPath.Length + sizeof(WCHAR);
+ if ((EnvPath.Length + sizeof(WCHAR)) > UNICODE_STRING_MAX_BYTES)
+ {
+ /* Don't let it overflow */
+ EnvPath.MaximumLength = EnvPath.Length;
+ }
+
+ /* Allocate the environment buffer */
+ Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+ 0,
+ EnvPath.MaximumLength);
+ if (Buffer)
+ {
+ /* Now query the PATH environment variable */
+ EnvPath.Buffer = Buffer;
+ Status = RtlQueryEnvironmentVariable_U(Environment,
+ &BasePathVariableName,
+ &EnvPath);
+ }
+ else
+ {
+ /* Failure case */
+ Status = STATUS_NO_MEMORY;
+ }
+ }
+
+ /* Release the PEB lock from above */
+ if (!Environment) RtlReleasePebLock();
+
+ /* There might not be a PATH */
+ if (Status == STATUS_VARIABLE_NOT_FOUND)
+ {
+ /* In this case, skip this PathOrder */
+ EnvPath.Length = EnvPath.MaximumLength = 0;
+ Status = STATUS_SUCCESS;
+ }
+ else if (!NT_SUCCESS(Status))
+ {
+ /* An early failure, go to exit code */
+ goto Quickie;
+ }
+ else
+ {
+ /* Add the length of the PATH variable */
+ ASSERT(!(EnvPath.Length & 1));
+ PathLengthInBytes += (EnvPath.Length + sizeof(L';'));
+ }
+ break;
+
+ /* Compute the size of the default search path */
+ case BaseSearchPathDefault:
+
+ /* Just add it... it already has a ';' at the end */
+ ASSERT(!(BaseDefaultPath.Length & 1));
+ PathLengthInBytes += BaseDefaultPath.Length;
+ break;
+
+ /* Compute the size of the current app directory */
+ case BaseSearchPathApp:
+ /* Find out where the app name ends, to get only the directory */
+ if (AppName) AppNameEnd = BasepEndOfDirName(AppName);
+
+ /* Check if there was no application name passed in */
+ if (!(AppName) || !(AppNameEnd))
+ {
+ /* Do we have a per-thread CURDIR to use? */
+ if (NtCurrentTeb()->NtTib.SubSystemTib)
+ {
+ /* This means someone added RTL_PERTHREAD_CURDIR */
+ UNIMPLEMENTED_DBGBREAK();
+ }
+
+ /* We do not. Do we have the LDR_ENTRY for the executable? */
+ if (!BasepExeLdrEntry)
+ {
+ /* We do not. Grab it */
+ LdrEnumerateLoadedModules(0,
+ BasepLocateExeLdrEntry,
+ NtCurrentPeb()->ImageBaseAddress);
+ }
+
+ /* Now do we have it? */
+ if (BasepExeLdrEntry)
+ {
+ /* Yes, so read the name out of it */
+ AppName = BasepExeLdrEntry->FullDllName.Buffer;
+ }
+
+ /* Find out where the app name ends, to get only the directory */
+ if (AppName) AppNameEnd = BasepEndOfDirName(AppName);
+ }
+
+ /* So, do we have an application name and its directory? */
+ if ((AppName) && (AppNameEnd))
+ {
+ /* Add the size of the app's directory, plus the separator */
+ PathLengthInBytes += ((AppNameEnd - AppName) * sizeof(WCHAR)) + sizeof(L';');
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* Bam, all done, we now have the final path size */
+ ASSERT(PathLengthInBytes > 0);
+ ASSERT(!(PathLengthInBytes & 1));
+
+ /* Allocate the buffer to hold it */
+ PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathLengthInBytes);
+ if (!PathBuffer)
+ {
+ /* Failure path */
+ Status = STATUS_NO_MEMORY;
+ goto Quickie;
+ }
+
+ /* Now we loop again, this time to copy the data */
+ PathCurrent = PathBuffer;
+ for (Order = PathOrder; *Order != BaseSearchPathInvalid; Order++) {
+ switch (*Order)
+ {
+ /* Add the DLL path */
+ case BaseSearchPathDll:
+ if (BaseDllDirectory.Length)
+ {
+ /* Copy it in the buffer, ASSERT there's enough space */
+ ASSERT((((PathCurrent - PathBuffer + 1) * sizeof(WCHAR)) + BaseDllDirectory.Length) <= PathLengthInBytes);
+ RtlCopyMemory(PathCurrent,
+ BaseDllDirectory.Buffer,
+ BaseDllDirectory.Length);
+
+ /* Update the current pointer, add a separator */
+ PathCurrent += (BaseDllDirectory.Length / sizeof(WCHAR));
+ *PathCurrent++ = ';';
+ }
+ break;
+
+ /* Add the current application path */
+ case BaseSearchPathApp:
+ if ((AppName) && (AppNameEnd))
+ {
+ /* Copy it in the buffer, ASSERT there's enough space */
+ ASSERT(((PathCurrent - PathBuffer + 1 + (AppNameEnd - AppName)) * sizeof(WCHAR)) <= PathLengthInBytes);
+ RtlCopyMemory(PathCurrent,
+ AppName,
+ (AppNameEnd - AppName) * sizeof(WCHAR));
+
+ /* Update the current pointer, add a separator */
+ PathCurrent += AppNameEnd - AppName;
+ *PathCurrent++ = ';';
+ }
+ break;
+
+ /* Add the default search path */
+ case BaseSearchPathDefault:
+ /* Copy it in the buffer, ASSERT there's enough space */
+ ASSERT((((PathCurrent - PathBuffer) * sizeof(WCHAR)) + BaseDefaultPath.Length) <= PathLengthInBytes);
+ RtlCopyMemory(PathCurrent, BaseDefaultPath.Buffer, BaseDefaultPath.Length);
+
+ /* Update the current pointer. The default path already has a ";" */
+ PathCurrent += (BaseDefaultPath.Length / sizeof(WCHAR));
+ break;
+
+ /* Add the path in the PATH environment variable */
+ case BaseSearchPathEnv:
+ if (EnvPath.Length)
+ {
+ /* Copy it in the buffer, ASSERT there's enough space */
+ ASSERT((((PathCurrent - PathBuffer + 1) * sizeof(WCHAR)) + EnvPath.Length) <= PathLengthInBytes);
+ RtlCopyMemory(PathCurrent, EnvPath.Buffer, EnvPath.Length);
+
+ /* Update the current pointer, add a separator */
+ PathCurrent += (EnvPath.Length / sizeof(WCHAR));
+ *PathCurrent++ = ';';
+ }
+ break;
+
+ /* Add the current dierctory */
+ case BaseSearchPathCurrent:
+
+ /* Copy it in the buffer, ASSERT there's enough space */
+ ASSERT(((PathCurrent - PathBuffer + 2) * sizeof(WCHAR)) <= PathLengthInBytes);
+ *PathCurrent++ = '.';
+
+ /* Add the path separator */
+ *PathCurrent++ = ';';
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* Everything should've perfectly fit in there */
+ ASSERT((PathCurrent - PathBuffer) * sizeof(WCHAR) == PathLengthInBytes);
+ ASSERT(PathCurrent > PathBuffer);
+
+ /* Terminate the whole thing */
+ PathCurrent[-1] = UNICODE_NULL;
+
+Quickie:
+ /* Exit path: free our buffers */
+ if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+ if (PathBuffer)
+ {
+ /* This only gets freed in the failure path, since caller wants it */
+ if (!NT_SUCCESS(Status))
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
+ PathBuffer = NULL;
+ }
+ }
+
+ /* Return the path! */
+ return PathBuffer;
+}
+
+LPWSTR
+WINAPI
+BaseComputeProcessSearchPath(VOID)
+{
+ DPRINT("Computing Process Search path\n");
+
+ /* Compute the path using default process order */
+ return BasepComputeProcessPath(BaseProcessOrder, NULL, NULL);
+}
+
+LPWSTR
+WINAPI
+BaseComputeProcessExePath(IN LPWSTR FullPath)
+{
+ PBASE_SEARCH_PATH_TYPE PathOrder;
+ DPRINT1("Computing EXE path: %wZ\n", FullPath);
+
+ /* Check if we should use the current directory */
+ PathOrder = NeedCurrentDirectoryForExePathW(FullPath) ?
+ BaseProcessOrder : BaseProcessOrderNoCurrent;
+
+ /* And now compute the path */
+ return BasepComputeProcessPath(PathOrder, NULL, NULL);
+}
+
+LPWSTR
+WINAPI
+BaseComputeProcessDllPath(IN LPWSTR FullPath,
+ IN PVOID Environment)
+{
+ LPWSTR DllPath = NULL;
+ UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager");
+ UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SafeDllSearchMode");
+ OBJECT_ATTRIBUTES ObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&KeyName, OBJ_CASE_INSENSITIVE);
+ KEY_VALUE_PARTIAL_INFORMATION PartialInfo;
+ HANDLE KeyHandle;
+ NTSTATUS Status;
+ ULONG ResultLength;
+ BASE_CURRENT_DIR_PLACEMENT CurrentDirPlacement, OldCurrentDirPlacement;
+
+ /* Acquire DLL directory lock */
+ RtlEnterCriticalSection(&BaseDllDirectoryLock);
+
+ /* Check if we have a base dll directory */
+ if (BaseDllDirectory.Buffer)
+ {
+ /* Then compute the process path using DLL order (without curdir) */
+ DllPath = BasepComputeProcessPath(BaseDllOrderNoCurrent, FullPath, Environment);
+
+ /* Release DLL directory lock */
+ RtlLeaveCriticalSection(&BaseDllDirectoryLock);
+
+ /* Return dll path */
+ return DllPath;
+ }
+
+ /* Release DLL directory lock */
+ RtlLeaveCriticalSection(&BaseDllDirectoryLock);
+
+ /* Read the current placement */
+ CurrentDirPlacement = BasepDllCurrentDirPlacement;
+ if (CurrentDirPlacement == BaseCurrentDirPlacementInvalid)
+ {
+ /* Open the configuration key */
+ Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
+ if (NT_SUCCESS(Status))
+ {
+ /* Query if safe search is enabled */
+ Status = NtQueryValueKey(KeyHandle,
+ &ValueName,
+ KeyValuePartialInformation,
+ &PartialInfo,
+ sizeof(PartialInfo),
+ &ResultLength);
+ if (NT_SUCCESS(Status))
+ {
+ /* Read the value if the size is OK */
+ if (ResultLength == sizeof(PartialInfo))
+ {
+ CurrentDirPlacement = *(PULONG)PartialInfo.Data;
+ }
+ }
+
+ /* Close the handle */
+ NtClose(KeyHandle);
+
+ /* Validate the registry value */
+ if ((CurrentDirPlacement <= BaseCurrentDirPlacementInvalid) ||
+ (CurrentDirPlacement >= BaseCurrentDirPlacementMax))
+ {
+ /* Default to safe search */
+ CurrentDirPlacement = BaseCurrentDirPlacementSafe;
+ }
+ }
+
+ /* Update the placement and read the old one */
+ OldCurrentDirPlacement = InterlockedCompareExchange((PLONG)&BasepDllCurrentDirPlacement,
+ CurrentDirPlacement,
+ BaseCurrentDirPlacementInvalid);
+ if (OldCurrentDirPlacement != BaseCurrentDirPlacementInvalid)
+ {
+ /* If there already was a placement, use it */
+ CurrentDirPlacement = OldCurrentDirPlacement;
+ }
+ }
+
+ /* Check if the placement is invalid or not set */
+ if ((CurrentDirPlacement <= BaseCurrentDirPlacementInvalid) ||
+ (CurrentDirPlacement >= BaseCurrentDirPlacementMax))
+ {
+ /* Default to safe search */
+ CurrentDirPlacement = BaseCurrentDirPlacementSafe;
+ }
+
+ /* Compute the process path using either normal or safe search */
+ DllPath = BasepComputeProcessPath(BaseDllOrderCurrent[CurrentDirPlacement],
+ FullPath,
+ Environment);
+
+ /* Return dll path */
+ return DllPath;
+}
+
+BOOLEAN
+WINAPI
+CheckForSameCurdir(IN PUNICODE_STRING DirName)
+{
+ PUNICODE_STRING CurDir;
+ USHORT CurLength;
+ BOOLEAN Result;
+ UNICODE_STRING CurDirCopy;
+
+ CurDir = &NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath;
+
+ CurLength = CurDir->Length;
+ if (CurDir->Length <= 6)
+ {
+ if (CurLength != DirName->Length) return FALSE;
+ }
+ else
+ {
+ if ((CurLength - 2) != DirName->Length) return FALSE;
+ }
+
+ RtlAcquirePebLock();
+
+ CurDirCopy = *CurDir;
+ if (CurDirCopy.Length > 6) CurDirCopy.Length -= 2;
+
+ Result = 0;
+
+ if (RtlEqualUnicodeString(&CurDirCopy, DirName, TRUE)) Result = TRUE;
+
+ RtlReleasePebLock();
+
+ return Result;
+}
/*
* Why not use RtlIsNameLegalDOS8Dot3? In fact the actual algorithm body is
/* Sure, any emtpy name is a short name */
if (!Length) return TRUE;
- /* This could be . or .. or somethign else */
+ /* This could be . or .. or something else */
if (*Name == L'.')
{
/* Which one is it */
}
/* Check for illegal characters */
- if ((c > 0x7F) || (IllegalMask[c / 32] && (1 << (c % 32))))
+ if ((c > 0x7F) || (IllegalMask[c / 32] & (1 << (c % 32))))
{
return FALSE;
}
/* Check if this is perhaps an extension? */
- if (c == L'.')
+ if (c == '.')
{
/* Unless the extension is too large or there's more than one */
if ((HasExtension) || (Dots > 3)) return FALSE;
for (i = 0, Dots = Length - 1; i < Length; i++, Dots--)
{
/* Check if this could be an extension */
- if (*FileName == '.')
+ if (FileName[i] == L'.')
{
/* Unlike the short case, we WANT more than one extension, or a long one */
- if ((HasExtension) || (Dots > 3)) return TRUE;
+ if ((HasExtension) || (Dots > 3))
+ {
+ return TRUE;
+ }
HasExtension = TRUE;
}
while (TRUE)
{
/* Loop within the path skipping slashes */
- while ((*Path) && ((*Path == L'\\') || (*Path == L'/'))) Path++;
+ while ((*Path == L'\\') || (*Path == L'/')) Path++;
/* Make sure there's something after the slashes too! */
if (*Path == UNICODE_NULL) break;
- /* Now do the same thing with the last marker */
+ /* Now skip past the file name until we get to the first slash */
p = Path + 1;
- while ((*p) && ((*p == L'\\') || (*p == L'/'))) p++;
+ while ((*p) && ((*p != L'\\') && (*p != L'/'))) p++;
/* Whatever is in between those two is now the file name length */
Length = p - Path;
* Check if it is valid
* Note that !IsShortName != IsLongName, these two functions simply help
* us determine if a conversion is necessary or not.
+ * "Found" really means: "Is a conversion necessary?", hence the "!"
*/
- Found = UseShort ? IsShortName_U(Path, Length) : IsLongName_U(Path, Length);
-
- /* "Found" really means: "Is a conversion necessary?", hence the ! */
- if (!Found)
+ Found = UseShort ? !IsShortName_U(Path, Length) : !IsLongName_U(Path, Length);
+ if (Found)
{
/* It is! did the caller request to know the markers? */
if ((First) && (Last))
}
/* Return if anything was found and valid */
- return !Found;
+ return Found;
}
PWCHAR
WINAPI
-SkipPathTypeIndicator_U(IN PWCHAR Path)
+SkipPathTypeIndicator_U(IN LPWSTR Path)
{
PWCHAR ReturnPath;
ULONG i;
return !NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL;
}
+/* PUBLIC FUNCTIONS ***********************************************************/
+
/*
* @implemented
*/
/*
* @implemented
+ *
+ * NOTE: Many of these A functions may seem to do rather complex A<->W mapping
+ * beyond what you would usually expect. There are two main reasons:
+ *
+ * First, these APIs are subject to the ANSI/OEM File API selection status that
+ * the caller has chosen, so we must use the "8BitString" internal Base APIs.
+ *
+ * Secondly, the Wide APIs (coming from the 9x world) are coded to return the
+ * length of the paths in "ANSI" by dividing their internal Wide character count
+ * by two... this is usually correct when dealing with pure-ASCII codepages but
+ * not necessarily when dealing with MBCS pre-Unicode sets, which NT supports
+ * for CJK, for example.
*/
DWORD
WINAPI
-GetFullPathNameA (
- LPCSTR lpFileName,
- DWORD nBufferLength,
- LPSTR lpBuffer,
- LPSTR *lpFilePart
- )
+GetFullPathNameA(IN LPCSTR lpFileName,
+ IN DWORD nBufferLength,
+ IN LPSTR lpBuffer,
+ IN LPSTR *lpFilePart)
{
- WCHAR BufferW[MAX_PATH];
- PWCHAR FileNameW;
- DWORD ret;
- LPWSTR FilePartW = NULL;
-
- DPRINT("GetFullPathNameA(lpFileName %s, nBufferLength %d, lpBuffer %p, "
- "lpFilePart %p)\n",lpFileName,nBufferLength,lpBuffer,lpFilePart);
-
- if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
- return 0;
+ NTSTATUS Status;
+ PWCHAR Buffer;
+ ULONG PathSize, FilePartSize;
+ ANSI_STRING AnsiString;
+ UNICODE_STRING FileNameString, UniString;
+ PWCHAR LocalFilePart;
+ PWCHAR* FilePart;
+
+ /* If the caller wants filepart, use a local wide buffer since this is A */
+ FilePart = lpFilePart != NULL ? &LocalFilePart : NULL;
+
+ /* Initialize for Quickie */
+ FilePartSize = PathSize = 0;
+ FileNameString.Buffer = NULL;
+
+ /* First get our string in Unicode */
+ Status = Basep8BitStringToDynamicUnicodeString(&FileNameString, lpFileName);
+ if (!NT_SUCCESS(Status)) goto Quickie;
- ret = GetFullPathNameW(FileNameW, MAX_PATH, BufferW, &FilePartW);
+ /* Allocate a buffer to hold teh path name */
+ Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+ 0,
+ MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL));
+ if (!Buffer)
+ {
+ BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
+ goto Quickie;
+ }
- if (!ret)
- return 0;
+ /* Call into RTL to get the full Unicode path name */
+ PathSize = RtlGetFullPathName_U(FileNameString.Buffer,
+ MAX_PATH * sizeof(WCHAR),
+ Buffer,
+ FilePart);
+ if (PathSize <= (MAX_PATH * sizeof(WCHAR)))
+ {
+ /* The buffer will fit, get the real ANSI string size now */
+ Status = RtlUnicodeToMultiByteSize(&PathSize, Buffer, PathSize);
+ if (NT_SUCCESS(Status))
+ {
+ /* Now check if the user wanted file part size as well */
+ if ((PathSize) && (lpFilePart) && (LocalFilePart))
+ {
+ /* Yep, so in this case get the length of the file part too */
+ Status = RtlUnicodeToMultiByteSize(&FilePartSize,
+ Buffer,
+ (LocalFilePart - Buffer) *
+ sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
+ {
+ /* We failed to do that, so fail the whole call */
+ BaseSetLastNTError(Status);
+ PathSize = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Reset the path size since the buffer is not large enough */
+ PathSize = 0;
+ }
- if (ret > MAX_PATH)
- {
- SetLastError(ERROR_FILENAME_EXCED_RANGE);
- return 0;
- }
+ /* Either no path, or local buffer was too small, enter failure code */
+ if (!PathSize) goto Quickie;
- ret = FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1);
+ /* If the *caller's* buffer was too small, fail, but add in space for NULL */
+ if (PathSize >= nBufferLength)
+ {
+ PathSize++;
+ goto Quickie;
+ }
- if (ret < nBufferLength && lpFilePart)
- {
- /* if the path closed with '\', FilePart is NULL */
- if (!FilePartW)
- *lpFilePart=NULL;
- else
- *lpFilePart = (FilePartW - BufferW) + lpBuffer;
- }
+ /* So far so good, initialize a unicode string to convert back to ANSI/OEM */
+ RtlInitUnicodeString(&UniString, Buffer);
+ Status = BasepUnicodeStringTo8BitString(&AnsiString, &UniString, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Final conversion failed, fail the call */
+ BaseSetLastNTError(Status);
+ PathSize = 0;
+ }
+ else
+ {
+ /* Conversion worked, now copy the ANSI/OEM buffer into the buffer */
+ RtlCopyMemory(lpBuffer, AnsiString.Buffer, PathSize + 1);
+ RtlFreeAnsiString(&AnsiString);
- DPRINT("GetFullPathNameA ret: lpBuffer %s lpFilePart %s\n",
- lpBuffer, (lpFilePart == NULL) ? "NULL" : *lpFilePart);
+ /* And finally, did the caller request file part information? */
+ if (lpFilePart)
+ {
+ /* Use the size we computed earlier and add it to the buffer */
+ *lpFilePart = LocalFilePart ? &lpBuffer[FilePartSize] : 0;
+ }
+ }
- return ret;
+Quickie:
+ /* Cleanup and return the path size */
+ if (FileNameString.Buffer) RtlFreeUnicodeString(&FileNameString);
+ if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+ return PathSize;
}
-
/*
* @implemented
*/
IN LPWSTR lpBuffer,
OUT LPWSTR *lpFilePart)
{
+ /* Call Rtl to do the work */
return RtlGetFullPathName_U((LPWSTR)lpFileName,
nBufferLength * sizeof(WCHAR),
lpBuffer,
*/
DWORD
WINAPI
-SearchPathA (
- LPCSTR lpPath,
- LPCSTR lpFileName,
- LPCSTR lpExtension,
- DWORD nBufferLength,
- LPSTR lpBuffer,
- LPSTR *lpFilePart
- )
+SearchPathA(IN LPCSTR lpPath,
+ IN LPCSTR lpFileName,
+ IN LPCSTR lpExtension,
+ IN DWORD nBufferLength,
+ IN LPSTR lpBuffer,
+ OUT LPSTR *lpFilePart)
{
- UNICODE_STRING PathU = { 0, 0, NULL };
- UNICODE_STRING FileNameU = { 0, 0, NULL };
- UNICODE_STRING ExtensionU = { 0, 0, NULL };
- UNICODE_STRING BufferU = { 0, 0, NULL };
- ANSI_STRING Path;
- ANSI_STRING FileName;
- ANSI_STRING Extension;
- ANSI_STRING Buffer;
- PWCHAR FilePartW;
- DWORD RetValue = 0;
- NTSTATUS Status = STATUS_SUCCESS;
-
- if (!lpFileName)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return 0;
- }
+ PUNICODE_STRING FileNameString;
+ UNICODE_STRING PathString, ExtensionString;
+ NTSTATUS Status;
+ ULONG PathSize, FilePartSize, AnsiLength;
+ PWCHAR LocalFilePart, Buffer;
+ PWCHAR* FilePart;
- RtlInitAnsiString (&Path,
- (LPSTR)lpPath);
- RtlInitAnsiString (&FileName,
- (LPSTR)lpFileName);
- RtlInitAnsiString (&Extension,
- (LPSTR)lpExtension);
+ /* If the caller wants filepart, use a local wide buffer since this is A */
+ FilePart = lpFilePart != NULL ? &LocalFilePart : NULL;
- /* convert ansi (or oem) strings to unicode */
- if (bIsFileApiAnsi)
- {
- Status = RtlAnsiStringToUnicodeString (&PathU,
- &Path,
- TRUE);
- if (!NT_SUCCESS(Status))
- goto Cleanup;
+ /* Initialize stuff for Quickie */
+ PathSize = 0;
+ Buffer = NULL;
+ ExtensionString.Buffer = PathString.Buffer = NULL;
- Status = RtlAnsiStringToUnicodeString (&FileNameU,
- &FileName,
- TRUE);
- if (!NT_SUCCESS(Status))
- goto Cleanup;
+ /* Get the UNICODE_STRING file name */
+ FileNameString = Basep8BitStringToStaticUnicodeString(lpFileName);
+ if (!FileNameString) return 0;
- Status = RtlAnsiStringToUnicodeString (&ExtensionU,
- &Extension,
- TRUE);
- if (!NT_SUCCESS(Status))
- goto Cleanup;
- }
- else
- {
- Status = RtlOemStringToUnicodeString (&PathU,
- &Path,
- TRUE);
- if (!NT_SUCCESS(Status))
- goto Cleanup;
- Status = RtlOemStringToUnicodeString (&FileNameU,
- &FileName,
- TRUE);
- if (!NT_SUCCESS(Status))
- goto Cleanup;
+ /* Did the caller specify an extension */
+ if (lpExtension)
+ {
+ /* Yup, convert it into UNICODE_STRING */
+ Status = Basep8BitStringToDynamicUnicodeString(&ExtensionString,
+ lpExtension);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+ }
- Status = RtlOemStringToUnicodeString (&ExtensionU,
- &Extension,
- TRUE);
- if (!NT_SUCCESS(Status))
- goto Cleanup;
+ /* Did the caller specify a path */
+ if (lpPath)
+ {
+ /* Yup, convert it into UNICODE_STRING */
+ Status = Basep8BitStringToDynamicUnicodeString(&PathString, lpPath);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+ }
+
+ /* Allocate our output buffer */
+ Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nBufferLength * sizeof(WCHAR));
+ if (!Buffer)
+ {
+ /* It failed, bail out */
+ BaseSetLastNTError(STATUS_NO_MEMORY);
+ goto Quickie;
+ }
+
+ /* Now run the Wide search with the input buffer lengths */
+ PathSize = SearchPathW(PathString.Buffer,
+ FileNameString->Buffer,
+ ExtensionString.Buffer,
+ nBufferLength,
+ Buffer,
+ FilePart);
+ if (PathSize <= nBufferLength)
+ {
+ /* It fits, but is it empty? If so, bail out */
+ if (!PathSize) goto Quickie;
+
+ /* The length above is inexact, we need it in ANSI */
+ Status = RtlUnicodeToMultiByteSize(&AnsiLength, Buffer, PathSize * sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
+ {
+ /* Conversion failed, fail the call */
+ PathSize = 0;
+ BaseSetLastNTError(Status);
+ goto Quickie;
}
- BufferU.MaximumLength = min(nBufferLength * sizeof(WCHAR), USHRT_MAX);
- BufferU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
- 0,
- BufferU.MaximumLength);
- if (BufferU.Buffer == NULL)
+ /* If the correct ANSI size is too big, return requird length plus a NULL */
+ if (AnsiLength >= nBufferLength)
{
- Status = STATUS_NO_MEMORY;
- goto Cleanup;
+ PathSize = AnsiLength + 1;
+ goto Quickie;
}
- Buffer.MaximumLength = min(nBufferLength, USHRT_MAX);
- Buffer.Buffer = lpBuffer;
+ /* Now apply the final conversion to ANSI */
+ Status = RtlUnicodeToMultiByteN(lpBuffer,
+ nBufferLength - 1,
+ &AnsiLength,
+ Buffer,
+ PathSize * sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
+ {
+ /* Conversion failed, fail the whole call */
+ PathSize = 0;
+ BaseSetLastNTError(STATUS_NO_MEMORY);
+ goto Quickie;
+ }
- RetValue = SearchPathW (NULL == lpPath ? NULL : PathU.Buffer,
- NULL == lpFileName ? NULL : FileNameU.Buffer,
- NULL == lpExtension ? NULL : ExtensionU.Buffer,
- nBufferLength,
- BufferU.Buffer,
- &FilePartW);
+ /* NULL-terminate and return the real ANSI length */
+ lpBuffer[AnsiLength] = ANSI_NULL;
+ PathSize = AnsiLength;
- if (0 != RetValue)
+ /* Now check if the user wanted file part size as well */
+ if (lpFilePart)
{
- BufferU.Length = wcslen(BufferU.Buffer) * sizeof(WCHAR);
- /* convert ansi (or oem) string to unicode */
- if (bIsFileApiAnsi)
- Status = RtlUnicodeStringToAnsiString(&Buffer,
- &BufferU,
- FALSE);
- else
- Status = RtlUnicodeStringToOemString(&Buffer,
- &BufferU,
- FALSE);
-
- if (NT_SUCCESS(Status) && Buffer.Buffer)
+ /* If we didn't get a file part, clear the caller's */
+ if (!LocalFilePart)
+ {
+ *lpFilePart = NULL;
+ }
+ else
+ {
+ /* Yep, so in this case get the length of the file part too */
+ Status = RtlUnicodeToMultiByteSize(&FilePartSize,
+ Buffer,
+ (LocalFilePart - Buffer) *
+ sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
{
- /* nul-terminate ascii string */
- Buffer.Buffer[BufferU.Length / sizeof(WCHAR)] = '\0';
-
- if (NULL != lpFilePart && BufferU.Length != 0)
- {
- *lpFilePart = strrchr (lpBuffer, '\\') + 1;
- }
+ /* We failed to do that, so fail the whole call */
+ BaseSetLastNTError(Status);
+ PathSize = 0;
}
- }
-Cleanup:
- RtlFreeHeap (RtlGetProcessHeap (),
- 0,
- PathU.Buffer);
- RtlFreeHeap (RtlGetProcessHeap (),
- 0,
- FileNameU.Buffer);
- RtlFreeHeap (RtlGetProcessHeap (),
- 0,
- ExtensionU.Buffer);
- RtlFreeHeap (RtlGetProcessHeap (),
- 0,
- BufferU.Buffer);
+ /* Return the file part buffer */
+ *lpFilePart = lpBuffer + FilePartSize;
+ }
+ }
+ }
+ else
+ {
+ /* Our initial buffer guess was too small, allocate a bigger one */
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+ Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize * sizeof(WCHAR));
+ if (!Buffer)
+ {
+ /* Out of memory, fail everything */
+ BaseSetLastNTError(STATUS_NO_MEMORY);
+ goto Quickie;
+ }
- if (!NT_SUCCESS(Status))
+ /* Do the search again -- it will fail, we just want the path size */
+ PathSize = SearchPathW(PathString.Buffer,
+ FileNameString->Buffer,
+ ExtensionString.Buffer,
+ PathSize,
+ Buffer,
+ FilePart);
+ if (!PathSize) goto Quickie;
+
+ /* Convert it to a correct size */
+ Status = RtlUnicodeToMultiByteSize(&PathSize, Buffer, PathSize * sizeof(WCHAR));
+ if (NT_SUCCESS(Status))
{
+ /* Make space for the NULL-char */
+ PathSize++;
+ }
+ else
+ {
+ /* Conversion failed for some reason, fail the call */
BaseSetLastNTError(Status);
- return 0;
+ PathSize = 0;
}
+ }
- return RetValue;
-}
-
-
-/***********************************************************************
- * ContainsPath (Wine name: contains_pathW)
- *
- * Check if the file name contains a path; helper for SearchPathW.
- * A relative path is not considered a path unless it starts with ./ or ../
- */
-static
-BOOL
-ContainsPath(LPCWSTR name)
-{
- if (RtlDetermineDosPathNameType_U(name) != RtlPathTypeRelative) return TRUE;
- if (name[0] != '.') return FALSE;
- if (name[1] == '/' || name[1] == '\\' || name[1] == '\0') return TRUE;
- return (name[1] == '.' && (name[2] == '/' || name[2] == '\\'));
+Quickie:
+ /* Cleanup/complete path */
+ if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+ if (ExtensionString.Buffer) RtlFreeUnicodeString(&ExtensionString);
+ if (PathString.Buffer) RtlFreeUnicodeString(&PathString);
+ return PathSize;
}
-
/*
* @implemented
*/
DWORD
WINAPI
-SearchPathW(LPCWSTR lpPath,
- LPCWSTR lpFileName,
- LPCWSTR lpExtension,
- DWORD nBufferLength,
- LPWSTR lpBuffer,
- LPWSTR *lpFilePart)
+SearchPathW(IN LPCWSTR lpPath,
+ IN LPCWSTR lpFileName,
+ IN LPCWSTR lpExtension,
+ IN DWORD nBufferLength,
+ IN LPWSTR lpBuffer,
+ OUT LPWSTR *lpFilePart)
{
- DWORD ret = 0;
+ UNICODE_STRING FileNameString, ExtensionString, PathString, CallerBuffer;
+ ULONG Flags, LengthNeeded, FilePartSize;
+ NTSTATUS Status;
+ DWORD Result = 0;
+
+ /* Default flags for RtlDosSearchPath_Ustr */
+ Flags = 6;
+
+ /* Clear file part in case we fail */
+ if (lpFilePart) *lpFilePart = NULL;
+
+ /* Initialize path buffer for free later */
+ PathString.Buffer = NULL;
+
+ /* Convert filename to a unicode string and eliminate trailing spaces */
+ RtlInitUnicodeString(&FileNameString, lpFileName);
+ while ((FileNameString.Length >= sizeof(WCHAR)) &&
+ (FileNameString.Buffer[(FileNameString.Length / sizeof(WCHAR)) - 1] == L' '))
+ {
+ FileNameString.Length -= sizeof(WCHAR);
+ }
+
+ /* Was it all just spaces? */
+ if (!FileNameString.Length)
+ {
+ /* Fail out */
+ BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+ goto Quickie;
+ }
+
+ /* Convert extension to a unicode string */
+ RtlInitUnicodeString(&ExtensionString, lpExtension);
- if (!lpFileName || !lpFileName[0])
+ /* Check if the user sent a path */
+ if (lpPath)
{
- SetLastError(ERROR_INVALID_PARAMETER);
- return 0;
+ /* Convert it to a unicode string too */
+ Status = RtlInitUnicodeStringEx(&PathString, lpPath);
+ if (NT_ERROR(Status))
+ {
+ /* Fail if it was too long */
+ BaseSetLastNTError(Status);
+ goto Quickie;
+ }
}
-
- /* If the name contains an explicit path, ignore the path */
- if (ContainsPath(lpFileName))
+ else
{
- /* try first without extension */
- if (RtlDoesFileExists_U(lpFileName))
- return GetFullPathNameW(lpFileName, nBufferLength, lpBuffer, lpFilePart);
-
- if (lpExtension)
+ /* A path wasn't sent, so compute it ourselves */
+ PathString.Buffer = BaseComputeProcessSearchPath();
+ if (!PathString.Buffer)
{
- LPCWSTR p = wcsrchr(lpFileName, '.');
- if (p && !strchr((const char *)p, '/') && !wcschr( p, '\\' ))
- lpExtension = NULL; /* Ignore the specified extension */
+ /* Fail if we couldn't compute it */
+ BaseSetLastNTError(STATUS_NO_MEMORY);
+ goto Quickie;
}
- /* Allocate a buffer for the file name and extension */
- if (lpExtension)
+ /* See how big the computed path is */
+ LengthNeeded = lstrlenW(PathString.Buffer);
+ if (LengthNeeded > UNICODE_STRING_MAX_CHARS)
{
- LPWSTR tmp;
- DWORD len = wcslen(lpFileName) + wcslen(lpExtension);
-
- if (!(tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, (len + 1) * sizeof(WCHAR))))
- {
- SetLastError(ERROR_OUTOFMEMORY);
- return 0;
- }
- wcscpy(tmp, lpFileName);
- wcscat(tmp, lpExtension);
- if (RtlDoesFileExists_U(tmp))
- ret = GetFullPathNameW(tmp, nBufferLength, lpBuffer, lpFilePart);
- RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
+ /* Fail if it's too long */
+ BaseSetLastNTError(STATUS_NAME_TOO_LONG);
+ goto Quickie;
}
+
+ /* Set the path size now that we have it */
+ PathString.MaximumLength = PathString.Length = LengthNeeded * sizeof(WCHAR);
+
+ /* Request SxS isolation from RtlDosSearchPath_Ustr */
+ Flags |= 1;
}
- else if (lpPath && lpPath[0]) /* search in the specified path */
+
+ /* Create the string that describes the output buffer from the caller */
+ CallerBuffer.Length = 0;
+ CallerBuffer.Buffer = lpBuffer;
+
+ /* How much space does the caller have? */
+ if (nBufferLength <= UNICODE_STRING_MAX_CHARS)
+ {
+ /* Add it into the string */
+ CallerBuffer.MaximumLength = nBufferLength * sizeof(WCHAR);
+ }
+ else
{
- ret = RtlDosSearchPath_U(lpPath,
- lpFileName,
- lpExtension,
- nBufferLength * sizeof(WCHAR),
- lpBuffer,
- lpFilePart) / sizeof(WCHAR);
+ /* Caller wants too much, limit it to the maximum length of a string */
+ CallerBuffer.MaximumLength = UNICODE_STRING_MAX_BYTES;
}
- else /* search in the default path */
+
+ /* Call Rtl to do the work */
+ Status = RtlDosSearchPath_Ustr(Flags,
+ &PathString,
+ &FileNameString,
+ &ExtensionString,
+ &CallerBuffer,
+ NULL,
+ NULL,
+ &FilePartSize,
+ &LengthNeeded);
+ if (NT_ERROR(Status))
{
- WCHAR *DllPath = GetDllLoadPath(NULL);
+ /* Check for unusual status codes */
+ if ((Status != STATUS_NO_SUCH_FILE) && (Status != STATUS_BUFFER_TOO_SMALL))
+ {
+ /* Print them out since maybe an app needs fixing */
+ DbgPrint("%s on file %wZ failed; NTSTATUS = %08lx\n",
+ __FUNCTION__,
+ &FileNameString,
+ Status);
+ DbgPrint(" Path = %wZ\n", &PathString);
+ }
- if (DllPath)
+ /* Check if the failure was due to a small buffer */
+ if (Status == STATUS_BUFFER_TOO_SMALL)
{
- ret = RtlDosSearchPath_U(DllPath,
- lpFileName,
- lpExtension,
- nBufferLength * sizeof(WCHAR),
- lpBuffer,
- lpFilePart) / sizeof(WCHAR);
- RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath);
+ /* Check if the length was actually too big for Rtl to work with */
+ Result = LengthNeeded / sizeof(WCHAR);
+ if (Result > 0xFFFFFFFF) BaseSetLastNTError(STATUS_NAME_TOO_LONG);
}
else
{
- SetLastError(ERROR_OUTOFMEMORY);
- return 0;
+ /* Some other error, set the error code */
+ BaseSetLastNTError(Status);
}
}
+ else
+ {
+ /* It worked! Write the file part now */
+ if (lpFilePart) *lpFilePart = &lpBuffer[FilePartSize];
+
+ /* Convert the final result length */
+ Result = CallerBuffer.Length / sizeof(WCHAR);
+ }
- if (!ret) SetLastError(ERROR_FILE_NOT_FOUND);
+Quickie:
+ /* Check if there was a dynamic path stirng to free */
+ if ((PathString.Buffer != lpPath) && (PathString.Buffer))
+ {
+ /* And free it */
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathString.Buffer);
+ }
- return ret;
+ /* Return the final result lenght */
+ return Result;
}
/*
HANDLE FindHandle;
DWORD ReturnLength;
ULONG ErrorMode;
- BOOLEAN Found;
+ BOOLEAN Found = FALSE;
WIN32_FIND_DATAW FindFileData;
/* Initialize so Quickie knows there's nothing to do */
ErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
/* Do a simple check to see if the path exists */
- if (GetFileAttributesW(lpszShortPath) == 0xFFFFFFF)
+ if (GetFileAttributesW(lpszShortPath) == INVALID_FILE_ATTRIBUTES)
{
/* It doesn't, so fail */
ReturnLength = 0;
}
/* Now get a pointer to the actual path, skipping indicators */
- Path = SkipPathTypeIndicator_U((PWCHAR)lpszShortPath);
-
- /* Try to find a file name in there */
- if (Path) Found = FindLFNorSFN_U(Path, &First, &Last, FALSE);
+ Path = SkipPathTypeIndicator_U((LPWSTR)lpszShortPath);
/* Is there any path or filename in there? */
- if (!(Path) || (*Path == UNICODE_NULL) || !(Found))
+ if (!(Path) ||
+ (*Path == UNICODE_NULL) ||
+ !(FindLFNorSFN_U(Path, &First, &Last, FALSE)))
{
/* There isn't, so the long path is simply the short path */
ReturnLength = wcslen(lpszShortPath);
Original = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
if (!Original) goto ErrorQuickie;
- /* Make a copy ofi t */
+ /* Make a copy of it */
RtlMoveMemory(Original, lpszShortPath, Length * sizeof(WCHAR));
/* Compute the new first and last markers */
}
else
{
- PathLength = GetLongPathNameW(LongPathUni.Buffer, ShortPath, PathLength);
+ PathLength = GetShortPathNameW(LongPathUni.Buffer, ShortPath, PathLength);
}
}
HANDLE FindHandle;
DWORD ReturnLength;
ULONG ErrorMode;
- BOOLEAN Found;
+ BOOLEAN Found = FALSE;
WIN32_FIND_DATAW FindFileData;
/* Initialize so Quickie knows there's nothing to do */
ErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
/* Do a simple check to see if the path exists */
- if (GetFileAttributesW(lpszShortPath) == 0xFFFFFFF)
+ if (GetFileAttributesW(lpszLongPath) == INVALID_FILE_ATTRIBUTES)
{
/* Windows checks for an application compatibility flag to allow this */
if (!(NtCurrentPeb()) || !(NtCurrentPeb()->AppCompatFlags.LowPart & 1))
}
/* Now get a pointer to the actual path, skipping indicators */
- Path = SkipPathTypeIndicator_U((PWCHAR)lpszShortPath);
-
- /* Try to find a file name in there */
- if (Path) Found = FindLFNorSFN_U(Path, &First, &Last, TRUE);
+ Path = SkipPathTypeIndicator_U((LPWSTR)lpszLongPath);
/* Is there any path or filename in there? */
- if (!(Path) || (*Path == UNICODE_NULL) || !(Found))
+ if (!(Path) ||
+ (*Path == UNICODE_NULL) ||
+ !(FindLFNorSFN_U(Path, &First, &Last, TRUE)))
{
/* There isn't, so the long path is simply the short path */
ReturnLength = wcslen(lpszLongPath);
/* Is there space for it? */
- if ((cchBuffer > ReturnLength) && (lpszLongPath))
+ if ((cchBuffer > ReturnLength) && (lpszShortPath))
{
/* Make sure the pointers aren't already the same */
if (lpszLongPath != lpszShortPath)
return ReturnLength;
}
+/*
+ * @implemented
+ *
+ * NOTE: Windows returns a dos/short (8.3) path
+ */
+DWORD
+WINAPI
+GetTempPathA(IN DWORD nBufferLength,
+ IN LPSTR lpBuffer)
+{
+ WCHAR BufferW[MAX_PATH];
+ DWORD ret;
+
+ ret = GetTempPathW(MAX_PATH, BufferW);
+
+ if (!ret) return 0;
+
+ if (ret > MAX_PATH)
+ {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return 0;
+ }
+
+ return FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1);
+}
+
+/*
+ * @implemented
+ *
+ * ripped from wine
+ */
+DWORD
+WINAPI
+GetTempPathW(IN DWORD count,
+ IN LPWSTR path)
+{
+ static const WCHAR tmp[] = { 'T', 'M', 'P', 0 };
+ static const WCHAR temp[] = { 'T', 'E', 'M', 'P', 0 };
+ static const WCHAR userprofile[] = { 'U','S','E','R','P','R','O','F','I','L','E',0 };
+ WCHAR tmp_path[MAX_PATH];
+ UINT ret;
+
+ DPRINT("%u,%p\n", count, path);
+
+ if (!(ret = GetEnvironmentVariableW( tmp, tmp_path, MAX_PATH )) &&
+ !(ret = GetEnvironmentVariableW( temp, tmp_path, MAX_PATH )) &&
+ !(ret = GetEnvironmentVariableW( userprofile, tmp_path, MAX_PATH )) &&
+ !(ret = GetWindowsDirectoryW( tmp_path, MAX_PATH )))
+ return 0;
+
+ if (ret > MAX_PATH)
+ {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return 0;
+ }
+
+ ret = GetFullPathNameW(tmp_path, MAX_PATH, tmp_path, NULL);
+ if (!ret) return 0;
+
+ if (ret > MAX_PATH - 2)
+ {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return 0;
+ }
+
+ if (tmp_path[ret-1] != '\\')
+ {
+ tmp_path[ret++] = '\\';
+ tmp_path[ret] = '\0';
+ }
+
+ ret++; /* add space for terminating 0 */
+
+ if (count)
+ {
+ lstrcpynW(path, tmp_path, count);
+ if (count >= ret)
+ ret--; /* return length without 0 */
+ else if (count < 4)
+ path[0] = 0; /* avoid returning ambiguous "X:" */
+ }
+
+ DPRINT("GetTempPathW returning %u, %S\n", ret, path);
+ return ret;
+}
+
+/*
+ * @implemented
+ */
+DWORD
+WINAPI
+GetCurrentDirectoryA(IN DWORD nBufferLength,
+ IN LPSTR lpBuffer)
+{
+ ANSI_STRING AnsiString;
+ NTSTATUS Status;
+ PUNICODE_STRING StaticString;
+ ULONG MaxLength;
+
+ StaticString = &NtCurrentTeb()->StaticUnicodeString;
+
+ MaxLength = nBufferLength;
+ if (nBufferLength >= UNICODE_STRING_MAX_BYTES)
+ {
+ MaxLength = UNICODE_STRING_MAX_BYTES - 1;
+ }
+
+ StaticString->Length = RtlGetCurrentDirectory_U(StaticString->MaximumLength,
+ StaticString->Buffer);
+ Status = RtlUnicodeToMultiByteSize(&nBufferLength,
+ StaticString->Buffer,
+ StaticString->Length);
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ return 0;
+ }
+
+ if (MaxLength <= nBufferLength)
+ {
+ return nBufferLength + 1;
+ }
+
+ AnsiString.Buffer = lpBuffer;
+ AnsiString.MaximumLength = MaxLength;
+ Status = BasepUnicodeStringTo8BitString(&AnsiString, StaticString, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ return 0;
+ }
+
+ return AnsiString.Length;
+}
+
+/*
+ * @implemented
+ */
+DWORD
+WINAPI
+GetCurrentDirectoryW(IN DWORD nBufferLength,
+ IN LPWSTR lpBuffer)
+{
+ return RtlGetCurrentDirectory_U(nBufferLength * sizeof(WCHAR), lpBuffer) / sizeof(WCHAR);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetCurrentDirectoryA(IN LPCSTR lpPathName)
+{
+ PUNICODE_STRING DirName;
+ NTSTATUS Status;
+
+ if (!lpPathName)
+ {
+ BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ DirName = Basep8BitStringToStaticUnicodeString(lpPathName);
+ if (!DirName) return FALSE;
+
+ if (CheckForSameCurdir(DirName)) return TRUE;
+
+ Status = RtlSetCurrentDirectory_U(DirName);
+ if (NT_SUCCESS(Status)) return TRUE;
+
+ if ((*DirName->Buffer != L'"') || (DirName->Length <= 2))
+ {
+ BaseSetLastNTError(Status);
+ return 0;
+ }
+
+ DirName = Basep8BitStringToStaticUnicodeString(lpPathName + 1);
+ if (!DirName) return FALSE;
+
+ Status = RtlSetCurrentDirectory_U(DirName);
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetCurrentDirectoryW(IN LPCWSTR lpPathName)
+{
+ NTSTATUS Status;
+ UNICODE_STRING UnicodeString;
+
+ if (!lpPathName)
+ {
+ BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ Status = RtlInitUnicodeStringEx(&UnicodeString, lpPathName);
+ if (NT_SUCCESS(Status))
+ {
+ if (!CheckForSameCurdir(&UnicodeString))
+ {
+ Status = RtlSetCurrentDirectory_U(&UnicodeString);
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+UINT
+WINAPI
+GetSystemDirectoryA(IN LPSTR lpBuffer,
+ IN UINT uSize)
+{
+ ANSI_STRING AnsiString;
+ NTSTATUS Status;
+ ULONG AnsiLength;
+
+ /* Get the correct size of the Unicode Base directory */
+ Status = RtlUnicodeToMultiByteSize(&AnsiLength,
+ BaseWindowsSystemDirectory.Buffer,
+ BaseWindowsSystemDirectory.MaximumLength);
+ if (!NT_SUCCESS(Status)) return 0;
+
+ if (uSize < AnsiLength) return AnsiLength;
+
+ RtlInitEmptyAnsiString(&AnsiString, lpBuffer, uSize);
+
+ Status = BasepUnicodeStringTo8BitString(&AnsiString,
+ &BaseWindowsSystemDirectory,
+ FALSE);
+ if (!NT_SUCCESS(Status)) return 0;
+
+ return AnsiString.Length;
+}
+
+/*
+ * @implemented
+ */
+UINT
+WINAPI
+GetSystemDirectoryW(IN LPWSTR lpBuffer,
+ IN UINT uSize)
+{
+ ULONG ReturnLength;
+
+ ReturnLength = BaseWindowsSystemDirectory.MaximumLength;
+ if ((uSize * sizeof(WCHAR)) >= ReturnLength)
+ {
+ RtlCopyMemory(lpBuffer,
+ BaseWindowsSystemDirectory.Buffer,
+ BaseWindowsSystemDirectory.Length);
+ lpBuffer[BaseWindowsSystemDirectory.Length / sizeof(WCHAR)] = ANSI_NULL;
+
+ ReturnLength = BaseWindowsSystemDirectory.Length;
+ }
+
+ return ReturnLength / sizeof(WCHAR);
+}
+
+/*
+ * @implemented
+ */
+UINT
+WINAPI
+GetWindowsDirectoryA(IN LPSTR lpBuffer,
+ IN UINT uSize)
+{
+ /* Is this a TS installation? */
+ if (gpTermsrvGetWindowsDirectoryA) UNIMPLEMENTED;
+
+ /* Otherwise, call the System API */
+ return GetSystemWindowsDirectoryA(lpBuffer, uSize);
+}
+
+/*
+ * @implemented
+ */
+UINT
+WINAPI
+GetWindowsDirectoryW(IN LPWSTR lpBuffer,
+ IN UINT uSize)
+{
+ /* Is this a TS installation? */
+ if (gpTermsrvGetWindowsDirectoryW) UNIMPLEMENTED;
+
+ /* Otherwise, call the System API */
+ return GetSystemWindowsDirectoryW(lpBuffer, uSize);
+}
+
+/*
+ * @implemented
+ */
+UINT
+WINAPI
+GetSystemWindowsDirectoryA(IN LPSTR lpBuffer,
+ IN UINT uSize)
+{
+ ANSI_STRING AnsiString;
+ NTSTATUS Status;
+ ULONG AnsiLength;
+
+ /* Get the correct size of the Unicode Base directory */
+ Status = RtlUnicodeToMultiByteSize(&AnsiLength,
+ BaseWindowsDirectory.Buffer,
+ BaseWindowsDirectory.MaximumLength);
+ if (!NT_SUCCESS(Status)) return 0;
+
+ if (uSize < AnsiLength) return AnsiLength;
+
+ RtlInitEmptyAnsiString(&AnsiString, lpBuffer, uSize);
+
+ Status = BasepUnicodeStringTo8BitString(&AnsiString,
+ &BaseWindowsDirectory,
+ FALSE);
+ if (!NT_SUCCESS(Status)) return 0;
+
+ return AnsiString.Length;
+}
+
+/*
+ * @implemented
+ */
+UINT
+WINAPI
+GetSystemWindowsDirectoryW(IN LPWSTR lpBuffer,
+ IN UINT uSize)
+{
+ ULONG ReturnLength;
+
+ ReturnLength = BaseWindowsDirectory.MaximumLength;
+ if ((uSize * sizeof(WCHAR)) >= ReturnLength)
+ {
+ RtlCopyMemory(lpBuffer,
+ BaseWindowsDirectory.Buffer,
+ BaseWindowsDirectory.Length);
+ lpBuffer[BaseWindowsDirectory.Length / sizeof(WCHAR)] = ANSI_NULL;
+
+ ReturnLength = BaseWindowsDirectory.Length;
+ }
+
+ return ReturnLength / sizeof(WCHAR);
+}
+
+/*
+ * @unimplemented
+ */
+UINT
+WINAPI
+GetSystemWow64DirectoryW(IN LPWSTR lpBuffer,
+ IN UINT uSize)
+{
+#ifdef _WIN64
+ UNIMPLEMENTED;
+ return 0;
+#else
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+#endif
+}
+
+/*
+ * @unimplemented
+ */
+UINT
+WINAPI
+GetSystemWow64DirectoryA(IN LPSTR lpBuffer,
+ IN UINT uSize)
+{
+#ifdef _WIN64
+ UNIMPLEMENTED;
+ return 0;
+#else
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+#endif
+}
+
/* EOF */