521 lines
13 KiB
C
521 lines
13 KiB
C
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
curdir.c
|
|
|
|
Abstract:
|
|
|
|
Current directory support
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 10-Oct-1990
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "basedll.h"
|
|
|
|
BOOL
|
|
CheckForSameCurdir(
|
|
PUNICODE_STRING PathName
|
|
)
|
|
{
|
|
PCURDIR CurDir;
|
|
UNICODE_STRING CurrentDir;
|
|
BOOL rv;
|
|
|
|
|
|
CurDir = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
|
|
|
|
if (CurDir->DosPath.Length > 6 ) {
|
|
if ( (CurDir->DosPath.Length-2) != PathName->Length ) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
if ( CurDir->DosPath.Length != PathName->Length ) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
RtlAcquirePebLock();
|
|
|
|
CurrentDir = CurDir->DosPath;
|
|
if ( CurrentDir.Length > 6 ) {
|
|
CurrentDir.Length -= 2;
|
|
}
|
|
rv = FALSE;
|
|
|
|
if ( RtlEqualUnicodeString(&CurrentDir,PathName,TRUE) ) {
|
|
rv = TRUE;
|
|
}
|
|
RtlReleasePebLock();
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
DWORD
|
|
APIENTRY
|
|
GetFullPathNameA(
|
|
LPCSTR lpFileName,
|
|
DWORD nBufferLength,
|
|
LPSTR lpBuffer,
|
|
LPSTR *lpFilePart
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ANSI thunk to GetFullPathNameW
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
ULONG UnicodeLength;
|
|
UNICODE_STRING UnicodeString;
|
|
UNICODE_STRING UnicodeResult;
|
|
ANSI_STRING AnsiResult;
|
|
PWSTR Ubuff;
|
|
PWSTR FilePart;
|
|
PWSTR *FilePartPtr;
|
|
INT PrefixLength = 0;
|
|
|
|
if ( ARGUMENT_PRESENT(lpFilePart) ) {
|
|
FilePartPtr = &FilePart;
|
|
} else {
|
|
FilePartPtr = NULL;
|
|
}
|
|
|
|
if (!Basep8BitStringToDynamicUnicodeString( &UnicodeString, lpFileName )) {
|
|
return 0;
|
|
}
|
|
|
|
Ubuff = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (MAX_PATH<<1) + sizeof(UNICODE_NULL));
|
|
if ( !Ubuff ) {
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
BaseSetLastNTError(STATUS_NO_MEMORY);
|
|
return 0;
|
|
}
|
|
|
|
UnicodeLength = RtlGetFullPathName_U(
|
|
UnicodeString.Buffer,
|
|
(MAX_PATH<<1),
|
|
Ubuff,
|
|
FilePartPtr
|
|
);
|
|
|
|
//
|
|
// UnicodeLength contains the byte count of unicode string.
|
|
// Original code does "UnicodeLength / sizeof(WCHAR)" to get
|
|
// the size of corresponding ansi string.
|
|
// This is correct in SBCS environment. However in DBCS environment,
|
|
// it's definitely WRONG.
|
|
//
|
|
if ( UnicodeLength <= MAX_PATH * sizeof (WCHAR) ) {
|
|
|
|
Status = RtlUnicodeToMultiByteSize(&UnicodeLength, Ubuff, UnicodeLength);
|
|
//
|
|
// At this point, UnicodeLength variable contains
|
|
// Ansi based byte length.
|
|
//
|
|
if ( NT_SUCCESS(Status) ) {
|
|
if ( UnicodeLength && ARGUMENT_PRESENT(lpFilePart) && FilePart != NULL ) {
|
|
INT UnicodePrefixLength;
|
|
|
|
UnicodePrefixLength = (INT)(FilePart - Ubuff) * sizeof(WCHAR);
|
|
Status = RtlUnicodeToMultiByteSize( &PrefixLength,
|
|
Ubuff,
|
|
UnicodePrefixLength );
|
|
//
|
|
// At this point, PrefixLength variable contains
|
|
// Ansi based byte length.
|
|
//
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
BaseSetLastNTError(Status);
|
|
UnicodeLength = 0;
|
|
}
|
|
}
|
|
} else {
|
|
BaseSetLastNTError(Status);
|
|
UnicodeLength = 0;
|
|
}
|
|
} else {
|
|
//
|
|
// we exceed the MAX_PATH limit. we should log the error and
|
|
// return zero. however US code returns the byte count of
|
|
// buffer required and doesn't log any error.
|
|
//
|
|
UnicodeLength = 0;
|
|
}
|
|
if ( UnicodeLength && UnicodeLength < nBufferLength ) {
|
|
RtlInitUnicodeString(&UnicodeResult,Ubuff);
|
|
Status = BasepUnicodeStringTo8BitString(&AnsiResult,&UnicodeResult,TRUE);
|
|
if ( NT_SUCCESS(Status) ) {
|
|
RtlMoveMemory(lpBuffer,AnsiResult.Buffer,UnicodeLength+1);
|
|
RtlFreeAnsiString(&AnsiResult);
|
|
|
|
if ( ARGUMENT_PRESENT(lpFilePart) ) {
|
|
if ( FilePart == NULL ) {
|
|
*lpFilePart = NULL;
|
|
} else {
|
|
*lpFilePart = lpBuffer + PrefixLength;
|
|
}
|
|
}
|
|
} else {
|
|
BaseSetLastNTError(Status);
|
|
UnicodeLength = 0;
|
|
}
|
|
} else {
|
|
if ( UnicodeLength ) {
|
|
UnicodeLength++;
|
|
}
|
|
}
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
RtlFreeHeap(RtlProcessHeap(), 0,Ubuff);
|
|
|
|
return (DWORD)UnicodeLength;
|
|
}
|
|
|
|
DWORD
|
|
APIENTRY
|
|
GetFullPathNameW(
|
|
LPCWSTR lpFileName,
|
|
DWORD nBufferLength,
|
|
LPWSTR lpBuffer,
|
|
LPWSTR *lpFilePart
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to return the fully qualified path name
|
|
corresponding to the specified file name.
|
|
|
|
This function is used to return a fully qualified pathname
|
|
corresponding to the specified filename. It does this by merging
|
|
the current drive and directory together with the specified file
|
|
name. In addition to this, it calculates the address of the file
|
|
name portion of the fully qualified pathname.
|
|
|
|
Arguments:
|
|
|
|
lpFileName - Supplies the file name of the file whose fully
|
|
qualified pathname is to be returned.
|
|
|
|
nBufferLength - Supplies the length in bytes of the buffer that is
|
|
to receive the fully qualified path.
|
|
|
|
lpBuffer - Returns the fully qualified pathname corresponding to the
|
|
specified file.
|
|
|
|
lpFilePart - Returns the address of the last component of the fully
|
|
qualified pathname.
|
|
|
|
Return Value:
|
|
|
|
The return value is the length of the string copied to lpBuffer, not
|
|
including the terminating null character. If the return value is
|
|
greater than nBufferLength, the return value is the size of the buffer
|
|
required to hold the pathname. The return value is zero if the
|
|
function failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
return (DWORD) RtlGetFullPathName_U(
|
|
lpFileName,
|
|
nBufferLength*2,
|
|
lpBuffer,
|
|
lpFilePart
|
|
)/2;
|
|
}
|
|
|
|
|
|
DWORD
|
|
APIENTRY
|
|
GetCurrentDirectoryA(
|
|
DWORD nBufferLength,
|
|
LPSTR lpBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ANSI thunk to GetCurrentDirectoryW
|
|
|
|
--*/
|
|
|
|
{
|
|
PUNICODE_STRING Unicode;
|
|
ANSI_STRING AnsiString;
|
|
NTSTATUS Status;
|
|
DWORD ReturnValue;
|
|
ULONG cbAnsiString;
|
|
|
|
if ( nBufferLength > MAXUSHORT ) {
|
|
nBufferLength = MAXUSHORT-2;
|
|
}
|
|
|
|
Unicode = &NtCurrentTeb()->StaticUnicodeString;
|
|
Unicode->Length = (USHORT)RtlGetCurrentDirectory_U(
|
|
Unicode->MaximumLength,
|
|
Unicode->Buffer
|
|
);
|
|
|
|
//
|
|
// Unicode->Length contains the byte count of unicode string.
|
|
// Original code does "UnicodeLength / sizeof(WCHAR)" to
|
|
// get the size of corresponding ansi string.
|
|
// This is correct in SBCS environment. However in DBCS
|
|
// environment, it's definitely WRONG.
|
|
//
|
|
Status = RtlUnicodeToMultiByteSize( &cbAnsiString, Unicode->Buffer, Unicode->Length );
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
BaseSetLastNTError(Status);
|
|
ReturnValue = 0;
|
|
}
|
|
else {
|
|
if ( nBufferLength > (DWORD)(cbAnsiString ) ) {
|
|
AnsiString.Buffer = lpBuffer;
|
|
AnsiString.MaximumLength = (USHORT)(nBufferLength+1);
|
|
Status = BasepUnicodeStringTo8BitString(&AnsiString,Unicode,FALSE);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
BaseSetLastNTError(Status);
|
|
ReturnValue = 0;
|
|
}
|
|
else {
|
|
ReturnValue = AnsiString.Length;
|
|
}
|
|
}
|
|
else {
|
|
// The return value is the size of the buffer required to hold the
|
|
// pathname (including the terminating null character).
|
|
|
|
ReturnValue = cbAnsiString + 1;
|
|
}
|
|
}
|
|
return ReturnValue;
|
|
}
|
|
|
|
DWORD
|
|
APIENTRY
|
|
GetCurrentDirectoryW(
|
|
DWORD nBufferLength,
|
|
LPWSTR lpBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The current directory for a process can be retreived using
|
|
GetCurrentDirectory.
|
|
|
|
Arguments:
|
|
|
|
nBufferLength - Supplies the length in bytes of the buffer that is to
|
|
receive the current directory string.
|
|
|
|
lpBuffer - Returns the current directory string for the current
|
|
process. The string is a null terminated string and specifies
|
|
the absolute path to the current directory.
|
|
|
|
Return Value:
|
|
|
|
The return value is the length of the string copied to lpBuffer, not
|
|
including the terminating null character. If the return value is
|
|
greater than nBufferLength, the return value is the size of the buffer
|
|
required to hold the pathname. The return value is zero if the
|
|
function failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
return (DWORD)RtlGetCurrentDirectory_U(nBufferLength*2,lpBuffer)/2;
|
|
}
|
|
|
|
|
|
BOOL
|
|
APIENTRY
|
|
SetCurrentDirectoryA(
|
|
LPCSTR lpPathName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ANSI thunk to SetCurrentDirectoryW
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
PUNICODE_STRING Unicode;
|
|
BOOL rv;
|
|
|
|
Unicode = Basep8BitStringToStaticUnicodeString( lpPathName );
|
|
if (Unicode == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !CheckForSameCurdir(Unicode) ) {
|
|
|
|
Status = RtlSetCurrentDirectory_U(Unicode);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// claris works 5.0 has a bug where it doesn't strip leading/trailing
|
|
// quotes properly. It ends up calling SetCurrentDirectoryA with a
|
|
// leading quote, and WinExec with a trailing quote. This error path
|
|
// logic will compensate for the leading quote problem
|
|
//
|
|
if ( Unicode->Buffer[0] == L'"' && Unicode->Length > 2 ) {
|
|
|
|
Unicode = Basep8BitStringToStaticUnicodeString( lpPathName+1 );
|
|
if (Unicode == NULL) {
|
|
return FALSE;
|
|
}
|
|
Status = RtlSetCurrentDirectory_U(Unicode);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
BaseSetLastNTError(Status);
|
|
rv = FALSE;
|
|
}
|
|
else {
|
|
rv = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
BaseSetLastNTError(Status);
|
|
rv = FALSE;
|
|
}
|
|
} else {
|
|
rv = TRUE;
|
|
}
|
|
} else {
|
|
rv = TRUE;
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
BOOL
|
|
APIENTRY
|
|
SetCurrentDirectoryW(
|
|
LPCWSTR lpPathName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The current directory for a process is changed using
|
|
SetCurrentDirectory.
|
|
|
|
Each process has a single current directory. A current directory is
|
|
made up of type parts.
|
|
|
|
- A disk designator either which is either a drive letter followed
|
|
by a colon, or a UNC servername/sharename "\\servername\sharename".
|
|
|
|
- A directory on the disk designator.
|
|
|
|
For APIs that manipulate files, the file names may be relative to
|
|
the current directory. A filename is relative to the entire current
|
|
directory if it does not begin with a disk designator or a path name
|
|
separator. If the file name begins with a path name separator, then
|
|
it is relative to the disk designator of the current directory. If
|
|
a file name begins with a disk designator, than it is a fully
|
|
qualified absolute path name.
|
|
|
|
|
|
The value of lpPathName supplies the current directory. The value
|
|
of lpPathName, may be a relative path name as described above, or a
|
|
fully qualified absolute path name. In either case, the fully
|
|
qualified absolute path name of the specified directory is
|
|
calculated and is stored as the current directory.
|
|
|
|
Arguments:
|
|
|
|
lpPathName - Supplies the pathname of the directory that is to be
|
|
made the current directory.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was successful.
|
|
|
|
FALSE/NULL - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
UNICODE_STRING UnicodeString;
|
|
BOOL rv;
|
|
|
|
RtlInitUnicodeString(&UnicodeString,lpPathName);
|
|
|
|
if ( !CheckForSameCurdir(&UnicodeString) ) {
|
|
|
|
Status = RtlSetCurrentDirectory_U(&UnicodeString);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
BaseSetLastNTError(Status);
|
|
rv = FALSE;
|
|
}
|
|
else {
|
|
rv = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
rv = TRUE;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
APIENTRY
|
|
GetLogicalDrives(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
|
|
|
|
Status = NtQueryInformationProcess( NtCurrentProcess(),
|
|
ProcessDeviceMap,
|
|
&ProcessDeviceMapInfo.Query,
|
|
sizeof( ProcessDeviceMapInfo.Query ),
|
|
NULL
|
|
);
|
|
if (NT_SUCCESS (Status)) {
|
|
if (ProcessDeviceMapInfo.Query.DriveMap == 0) {
|
|
SetLastError(NO_ERROR);
|
|
}
|
|
return ProcessDeviceMapInfo.Query.DriveMap;
|
|
} else {
|
|
BaseSetLastNTError(Status);
|
|
return 0;
|
|
}
|
|
}
|