/* GLOBALS ********************************************************************/
-UNICODE_STRING BaseDllDirectory;
UNICODE_STRING NoDefaultCurrentDirectoryInExePath = RTL_CONSTANT_STRING(L"NoDefaultCurrentDirectoryInExePath");
-UNICODE_STRING SystemDirectory;
-UNICODE_STRING WindowsDirectory;
-UNICODE_STRING BaseDefaultPathAppend;
-UNICODE_STRING BaseDefaultPath;
+
+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 */
0x10000000 // 7C not allowed
};
+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
* identical (other than the Rtl can optionally check for spaces), however the
}
/* 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;
}
PWCHAR
WINAPI
-SkipPathTypeIndicator_U(IN PWCHAR Path)
+SkipPathTypeIndicator_U(IN LPWSTR Path)
{
PWCHAR ReturnPath;
ULONG i;
if (!PathSize) goto Quickie;
/* If the *caller's* buffer was too small, fail, but add in space for NULL */
- if (PathSize < nBufferLength)
+ if (PathSize >= nBufferLength)
{
PathSize++;
goto Quickie;
return PathSize;
}
-/***********************************************************************
- * 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] == '\\'));
-}
-
-
/*
* @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;
- if (!lpFileName || !lpFileName[0])
+ /* 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' '))
{
- SetLastError(ERROR_INVALID_PARAMETER);
- return 0;
+ FileNameString.Length -= sizeof(WCHAR);
}
- /* If the name contains an explicit path, ignore the path */
- if (ContainsPath(lpFileName))
+ /* Was it all just spaces? */
+ if (!FileNameString.Length)
{
- /* try first without extension */
- if (RtlDoesFileExists_U(lpFileName))
- return GetFullPathNameW(lpFileName, nBufferLength, lpBuffer, lpFilePart);
+ /* Fail out */
+ BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+ goto Quickie;
+ }
+
+ /* Convert extension to a unicode string */
+ RtlInitUnicodeString(&ExtensionString, lpExtension);
- if (lpExtension)
+ /* Check if the user sent a path */
+ if (lpPath)
+ {
+ /* Convert it to a unicode string too */
+ Status = RtlInitUnicodeStringEx(&PathString, lpPath);
+ if (NT_ERROR(Status))
{
- LPCWSTR p = wcsrchr(lpFileName, '.');
- if (p && !strchr((const char *)p, '/') && !wcschr( p, '\\' ))
- lpExtension = NULL; /* Ignore the specified extension */
+ /* Fail if it was too long */
+ BaseSetLastNTError(Status);
+ goto Quickie;
}
-
- /* Allocate a buffer for the file name and extension */
- if (lpExtension)
+ }
+ else
+ {
+ /* A path wasn't sent, so compute it ourselves */
+ PathString.Buffer = BaseComputeProcessSearchPath();
+ if (!PathString.Buffer)
{
- LPWSTR tmp;
- DWORD len = wcslen(lpFileName) + wcslen(lpExtension);
+ /* Fail if we couldn't compute it */
+ BaseSetLastNTError(STATUS_NO_MEMORY);
+ goto Quickie;
+ }
- 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);
+ /* See how big the computed path is */
+ LengthNeeded = lstrlenW(PathString.Buffer);
+ if (LengthNeeded > UNICODE_STRING_MAX_CHARS)
+ {
+ /* 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)
{
- ret = RtlDosSearchPath_U(lpPath,
- lpFileName,
- lpExtension,
- nBufferLength * sizeof(WCHAR),
- lpBuffer,
- lpFilePart) / sizeof(WCHAR);
+ /* Add it into the string */
+ CallerBuffer.MaximumLength = nBufferLength * sizeof(WCHAR);
}
- else /* search in the default path */
+ else
{
- WCHAR *DllPath = GetDllLoadPath(NULL);
+ /* Caller wants too much, limit it to the maximum length of a string */
+ CallerBuffer.MaximumLength = UNICODE_STRING_MAX_BYTES;
+ }
- if (DllPath)
+ /* Call Rtl to do the work */
+ Status = RtlDosSearchPath_Ustr(Flags,
+ &PathString,
+ &FileNameString,
+ &ExtensionString,
+ &CallerBuffer,
+ NULL,
+ NULL,
+ &FilePartSize,
+ &LengthNeeded);
+ if (NT_ERROR(Status))
+ {
+ /* Check for unusual status codes */
+ if ((Status != STATUS_NO_SUCH_FILE) && (Status != STATUS_BUFFER_TOO_SMALL))
{
- ret = RtlDosSearchPath_U(DllPath,
- lpFileName,
- lpExtension,
- nBufferLength * sizeof(WCHAR),
- lpBuffer,
- lpFilePart) / sizeof(WCHAR);
- RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath);
+ /* 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);
+ }
+
+ /* Check if the failure was due to a small buffer */
+ if (Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ /* 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 */
}
/* 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 */
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) == INVALID_FILE_ATTRIBUTES)
+ 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
- */
-DWORD
-WINAPI
-GetCurrentDirectoryA(IN DWORD nBufferLength,
- IN LPSTR lpBuffer)
-{
- WCHAR BufferW[MAX_PATH];
- DWORD ret;
-
- ret = GetCurrentDirectoryW(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
- */
-DWORD
-WINAPI
-GetCurrentDirectoryW(IN DWORD nBufferLength,
- IN LPWSTR lpBuffer)
-{
- ULONG Length;
-
- Length = RtlGetCurrentDirectory_U (nBufferLength * sizeof(WCHAR), lpBuffer);
- return (Length / sizeof (WCHAR));
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-SetCurrentDirectoryA(IN LPCSTR lpPathName)
-{
- PWCHAR PathNameW;
-
- DPRINT("setcurrdir: %s\n",lpPathName);
-
- if (!(PathNameW = FilenameA2W(lpPathName, FALSE))) return FALSE;
-
- return SetCurrentDirectoryW(PathNameW);
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-SetCurrentDirectoryW(IN LPCWSTR lpPathName)
-{
- UNICODE_STRING UnicodeString;
- NTSTATUS Status;
-
- RtlInitUnicodeString(&UnicodeString, lpPathName);
-
- Status = RtlSetCurrentDirectory_U(&UnicodeString);
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError (Status);
- return FALSE;
- }
-
- return TRUE;
-}
-
/*
* @implemented
*
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
*/
GetSystemDirectoryA(IN LPSTR lpBuffer,
IN UINT uSize)
{
- return FilenameU2A_FitOrFail(lpBuffer, uSize, &SystemDirectory);
+ 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;
}
/*
GetSystemDirectoryW(IN LPWSTR lpBuffer,
IN UINT uSize)
{
- ULONG Length;
-
- Length = SystemDirectory.Length / sizeof (WCHAR);
+ ULONG ReturnLength;
- if (lpBuffer == NULL) return Length + 1;
-
- if (uSize > Length)
+ ReturnLength = BaseWindowsSystemDirectory.MaximumLength;
+ if ((uSize * sizeof(WCHAR)) >= ReturnLength)
{
- memmove(lpBuffer, SystemDirectory.Buffer, SystemDirectory.Length);
- lpBuffer[Length] = 0;
+ RtlCopyMemory(lpBuffer,
+ BaseWindowsSystemDirectory.Buffer,
+ BaseWindowsSystemDirectory.Length);
+ lpBuffer[BaseWindowsSystemDirectory.Length / sizeof(WCHAR)] = ANSI_NULL;
- return Length; //good: ret chars excl. nullchar
+ ReturnLength = BaseWindowsSystemDirectory.Length;
}
- return Length+1; //bad: ret space needed incl. nullchar
+ return ReturnLength / sizeof(WCHAR);
}
/*
GetWindowsDirectoryA(IN LPSTR lpBuffer,
IN UINT uSize)
{
- return FilenameU2A_FitOrFail(lpBuffer, uSize, &WindowsDirectory);
+ /* Is this a TS installation? */
+ if (gpTermsrvGetWindowsDirectoryA) UNIMPLEMENTED;
+
+ /* Otherwise, call the System API */
+ return GetSystemWindowsDirectoryA(lpBuffer, uSize);
}
/*
GetWindowsDirectoryW(IN LPWSTR lpBuffer,
IN UINT uSize)
{
- ULONG Length;
-
- Length = WindowsDirectory.Length / sizeof (WCHAR);
-
- if (lpBuffer == NULL) return Length + 1;
-
- if (uSize > Length)
- {
- memmove(lpBuffer, WindowsDirectory.Buffer, WindowsDirectory.Length);
- lpBuffer[Length] = 0;
+ /* Is this a TS installation? */
+ if (gpTermsrvGetWindowsDirectoryW) UNIMPLEMENTED;
- return Length; //good: ret chars excl. nullchar
- }
-
- return Length+1; //bad: ret space needed incl. nullchar
+ /* Otherwise, call the System API */
+ return GetSystemWindowsDirectoryW(lpBuffer, uSize);
}
/*
GetSystemWindowsDirectoryA(IN LPSTR lpBuffer,
IN UINT uSize)
{
- return GetWindowsDirectoryA(lpBuffer, 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;
}
/*
GetSystemWindowsDirectoryW(IN LPWSTR lpBuffer,
IN UINT uSize)
{
- return GetWindowsDirectoryW(lpBuffer, 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);
}
/*