mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1705 lines
45 KiB
1705 lines
45 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dlldir.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the OS/2 V2.0 directory manipulation API calls
|
|
|
|
Author:
|
|
|
|
Therese Stowell (thereses) 19-Oct-1989
|
|
|
|
Revision History:
|
|
|
|
Yaron Shamir (yarons) 20-May-1991
|
|
Fixed all bug found by Filio test suite (GetCurrentDirectory return
|
|
upper case; various error codes)
|
|
Yaron Shamir (yarons) 22-May-1991
|
|
Converted to Unicode.
|
|
|
|
|
|
--*/
|
|
|
|
#define INCL_OS2V20_ERRORS
|
|
#define INCL_OS2V20_FILESYS
|
|
#include "os2dll.h"
|
|
#include "os2win.h"
|
|
#include <direct.h>
|
|
|
|
VOID
|
|
SetLocalCurrentDirectory(
|
|
PSTRING CurrentDirectoryString,
|
|
HANDLE CurrentDirectoryHandle
|
|
);
|
|
|
|
ULONG
|
|
Od2Oem_getdcwd(
|
|
ULONG DiskNumber,
|
|
LPSTR lpBuffer,
|
|
DWORD nBufferLength
|
|
);
|
|
|
|
ULONG
|
|
Od2Oem_chdrive(
|
|
ULONG DiskNumber
|
|
);
|
|
|
|
ULONG
|
|
Od2Oem_chdir_chdrive(
|
|
LPSTR lpBuffer
|
|
);
|
|
|
|
APIRET
|
|
GetCurrentDirectoryW(
|
|
DWORD nBufferLength,
|
|
LPWSTR lpBuffer
|
|
);
|
|
|
|
APIRET
|
|
Od2GetCurrentDirectory(
|
|
IN ULONG DiskNumber,
|
|
OUT PSTRING *CurrentDirectoryString,
|
|
OUT PHANDLE CurrentDirectoryHandle,
|
|
OUT PULONG DirectoryNameLength,
|
|
IN BOOLEAN Verify
|
|
);
|
|
// DiskName is used by VerifyDriveExists
|
|
|
|
|
|
// BUGBUG at some point, need to read config.sys and set up symbolic links
|
|
// for drives.
|
|
|
|
|
|
APIRET
|
|
VerifyDriveExists(
|
|
IN ULONG DiskNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine verifies that a drive exists
|
|
|
|
Arguments:
|
|
|
|
DiskNumber - 1-based drive number
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR DiskName[] = "\\OS2SS\\DRIVES\\D:\\";
|
|
STRING DiskNameString;
|
|
UNICODE_STRING DiskNameString_U;
|
|
NTSTATUS Status;
|
|
HANDLE DiskHandle;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
APIRET RetCode;
|
|
|
|
DiskName[DRIVE_LETTER+FILE_PREFIX_LENGTH] = (CHAR) (DiskNumber + '@');
|
|
Od2InitMBString(&DiskNameString,DiskName);
|
|
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
RetCode = Od2MBStringToUnicodeString(
|
|
&DiskNameString_U,
|
|
&DiskNameString,
|
|
TRUE);
|
|
|
|
if (RetCode)
|
|
{
|
|
#if DBG
|
|
ASSERT ( FALSE );
|
|
IF_OD2_DEBUG( FILESYS )
|
|
{
|
|
DbgPrint("VerifyDriveExists: no memory for Unicode Conversion\n");
|
|
}
|
|
#endif
|
|
//return STATUS_NO_MEMORY;
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&DiskNameString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
do {
|
|
Status = NtOpenFile(&DiskHandle,
|
|
FILE_READ_DATA | SYNCHRONIZE,
|
|
&Obja,
|
|
&IoStatus,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
// BUGBUG since we're opening the root directory, do we set FILE_DIRECTORY_FILE?
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
} while (RetryCreateOpen(Status, &Obja));
|
|
|
|
RtlFreeUnicodeString (&DiskNameString_U);
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("calling NtOpenFile with %s succeeded.\n",DiskName);
|
|
}
|
|
#endif
|
|
NtClose(DiskHandle);
|
|
}
|
|
else {
|
|
// from dllname.c lines ~1060
|
|
// force return of ERROR_INVALID_DRIVE
|
|
//return (ERROR_INVALID_DRIVE);
|
|
// Fixed by MJarus, 2/16/93 :
|
|
// The previous was done by BeniL since Or2MapStatus
|
|
// returns ERROR_PATH_NOT_FOUND in some cases when
|
|
// it works thru the network
|
|
// But it has to check some special codes (to pass
|
|
// the CT herror)
|
|
if (( Status == STATUS_NO_MEDIA_IN_DEVICE ) ||
|
|
( Status == STATUS_DEVICE_NOT_READY ))
|
|
{
|
|
RetCode = ERROR_NOT_READY;
|
|
} else if ( Status == STATUS_MEDIA_WRITE_PROTECTED )
|
|
{
|
|
RetCode = ERROR_WRITE_PROTECT;
|
|
} else
|
|
{
|
|
RetCode = ERROR_INVALID_DRIVE;
|
|
}
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("calling NtOpenFile with %s failed.\n",DiskName);
|
|
DbgPrint("status is %X, RetCode %lu.\n", Status, RetCode);
|
|
}
|
|
#endif
|
|
}
|
|
return RetCode;
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosSetDefaultDisk(
|
|
IN ULONG DiskNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the current drive for a process
|
|
|
|
Arguments:
|
|
|
|
DiskNumber - 1-based drive number
|
|
|
|
Return Value:
|
|
|
|
ERROR_INVALID_DRIVE - the specified drive doesn't exist
|
|
|
|
--*/
|
|
|
|
{
|
|
PSTRING DirectoryNameString;
|
|
APIRET RetCode;
|
|
ULONG DirectoryLength;
|
|
HANDLE CurDirHandle;
|
|
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosSetDefaultDisk";
|
|
#endif
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS )
|
|
{
|
|
DbgPrint("%s %d \n", RoutineName, DiskNumber);
|
|
}
|
|
#endif
|
|
if (DiskNumber > MAX_DRIVES)
|
|
return ERROR_INVALID_DRIVE;
|
|
RetCode = VerifyDriveExists(DiskNumber);
|
|
if ( RetCode ) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("%s %d Failed on VerifyDriveExists Rc == %lu\n",
|
|
RoutineName, DiskNumber, RetCode);
|
|
}
|
|
#endif
|
|
return (RetCode);
|
|
}
|
|
|
|
//
|
|
// get rid of the old default disk's current directory
|
|
// and set it to the current dir of default disk
|
|
//
|
|
|
|
if (Od2CurrentDisk != DiskNumber-1) {
|
|
if (Od2Oem_chdrive(DiskNumber)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("%s %d Failed on _chdrive\n",
|
|
RoutineName, DiskNumber);
|
|
}
|
|
#endif
|
|
return(ERROR_INVALID_DRIVE);
|
|
}
|
|
RetCode = Od2GetCurrentDirectory(DiskNumber - 1,
|
|
&DirectoryNameString,
|
|
&CurDirHandle,
|
|
&DirectoryLength,
|
|
TRUE
|
|
);
|
|
if (RetCode != NO_ERROR) {
|
|
return(RetCode);
|
|
}
|
|
|
|
AcquireFileLockExclusive(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
SetLocalCurrentDirectory(DirectoryNameString,CurDirHandle);
|
|
Od2CurrentDisk = DiskNumber-1;
|
|
|
|
ReleaseFileLockExclusive(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
RtlFreeHeap(Od2Heap, 0, DirectoryNameString);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosQueryCurrentDisk(
|
|
OUT PULONG DiskNumber,
|
|
OUT PULONG LogicalDrives
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the current drive for a process and a bitmap of
|
|
all existing drives.
|
|
|
|
Arguments:
|
|
|
|
DiskNumber - where to return the current drive
|
|
|
|
LogicalDrives - where to return a bitmap of all existing drives.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG LogicalDrivesMap;
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosQueryCurrentDisk";
|
|
#endif
|
|
|
|
|
|
if (!(LogicalDrivesMap = GetLogicalDrives())) {
|
|
return ERROR_INVALID_DRIVE;
|
|
}
|
|
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
try {
|
|
*DiskNumber = Od2CurrentDisk + 1;
|
|
*LogicalDrives = LogicalDrivesMap;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
LogicalDrivesMap = 0;
|
|
}
|
|
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
if (!LogicalDrivesMap)
|
|
{
|
|
Od2ExitGP();
|
|
return ERROR_INVALID_ADDRESS;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
VOID
|
|
AllocateCurrentDirectory(
|
|
PSTRING CurrentDirectoryString,
|
|
HANDLE CurrentDirectoryHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine saves the current directory for the current drive.
|
|
|
|
Arguments:
|
|
|
|
CurrentDirectoryString - new current directory
|
|
|
|
CurrentDirectoryHandle - handle to new open current directory
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
Note:
|
|
|
|
The caller must have the FileLock.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// if (root dir)
|
|
// pCurDir = NULL;
|
|
//
|
|
|
|
if (CurrentDirectoryString->Length == FILE_PREFIX_LENGTH+ROOTDIRLENGTH) {
|
|
Od2CurrentDirectory.pCurDir = NULL;
|
|
}
|
|
|
|
//
|
|
// else
|
|
// store the dir handle
|
|
// allocate heap space for string and copy it in
|
|
//
|
|
|
|
else {
|
|
Od2CurrentDirectory.NtHandle = CurrentDirectoryHandle;
|
|
|
|
//
|
|
// we allocate space for the CURRENT_DIRECTORY_STRING and the string
|
|
// itself all at once.
|
|
//
|
|
|
|
Od2CurrentDirectory.pCurDir = RtlAllocateHeap(Od2Heap, 0,
|
|
sizeof(CURRENT_DIRECTORY_STRING) +
|
|
CurrentDirectoryString->Length+1); // +1 is for NUL
|
|
if (Od2CurrentDirectory.pCurDir == NULL) {
|
|
#if DBG
|
|
KdPrint(( "OS2: AllocateCurrentDirectory, no memory in Od2Heap\n" ));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
Od2CurrentDirectory.pCurDir->CurDirString.Length =
|
|
CurrentDirectoryString->Length;
|
|
Od2CurrentDirectory.pCurDir->CurDirString.MaximumLength =
|
|
(USHORT) (CurrentDirectoryString->Length+1);
|
|
|
|
//
|
|
// heap space was allocated for string after the CURRENT_DIRECTORY_STRING
|
|
// structure. set up string pointer here (buffer). then copy the
|
|
// string in.
|
|
//
|
|
|
|
Od2CurrentDirectory.pCurDir->CurDirString.Buffer = (PSZ) (((ULONG) (Od2CurrentDirectory.pCurDir)) +
|
|
sizeof(CURRENT_DIRECTORY_STRING));
|
|
RtlMoveMemory(Od2CurrentDirectory.pCurDir->CurDirString.Buffer,
|
|
CurrentDirectoryString->Buffer,
|
|
CurrentDirectoryString->Length+1
|
|
);
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("new current dir is %s\n",Od2CurrentDirectory.pCurDir->CurDirString.Buffer);
|
|
DbgPrint("Length is %d\n",Od2CurrentDirectory.pCurDir->CurDirString.Length);
|
|
DbgPrint("MaximumLength is %d\n",Od2CurrentDirectory.pCurDir->CurDirString.MaximumLength);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FreeCurrentDirectory(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees the current directory for the current drive
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
Note:
|
|
|
|
We let the server free the open handle to the directory.
|
|
|
|
File lock must be acquired BEFORE calling this routine
|
|
|
|
--*/
|
|
|
|
{
|
|
if (Od2CurrentDirectory.pCurDir != NULL) {
|
|
RtlFreeHeap( Od2Heap, 0, Od2CurrentDirectory.pCurDir );
|
|
Od2CurrentDirectory.pCurDir = NULL;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SetLocalCurrentDirectory(
|
|
PSTRING CurrentDirectoryString,
|
|
HANDLE CurrentDirectoryHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees the old current directory for the current drive
|
|
and sets up the new one.
|
|
|
|
Arguments:
|
|
|
|
CurrentDirectoryString - new current directory
|
|
|
|
CurrentDirectoryHandle - handle to new open current directory
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
Note:
|
|
|
|
File lock must be acquired BEFORE calling this routine
|
|
|
|
--*/
|
|
|
|
{
|
|
FreeCurrentDirectory();
|
|
AllocateCurrentDirectory(CurrentDirectoryString,
|
|
CurrentDirectoryHandle
|
|
);
|
|
}
|
|
|
|
|
|
|
|
APIRET
|
|
DosSetCurrentDir(
|
|
IN PSZ DirectoryName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the current directory for a process.
|
|
|
|
Arguments:
|
|
|
|
DirectoryName - new current directory
|
|
|
|
Return Value:
|
|
|
|
ERROR_PATH_NOT_FOUND - new current directory doesn't exist
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - couldn't allocate port memory to hold dirname
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
APIRET RetCode;
|
|
STRING CanonicalNameString;
|
|
UNICODE_STRING CanonicalNameString_U;
|
|
HANDLE DirHandle;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
ULONG DiskNumber;
|
|
ULONG FileType;
|
|
ULONG FileFlags;
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosSetCurrentDir";
|
|
#endif
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("%s: %s\n", RoutineName, DirectoryName);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Canonicalize the directory string
|
|
//
|
|
|
|
RetCode = Od2Canonicalize(DirectoryName,
|
|
CANONICALIZE_FILE_DEV_OR_PIPE,
|
|
&CanonicalNameString,
|
|
NULL,
|
|
&FileFlags,
|
|
&FileType
|
|
);
|
|
if (RetCode != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("%s: Od2Canonicalize returned %d\n",
|
|
RoutineName, RetCode);
|
|
}
|
|
#endif
|
|
return(ERROR_PATH_NOT_FOUND);
|
|
// return RetCode;
|
|
}
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("canonicalize returned %s\n",CanonicalNameString.Buffer);
|
|
}
|
|
#endif
|
|
|
|
if ((FileType & (FILE_TYPE_NMPIPE | FILE_TYPE_DEV | FILE_TYPE_UNC | FILE_TYPE_PSDEV)) ||
|
|
(FileFlags & CANONICALIZE_META_CHARS_FOUND)) {
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("not a filename or metas found\n");
|
|
}
|
|
#endif
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
|
|
ASSERT (CanonicalNameString.Buffer[FILE_PREFIX_LENGTH+COLON] == ':');
|
|
ASSERT (CanonicalNameString.Buffer[FILE_PREFIX_LENGTH+FIRST_SLASH] != '\0');
|
|
|
|
//
|
|
// Open the directory string
|
|
//
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
RetCode = Od2MBStringToUnicodeString(
|
|
&CanonicalNameString_U,
|
|
&CanonicalNameString,
|
|
TRUE);
|
|
if (RetCode)
|
|
{
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS )
|
|
{
|
|
DbgPrint("%s: no memory for Unicode Conversion\n",
|
|
RoutineName);
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
return RetCode;
|
|
}
|
|
|
|
InitializeObjectAttributes(&Obja,
|
|
&CanonicalNameString_U,
|
|
OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
|
|
NULL,
|
|
NULL);
|
|
|
|
do {
|
|
Status = NtOpenFile(&DirHandle,
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
|
&Obja,
|
|
&IoStatus,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
|
|
);
|
|
} while (RetryCreateOpen(Status, &Obja));
|
|
|
|
RtlFreeUnicodeString (&CanonicalNameString_U);
|
|
if (!NT_SUCCESS(Status)) {
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("NtOpenFile failed.\n");
|
|
DbgPrint("St == %X\n",Status);
|
|
}
|
|
#endif
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("NtOpenFile succeeded.\n");
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// now that the file is opened, we need to make sure that it isn't a
|
|
// device or named pipe that Canonicalize didn't detect.
|
|
//
|
|
|
|
if (CheckFileType(DirHandle,FILE_TYPE_NMPIPE | FILE_TYPE_DEV)) {
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
NtClose(DirHandle);
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("not a filename\n");
|
|
}
|
|
#endif
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
|
|
if (CanonicalNameString.Buffer[FILE_PREFIX_LENGTH+DRIVE_LETTER] > 'Z')
|
|
DiskNumber = CanonicalNameString.Buffer[FILE_PREFIX_LENGTH+DRIVE_LETTER] - 'a'; // zero-based drive number
|
|
else
|
|
DiskNumber = CanonicalNameString.Buffer[FILE_PREFIX_LENGTH+DRIVE_LETTER] - 'A'; // zero-based drive number
|
|
|
|
if (Od2Oem_chdir_chdrive(DirectoryName)){
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
NtClose(DirHandle);
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// if the new curdir is the root, we don't keep the handle to it open
|
|
//
|
|
|
|
if (CanonicalNameString.Length == FILE_PREFIX_LENGTH+ROOTDIRLENGTH) { // root directory
|
|
NtClose(DirHandle);
|
|
DirHandle = NULL;
|
|
}
|
|
|
|
NtClose(Od2DirHandles[DiskNumber]);
|
|
Od2DirHandles[DiskNumber] = DirHandle;
|
|
Od2DirHandlesIsValid[DiskNumber] = TRUE;
|
|
|
|
//
|
|
// if the directory was change successfully, we need to
|
|
// update Od2CurrentDirectory because we maintain a copy of
|
|
// that information in the DLL.
|
|
//
|
|
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
if (DiskNumber == Od2CurrentDisk) {
|
|
SetLocalCurrentDirectory(&CanonicalNameString,DirHandle);
|
|
}
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
VOID
|
|
SetUpRootDirectory(
|
|
IN ULONG DiskNumber,
|
|
OUT PSTRING *RootDirectoryString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the "\d:\" where d is the drive letter specified.
|
|
The returned string is allocated from the heap.
|
|
|
|
Arguments:
|
|
|
|
DiskNumber - 0-based drive number
|
|
|
|
RootDirectoryString - where to return the root directory. heap
|
|
space is allocated and the pointer to it is stored here.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR DiskName[] = "\\OS2SS\\DRIVES\\D:\\";
|
|
|
|
DiskName[DRIVE_LETTER+FILE_PREFIX_LENGTH] = (CHAR) (DiskNumber + 'A');
|
|
*RootDirectoryString = RtlAllocateHeap(Od2Heap, 0,
|
|
sizeof(STRING) +
|
|
FILE_PREFIX_LENGTH + DRIVE_LETTER_SIZE + 1
|
|
);
|
|
if (*RootDirectoryString == NULL) {
|
|
#if DBG
|
|
KdPrint(( "OS2: SetUpRootDirectory, no memory in Od2Heap\n" ));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
(*RootDirectoryString)->Length = FILE_PREFIX_LENGTH+DRIVE_LETTER_SIZE;
|
|
(*RootDirectoryString)->MaximumLength = FILE_PREFIX_LENGTH+DRIVE_LETTER_SIZE + 1;
|
|
(*RootDirectoryString)->Buffer = (PSZ) (((ULONG) (*RootDirectoryString)) +
|
|
sizeof(STRING));
|
|
RtlMoveMemory((*RootDirectoryString)->Buffer,
|
|
DiskName,
|
|
FILE_PREFIX_LENGTH+DRIVE_LETTER_SIZE + 1
|
|
);
|
|
}
|
|
|
|
|
|
|
|
APIRET
|
|
Od2GetCurrentDirectory(
|
|
IN ULONG DiskNumber,
|
|
OUT PSTRING *CurrentDirectoryString,
|
|
OUT PHANDLE CurrentDirectoryHandle,
|
|
OUT PULONG DirectoryNameLength,
|
|
IN BOOLEAN Verify
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the current directory for a particular drive.
|
|
The curdir string is returned in an allocated buffer, beginning with
|
|
"\d:\".
|
|
|
|
Arguments:
|
|
|
|
DiskNumber - 0-based drive number
|
|
|
|
CurrentDirectoryString - where to return the current directory. heap
|
|
space is allocated and the pointer to it is stored here.
|
|
|
|
CurrentDirectoryHandle - where to return NT handle to current directory.
|
|
|
|
DirectoryNameLength - on output, length of current directory, not including
|
|
NULL.
|
|
|
|
Verify - whether to verify that path still exists. we do for
|
|
DosQueryCurrentDir. we don't for path canonicalization.
|
|
|
|
Return Value:
|
|
|
|
ERROR_INVALID_DRIVE - specified drive doesn't exist
|
|
|
|
ERROR_BUFFER_OVERFLOW - current directory won't fit in buffer
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE NtDirectoryHandle;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
CHAR DiskName[] = "\\OS2SS\\DRIVES\\D:\\";
|
|
STRING RootDirString;
|
|
NTSTATUS Status;
|
|
APIRET RetCode;
|
|
UNICODE_STRING TmpString_U;
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "GetCurrentDirectory";
|
|
#endif
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("%s: disk # %ld, Current %ld\n",
|
|
RoutineName, DiskNumber, Od2CurrentDisk);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// we maintain the current directory for the current drive in the DLL,
|
|
// so if the requested drive is the current drive, we don't have to
|
|
// call the server.
|
|
//
|
|
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
if (DiskNumber == Od2CurrentDisk) {
|
|
|
|
//
|
|
// verify that current dir still exists. it doesn't matter whether
|
|
// the contents of the drive have changed. if the current directory
|
|
// on floppy a: is "os2\bin" and floppy b: is inserted into the
|
|
// drive, if "os2\bin" exists on floppy b:, the current directory
|
|
// is not changed. if "os2\bin" does not exist on floppy b:, the
|
|
// current directory is set to the root. because we're not trying
|
|
// to verify that the volume hasn't changed, we need to call
|
|
// NtOpenFile, not NtQueryDirectoryFile, because open takes a path
|
|
// rather than a handle.
|
|
//
|
|
// if the current directory is the root, verify that the drive exists.
|
|
//
|
|
|
|
if (Od2CurrentDirectory.pCurDir == NULL) {
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
if (Verify) {
|
|
if (RetCode = VerifyDriveExists(DiskNumber+1)) {
|
|
return (RetCode);
|
|
}
|
|
}
|
|
SetUpRootDirectory(DiskNumber,CurrentDirectoryString);
|
|
if (*CurrentDirectoryString == NULL) {
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
*DirectoryNameLength = FILE_PREFIX_LENGTH+DRIVE_LETTER_SIZE;
|
|
*CurrentDirectoryHandle = NULL;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// if caller wants it, make sure that current directory path exists.
|
|
//
|
|
|
|
if (Verify) {
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
|
|
RetCode = Od2MBStringToUnicodeString(
|
|
&TmpString_U,
|
|
&(Od2CurrentDirectory.pCurDir->CurDirString),
|
|
TRUE);
|
|
|
|
InitializeObjectAttributes(&Obja,
|
|
&TmpString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
do {
|
|
Status = NtOpenFile(&NtDirectoryHandle,
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
|
&Obja,
|
|
&IoStatus,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
|
|
);
|
|
} while (RetryCreateOpen(Status, &Obja));
|
|
RtlFreeUnicodeString (&TmpString_U);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
// current directory path doesn't exist, so
|
|
// set current directory to root. if it fails, ignore the
|
|
// error.
|
|
//
|
|
|
|
DiskName[DRIVE_LETTER+FILE_PREFIX_LENGTH] = (CHAR) (DiskNumber + 'A');
|
|
Od2InitMBString(&RootDirString,DiskName);
|
|
SetLocalCurrentDirectory(&RootDirString,NULL);
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
if (Od2Oem_chdir_chdrive(RootDirString.Buffer)){
|
|
return ERROR_INVALID_DRIVE;
|
|
}
|
|
NtClose(Od2DirHandles[DiskNumber]);
|
|
Od2DirHandles[DiskNumber] = NULL;
|
|
Od2DirHandlesIsValid[DiskNumber] = TRUE;
|
|
if (RetCode = VerifyDriveExists(DiskNumber+1)) {
|
|
return (RetCode);
|
|
}
|
|
else {
|
|
SetUpRootDirectory(DiskNumber,CurrentDirectoryString);
|
|
if (*CurrentDirectoryString == NULL) {
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
*DirectoryNameLength = FILE_PREFIX_LENGTH+DRIVE_LETTER_SIZE;
|
|
*CurrentDirectoryHandle = NULL;
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
NtClose(NtDirectoryHandle);
|
|
}
|
|
|
|
//
|
|
// allocate heap space to return current directory string in
|
|
//
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("current dir is %s\n",Od2CurrentDirectory.pCurDir->CurDirString.Buffer);
|
|
DbgPrint("Length is %d\n",Od2CurrentDirectory.pCurDir->CurDirString.Length);
|
|
DbgPrint("MaximumLength is %d\n",Od2CurrentDirectory.pCurDir->CurDirString.MaximumLength);
|
|
}
|
|
#endif
|
|
|
|
*CurrentDirectoryString = RtlAllocateHeap(Od2Heap, 0,
|
|
sizeof(STRING) +
|
|
Od2CurrentDirectory.pCurDir->CurDirString.Length+1
|
|
);
|
|
if (*CurrentDirectoryString == NULL) {
|
|
#if DBG
|
|
KdPrint(( "OS2: Od2GetCurrentDirectory, no memory in Od2Heap\n" ));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
(*CurrentDirectoryString)->Length =
|
|
Od2CurrentDirectory.pCurDir->CurDirString.Length;
|
|
(*CurrentDirectoryString)->MaximumLength =
|
|
(USHORT) (Od2CurrentDirectory.pCurDir->CurDirString.Length + 1);
|
|
|
|
//
|
|
// heap space was allocated for string after the STRING
|
|
// structure. set up string pointer here (buffer). then copy the
|
|
// string in. don't copy the drive letter.
|
|
//
|
|
|
|
(*CurrentDirectoryString)->Buffer = (PSZ) (((ULONG) (*CurrentDirectoryString)) +
|
|
sizeof(STRING));
|
|
RtlMoveMemory((*CurrentDirectoryString)->Buffer,
|
|
Od2CurrentDirectory.pCurDir->CurDirString.Buffer,
|
|
Od2CurrentDirectory.pCurDir->CurDirString.Length + 1
|
|
);
|
|
|
|
//
|
|
// Upcase string, since OS2 expects this (at least for FAT filesys)
|
|
//
|
|
|
|
RtlUpperString( *CurrentDirectoryString, *CurrentDirectoryString );
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("returning the following current dir string:\n");
|
|
DbgPrint("current dir is %s\n",(*CurrentDirectoryString)->Buffer);
|
|
DbgPrint("Length is %d\n",(*CurrentDirectoryString)->Length);
|
|
DbgPrint("MaximumLength is %d\n",(*CurrentDirectoryString)->MaximumLength);
|
|
}
|
|
#endif
|
|
|
|
*DirectoryNameLength = (*CurrentDirectoryString)->Length;
|
|
*CurrentDirectoryHandle = Od2CurrentDirectory.NtHandle;
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// the requested current directory is not on the current drive.
|
|
//
|
|
|
|
else {
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
*CurrentDirectoryString = RtlAllocateHeap(Od2Heap, 0,
|
|
CCHMAXPATH + sizeof(STRING) + DRIVE_LETTER_SIZE + FILE_PREFIX_LENGTH);
|
|
if (*CurrentDirectoryString == NULL) {
|
|
#if DBG
|
|
KdPrint(( "OS2: Od2GetCurrentDirectory, no memory in Od2Heap\n" ));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
RtlZeroMemory( *CurrentDirectoryString, CCHMAXPATH + sizeof(STRING) + DRIVE_LETTER_SIZE + FILE_PREFIX_LENGTH);
|
|
|
|
if (Od2DirHandlesIsValid[DiskNumber] == FALSE) {
|
|
RetCode = Od2InitCurrentDir(DiskNumber);
|
|
if (RetCode != NO_ERROR) {
|
|
RtlFreeHeap(Od2Heap, 0, *CurrentDirectoryString);
|
|
return(RetCode);
|
|
}
|
|
}
|
|
|
|
(*CurrentDirectoryString)->Buffer = (PSZ) (((ULONG) (*CurrentDirectoryString)) +
|
|
sizeof(STRING));
|
|
RtlMoveMemory((*CurrentDirectoryString)->Buffer, "\\OS2SS\\DRIVES\\", FILE_PREFIX_LENGTH);
|
|
if (Od2Oem_getdcwd((DiskNumber + 1),
|
|
(PSZ) (((*CurrentDirectoryString)->Buffer) + FILE_PREFIX_LENGTH),
|
|
CCHMAXPATH + DRIVE_LETTER_SIZE)) {
|
|
RtlFreeHeap(Od2Heap,0,*CurrentDirectoryString);
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
(*CurrentDirectoryString)->Length = strlen((*CurrentDirectoryString)->Buffer);
|
|
(*CurrentDirectoryString)->MaximumLength = (*CurrentDirectoryString)->Length + 1;
|
|
*DirectoryNameLength = (*CurrentDirectoryString)->Length;
|
|
*CurrentDirectoryHandle = Od2DirHandles[DiskNumber];
|
|
return NO_ERROR;
|
|
}
|
|
ASSERT (FALSE); // should never get here
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosQueryCurrentDir(
|
|
IN ULONG DiskNumber, // 1-based drive number
|
|
OUT PSZ DirectoryName,
|
|
IN OUT PULONG DirectoryNameLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the current directory for a particular drive and
|
|
process.
|
|
|
|
Arguments:
|
|
|
|
DiskNumber - which drive to use
|
|
|
|
DirectoryName - where to return the current directory
|
|
|
|
DirectoryNameLength - on input, length of buffer. on output, length of
|
|
current directory.
|
|
|
|
Return Value:
|
|
|
|
ERROR_INVALID_DRIVE - specified drive doesn't exist
|
|
|
|
ERROR_BUFFER_OVERFLOW - current directory won't fit in buffer
|
|
|
|
--*/
|
|
|
|
{
|
|
PSTRING DirectoryNameString;
|
|
ULONG Disk; // 0-based drive number
|
|
APIRET RetCode;
|
|
ULONG DirectoryLength,BufferLength;
|
|
HANDLE CurDirHandle;
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosQueryCurrentDir";
|
|
#endif
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("%s: drive # %ld\n", RoutineName, DiskNumber);
|
|
}
|
|
#endif
|
|
Disk = DiskNumber-1;
|
|
if (DiskNumber > MAX_DRIVES)
|
|
return ERROR_INVALID_DRIVE;
|
|
else if (DiskNumber == 0) {
|
|
Disk = Od2CurrentDisk;
|
|
}
|
|
try {
|
|
BufferLength = *DirectoryNameLength;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
if( RetCode = VerifyDriveExists(Disk + 1))
|
|
{
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("DosQueryCurrentDir %d Failed on VerifyDriveExists Rc == %lu\n",
|
|
Disk + 1, RetCode);
|
|
}
|
|
#endif
|
|
return (RetCode);
|
|
}
|
|
|
|
RetCode = Od2GetCurrentDirectory(Disk,
|
|
&DirectoryNameString,
|
|
&CurDirHandle,
|
|
&DirectoryLength,
|
|
TRUE
|
|
);
|
|
|
|
if (RetCode != NO_ERROR) {
|
|
return(RetCode);
|
|
}
|
|
|
|
//
|
|
// copy string to user's buffer. GetCurrentDirectory returns the
|
|
// current directory beginning with the drive letter, but the user
|
|
// doesn't get the drive letter, so start copying past it. we test for
|
|
// a non-root directory because we shouldn't touch the user's buffer
|
|
// if it is the root dir.
|
|
//
|
|
|
|
try {
|
|
|
|
//
|
|
// if not root directory, copy name
|
|
//
|
|
DirectoryLength -= (FILE_PREFIX_LENGTH + DRIVE_LETTER_SIZE);
|
|
|
|
if (DirectoryLength >= *DirectoryNameLength) {
|
|
RtlFreeHeap(Od2Heap,0,DirectoryNameString);
|
|
*DirectoryNameLength = DirectoryLength +1;
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
strncpy(DirectoryName,
|
|
DirectoryNameString->Buffer + FILE_PREFIX_LENGTH + DRIVE_LETTER_SIZE,
|
|
DirectoryLength + 1
|
|
);
|
|
*DirectoryNameLength = DirectoryLength +1;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("%s: length %ld and name %s\n",
|
|
RoutineName, *DirectoryNameLength, DirectoryName);
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Od2Heap,0,DirectoryNameString);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosCreateDir(
|
|
IN PSZ DirectoryName,
|
|
IN PEAOP2 DirectoryAttributes OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine makes a directory.
|
|
|
|
Arguments:
|
|
|
|
DirectoryName - name of directory
|
|
|
|
DirectoryAttributes - optional extended attributes for directory
|
|
|
|
Return Value:
|
|
|
|
ERROR_PATH_NOT_FOUND - DirectoryName is a device or pipe name.
|
|
|
|
ERROR_FILE_NOT_FOUND - some component of DirectoryName doesn't exist.
|
|
|
|
Note:
|
|
The FileLock must be acquired in the calling procedure
|
|
|
|
--*/
|
|
|
|
{
|
|
APIRET RetCode;
|
|
STRING CanonicalNameString;
|
|
UNICODE_STRING CanonicalNameString_U;
|
|
ULONG FileType;
|
|
ULONG FileFlags;
|
|
USHORT DeviceAttribute;
|
|
HANDLE DirHandle;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("entering MkDir with %s\n",DirectoryName);
|
|
}
|
|
#endif
|
|
|
|
RetCode = Od2Canonicalize(DirectoryName,
|
|
CANONICALIZE_FILE_DEV_OR_PIPE,
|
|
&CanonicalNameString,
|
|
&DirHandle,
|
|
&FileFlags,
|
|
&FileType
|
|
);
|
|
|
|
if (RetCode != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("CreateDir: Od2Canonicalize returned %d\n", RetCode);
|
|
}
|
|
#endif
|
|
if (RetCode == ERROR_FILE_NOT_FOUND || RetCode == ERROR_INVALID_NAME) {
|
|
RetCode = ERROR_PATH_NOT_FOUND;
|
|
}
|
|
return RetCode;
|
|
}
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("canonicalize returned %s\n",CanonicalNameString.Buffer);
|
|
}
|
|
#endif
|
|
|
|
if (FileType & (FILE_TYPE_NMPIPE | FILE_TYPE_DEV | FILE_TYPE_PSDEV)) {
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
|
|
if (FileFlags & CANONICALIZE_META_CHARS_FOUND) {
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
RetCode = Od2MBStringToUnicodeString(
|
|
&CanonicalNameString_U,
|
|
&CanonicalNameString,
|
|
TRUE);
|
|
|
|
if (RetCode)
|
|
{
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS )
|
|
{
|
|
DbgPrint("DosCreateDir: no memory for Unicode Conversion\n");
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
return RetCode;
|
|
}
|
|
|
|
InitializeObjectAttributes(&Obja,
|
|
&CanonicalNameString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
DirHandle,
|
|
NULL);
|
|
|
|
RetCode = OpenCreatePath(&DirHandle,
|
|
FILE_WRITE_EA | SYNCHRONIZE,
|
|
&Obja,
|
|
&IoStatus,
|
|
0L,
|
|
0L,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_CREATE,
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
|
|
DirectoryAttributes,
|
|
(PUSHORT) &FileType,
|
|
&DeviceAttribute,
|
|
TRUE
|
|
);
|
|
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
RtlFreeUnicodeString (&CanonicalNameString_U);
|
|
|
|
if (RetCode != NO_ERROR)
|
|
{
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS )
|
|
{
|
|
DbgPrint("DosCreateDir: OpenCreatePath returned %ld\n",RetCode);
|
|
}
|
|
#endif
|
|
if (RetCode == ERROR_INVALID_NAME)
|
|
{
|
|
RetCode = ERROR_PATH_NOT_FOUND;
|
|
}
|
|
return RetCode;
|
|
}
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS )
|
|
{
|
|
DbgPrint("NtCreateFile successful\n");
|
|
}
|
|
#endif
|
|
|
|
NtClose(DirHandle);
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS )
|
|
{
|
|
DbgPrint("mkdir successful\n");
|
|
}
|
|
#endif
|
|
return NO_ERROR;
|
|
}
|
|
|
|
APIRET
|
|
DeleteObject(
|
|
IN PSZ ObjectName,
|
|
IN ULONG ObjectType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes a file or directory object.
|
|
|
|
Arguments:
|
|
|
|
ObjectName - name of directory
|
|
|
|
ObjectType - type of object to delete
|
|
|
|
Return Value:
|
|
|
|
TBS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
APIRET RetCode = NO_ERROR;
|
|
STRING CanonicalNameString;
|
|
WCHAR CurrentDirectory_U[CCHMAXPATH];
|
|
CHAR CurrentDirectory_A[CCHMAXPATH];
|
|
STRING CanonicalCurrentDirectory;
|
|
ANSI_STRING str_a;
|
|
UNICODE_STRING str_u;
|
|
UNICODE_STRING CanonicalNameString_U;
|
|
ULONG FileType;
|
|
ULONG FileFlags;
|
|
HANDLE ObjHandle;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
FILE_DISPOSITION_INFORMATION FileDispInfo;
|
|
|
|
RetCode = Od2Canonicalize(ObjectName,
|
|
CANONICALIZE_FILE_DEV_OR_PIPE,
|
|
&CanonicalNameString,
|
|
&ObjHandle,
|
|
&FileFlags,
|
|
&FileType
|
|
);
|
|
if (RetCode != NO_ERROR)
|
|
{
|
|
if ((RetCode != ERROR_FILENAME_EXCED_RANGE)
|
|
&& (RetCode != ERROR_NOT_READY)
|
|
&& (RetCode != ERROR_WRITE_PROTECT)
|
|
/* && (RetCode != ERROR_FILE_NOT_FOUND) */
|
|
)
|
|
{
|
|
RetCode = ERROR_PATH_NOT_FOUND;
|
|
}
|
|
return RetCode;
|
|
}
|
|
|
|
//
|
|
// Special handling of <boot-drive>:\config.sys
|
|
// opening this file is mapped to the OS/2 SS config.sys
|
|
//
|
|
if (Od2FileIsConfigSys(&CanonicalNameString, OPEN_ACCESS_READWRITE, &Status))
|
|
{
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
// failed to init for config.sys
|
|
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
return Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
FileFlags = 0;
|
|
FileType = FILE_TYPE_FILE;
|
|
ObjHandle = NULL;
|
|
}
|
|
|
|
if (FileFlags & CANONICALIZE_META_CHARS_FOUND)
|
|
{
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
if (FileFlags & CANONICALIZE_IS_ROOT_DIRECTORY)
|
|
{
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS )
|
|
{
|
|
DbgPrint("canonicalize returned %s\n",CanonicalNameString.Buffer);
|
|
}
|
|
#endif
|
|
|
|
if (FileType & (FILE_TYPE_NMPIPE | FILE_TYPE_DEV | FILE_TYPE_PSDEV)) {
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
|
|
RetCode = Od2MBStringToUnicodeString(
|
|
&CanonicalNameString_U,
|
|
&CanonicalNameString,
|
|
TRUE);
|
|
if (RetCode)
|
|
{
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS )
|
|
{
|
|
DbgPrint("DeleteObject: no memory for Unicode Conversion\n");
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
return RetCode;
|
|
}
|
|
|
|
InitializeObjectAttributes(&Obja,
|
|
&CanonicalNameString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
ObjHandle,
|
|
NULL);
|
|
|
|
do {
|
|
Status = NtOpenFile(&ObjHandle,
|
|
DELETE,
|
|
&Obja,
|
|
&IoStatus,
|
|
0,
|
|
ObjectType
|
|
);
|
|
} while (RetryCreateOpen(Status, &Obja));
|
|
|
|
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
|
|
RtlFreeUnicodeString (&CanonicalNameString_U);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("NtOpenFile returned %X\n",Status);
|
|
}
|
|
#endif
|
|
switch (Status) {
|
|
case STATUS_OBJECT_NAME_INVALID:
|
|
//
|
|
// BUGBUG - This error code can appear in (at least) two
|
|
// cases: abc.lkjlkj (FAT only, need to be mapped to EXCEED_RANGE)
|
|
// or .a (FAT only, needs to be mapped to PATH_NOT_FOUND).
|
|
// NtOpen returns to the same status - we need to check
|
|
// the pathname to determine the problem.
|
|
//
|
|
return (ERROR_PATH_NOT_FOUND);
|
|
|
|
case STATUS_OBJECT_PATH_SYNTAX_BAD:
|
|
if (ObjectType == FILE_NON_DIRECTORY_FILE) {
|
|
return (ERROR_FILE_NOT_FOUND);
|
|
}
|
|
else {
|
|
return (ERROR_PATH_NOT_FOUND);
|
|
}
|
|
|
|
case STATUS_SHARING_VIOLATION:
|
|
if (ObjectType == FILE_DIRECTORY_FILE) {
|
|
GetCurrentDirectoryW((DWORD)(sizeof(CurrentDirectory_U)), CurrentDirectory_U);
|
|
|
|
//
|
|
// convert UNICODE-STRING to ANSI-STRING
|
|
//
|
|
RtlInitUnicodeString(&str_u, (PWSTR) CurrentDirectory_U);
|
|
str_a.Buffer = CurrentDirectory_A;
|
|
str_a.MaximumLength = sizeof(CurrentDirectory_A);
|
|
Od2UnicodeStringToMBString(&str_a, &str_u, FALSE);
|
|
CurrentDirectory_A[str_a.Length] = '\0';
|
|
|
|
Od2Canonicalize(CurrentDirectory_A,
|
|
CANONICALIZE_FILE_OR_DEV,
|
|
&CanonicalCurrentDirectory,
|
|
&ObjHandle,
|
|
&FileFlags,
|
|
&FileType
|
|
);
|
|
if (!strcmp(CanonicalNameString.Buffer, CanonicalCurrentDirectory.Buffer)) {
|
|
return (ERROR_CURRENT_DIRECTORY);
|
|
}
|
|
}
|
|
return (ERROR_SHARING_VIOLATION);
|
|
|
|
default:
|
|
return (Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND));
|
|
}
|
|
}
|
|
|
|
//
|
|
// now that the file is opened, we need to make sure that it isn't a
|
|
// device or named pipe that Canonicalize didn't detect.
|
|
//
|
|
|
|
if (CheckFileType(ObjHandle,FILE_TYPE_NMPIPE | FILE_TYPE_DEV)) {
|
|
NtClose(ObjHandle);
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("not a file/dir name\n");
|
|
}
|
|
#endif
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
|
|
// //
|
|
// // ObjectType is FILE_DIRECTORY_FILE or NULL. If it's FILE..., NtOpenFile
|
|
// // will fail if the path isn't a directory. If it's NULL, we need to
|
|
// // verify that the path is a file.
|
|
// //
|
|
//
|
|
// if (ObjectType == 0) {
|
|
// Status = NtQueryInformationFile(ObjHandle,
|
|
// &IoStatus,
|
|
// &FileStandardInfo,
|
|
// sizeof (FileStandardInfo),
|
|
// FileStandardInformation);
|
|
// ASSERT( NT_SUCCESS( Status ) );
|
|
// if (FileStandardInfo.Directory) {
|
|
// NtClose(ObjHandle);
|
|
// return ERROR_ACCESS_DENIED;
|
|
// }
|
|
// }
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("NtOpenFile successful\n");
|
|
DbgPrint("value of iostatus.info is %ld\n",IoStatus.Information);
|
|
}
|
|
#endif
|
|
|
|
FileDispInfo.DeleteFile = TRUE;
|
|
do {
|
|
Status = NtSetInformationFile(ObjHandle,
|
|
&IoStatus,
|
|
(PVOID) &FileDispInfo,
|
|
sizeof (FileDispInfo),
|
|
FileDispositionInformation
|
|
);
|
|
} while (RetryIO(Status, ObjHandle));
|
|
NtClose(ObjHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("NtSetInformationFile returned %X\n",Status);
|
|
}
|
|
#endif
|
|
return (Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND));
|
|
}
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("NtSetInformationFile successful\n");
|
|
}
|
|
#endif
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosDeleteDir(
|
|
IN PSZ DirectoryName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes a directory.
|
|
|
|
Arguments:
|
|
|
|
DirectoryName - name of directory
|
|
|
|
Return Value:
|
|
|
|
ERROR_PATH_NOT_FOUND - DirectoryName is a device or pipe name.
|
|
|
|
ERROR_FILE_NOT_FOUND - some component of DirectoryName doesn't exist.
|
|
|
|
--*/
|
|
|
|
{
|
|
APIRET RetCode;
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("entering RmDir with %s\n",DirectoryName);
|
|
}
|
|
#endif
|
|
RetCode = DeleteObject(DirectoryName,FILE_DIRECTORY_FILE);
|
|
if (RetCode == ERROR_FILE_NOT_FOUND) {
|
|
return(ERROR_PATH_NOT_FOUND);
|
|
}
|
|
return RetCode;
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosQueryVerify(
|
|
OUT PBOOL32 Verify
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the value of the Verify flag.
|
|
|
|
Arguments:
|
|
|
|
Verify - where to return the value of verify.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
try {
|
|
*Verify = (BOOL32) VerifyFlag;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosSetVerify(
|
|
IN BOOL32 Verify
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the value of the Verify flag.
|
|
|
|
Arguments:
|
|
|
|
Verify - new value of verify flag
|
|
|
|
Return Value:
|
|
|
|
ERROR_INVALID_VERIFY_SWITCH - new value of verify flag is invalid.
|
|
|
|
--*/
|
|
|
|
{
|
|
if ((Verify != TRUE) && (Verify != FALSE))
|
|
return ERROR_INVALID_VERIFY_SWITCH;
|
|
VerifyFlag = (BOOLEAN) Verify;
|
|
return NO_ERROR;
|
|
}
|