/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
dllhandl.c
Abstract:
This module implements the OS/2 V2.0 file handle manipulation API calls
Author:
Therese Stowell (thereses) 19-Oct-1989
Revision History:
Yaron Shamir (yarons) 20-May-1991
fix bugs found by fileio test suite (map error code in OpenCreatePath)
--*/
//
// Serialization
//
// File I/O must be serialized in three ways:
// 1) on a per-file basis to prevent disk corruption
// 2) on a per-open instance basis to prevent corruption of
// the file pointer and other per open instance data and
// to prevent one thread from closing the handle while
// another thread is performing a handle-based operation
// 3) on a per-process basis to prevent corruption of the file
// handle table.
//
// The NT IO system performs the first two types of serialization when
// synchronous IO mode is used. The OS/2 subsystem performs the third
// type of serialization using a spin lock, AcquireFileLock(). This
// lock allows multiple readers and one writer.
//
// BUGBUG to speed up some calls, store access in handle table
#define INCL_OS2V20_ERRORS
#define INCL_OS2V20_FILESYS
#include "os2dll.h"
#include "conrqust.h"
NTSTATUS
Od2AlertableWaitForSingleObject(
IN HANDLE handle
);
OS2IO_VECTORS NulVectors = {
NulOpenRoutine,
NonFileSetHandleStateRoutine,
DeviceQueryHTypeRoutine,
DeviceCloseRoutine,
DeviceDupHandleRoutine,
NulReadRoutine,
NulWriteRoutine
};
OS2IO_VECTORS ConVectors = {
ConOpenRoutine,
NonFileSetHandleStateRoutine,
DeviceQueryHTypeRoutine,
DeviceCloseRoutine,
DeviceDupHandleRoutine,
ConReadRoutine,
ScreenWriteRoutine
};
OS2IO_VECTORS ComVectors = {
ComOpenRoutine,
NonFileSetHandleStateRoutine,
DeviceQueryHTypeRoutine,
ComCloseRoutine,
ComDupHandleRoutine,
ComReadRoutine,
ComWriteRoutine
};
OS2IO_VECTORS LptVectors = {
LptOpenRoutine,
NonFileSetHandleStateRoutine,
DeviceQueryHTypeRoutine,
DeviceCloseRoutine,
DeviceDupHandleRoutine,
TmpReadRoutine,
TmpWriteRoutine
// LptReadRoutine,
// LptWriteRoutine
};
OS2IO_VECTORS KbdVectors = {
KbdOpenRoutine,
NonFileSetHandleStateRoutine,
DeviceQueryHTypeRoutine,
KbdCloseRoutine,
KbdDupHandleRoutine,
KbdReadRoutine,
NulWriteRoutine
};
OS2IO_VECTORS MouseVectors = {
MouseOpenRoutine,
NonFileSetHandleStateRoutine,
DeviceQueryHTypeRoutine,
MouseCloseRoutine,
MouseDupHandleRoutine,
TmpReadRoutine,
TmpWriteRoutine
// MouseReadRoutine,
// MouseWriteRoutine
};
OS2IO_VECTORS ClockVectors = {
ClockOpenRoutine,
NonFileSetHandleStateRoutine,
DeviceQueryHTypeRoutine,
DeviceCloseRoutine,
DeviceDupHandleRoutine,
TmpReadRoutine,
TmpWriteRoutine
// ClockReadRoutine,
// ClockWriteRoutine
};
OS2IO_VECTORS ScreenVectors = {
ScreenOpenRoutine,
NonFileSetHandleStateRoutine,
DeviceQueryHTypeRoutine,
DeviceCloseRoutine,
DeviceDupHandleRoutine,
NulReadRoutine,
ScreenWriteRoutine
// ScreenReadRoutine,
// ScreenWriteRoutine
};
OS2IO_VECTORS PointerVectors = {
PointerOpenRoutine,
NonFileSetHandleStateRoutine,
DeviceQueryHTypeRoutine,
DeviceCloseRoutine,
DeviceDupHandleRoutine,
TmpReadRoutine,
TmpWriteRoutine
// PointerReadRoutine,
// PointerWriteRoutine
};
OS2IO_VECTORS FileVectors = {
FileOpenRoutine,
FileSetHandleStateRoutine,
FileQueryHTypeRoutine,
FileCloseRoutine,
FileDupHandleRoutine,
FileReadRoutine,
FileWriteRoutine
};
OS2IO_VECTORS DeviceVectors = {
FileOpenRoutine,
NonFileSetHandleStateRoutine,
DeviceQueryHTypeRoutine,
FileCloseRoutine,
FileDupHandleRoutine,
FileReadRoutine,
FileWriteRoutine
};
/*
OS2IO_VECTORS PseudoDeviceVectors = {
PsDeviceSetHandleStateRoutine,
PsDeviceCloseRoutine,
PsDeviceDupHandleRoutine,
PsDeviceReadRoutine,
PsDeviceWriteRoutine
};
*/
OS2IO_VECTORS RemoteVectors = {
NULL,
RemoteSetHandleStateRoutine,
RemoteQueryHTypeRoutine,
RemoteCloseRoutine,
RemoteDupHandleRoutine,
RemoteReadRoutine,
RemoteWriteRoutine
};
OS2IO_VECTORS MonitorVectors = {
NULL,
NoSuppSetHandleStateRoutine,
NoSuppQueryHTypeRoutine,
NoSuppCloseRoutine,
NoSuppDupHandleRoutine,
TmpReadRoutine,
TmpWriteRoutine
// MonitorReadRoutine,
// MonitorWriteRoutine
};
POS2IO_VECTORS IoVectorArray[] = {&NulVectors,
&ConVectors,
&ComVectors, // same as AuxVectors
&LptVectors, // same as PrnVectors
&KbdVectors,
&MouseVectors,
&ClockVectors,
&ScreenVectors,
&PointerVectors,
&FileVectors,
&FileVectors, // &PipeVectors, (deleted)
&DeviceVectors,
&RemoteVectors,
&MonitorVectors
};
VOID
MapShareAccess(
IN ULONG OpenMode,
OUT PULONG DesiredAccess,
OUT PULONG ShareAccess
);
APIRET
DereferenceFileHandle(
IN HFILE FileHandle,
OUT PFILE_HANDLE *hFileRecord
)
/*++
Routine Description:
This routine maps a file handle to a file handle record
Arguments:
FileHandle - handle to map
hFileRecord - where to store pointer to file handle record
Return Value:
ERROR_INVALID_HANDLE - handle is invalid
Note:
File lock must be acquired shared or exclusive BEFORE calling this routine
--*/
{
//
// Check for invalid handle.
//
if ((((ULONG) FileHandle) >= HandleTableLength) ||
(!(HandleTable[(ULONG) FileHandle].Flags & FILE_HANDLE_VALID))) {
return ERROR_INVALID_HANDLE;
}
*hFileRecord = &(HandleTable[(ULONG) FileHandle]);
return NO_ERROR;
}
PFILE_HANDLE
DereferenceFileHandleNoCheck(
IN HFILE FileHandle
)
/*++
Routine Description:
This routine maps a file handle to a file handle record without checking
the handle's validity
Arguments:
FileHandle - handle to map
Return Value:
pointer to file handle record
Note:
File lock must be acquired shared or exclusive BEFORE calling this routine
--*/
{
return &(HandleTable[(ULONG) FileHandle]);
}
VOID
InvalidateHandle(
IN PFILE_HANDLE hFileRecord
)
/*++
Routine Description:
This routine marks an OS/2 file handle invalid.
Arguments:
hFileRecord - pointer to record of OS/2 handle to mark invalid
Return Value:
none.
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
if (hFileRecord->Flags & FILE_HANDLE_ALLOCATED) {
hFileRecord->Flags &= ~FILE_HANDLE_VALID;
}
else
ASSERT(FALSE);
}
VOID
ValidateHandle(
IN PFILE_HANDLE hFileRecord
)
/*++
Routine Description:
This routine marks an OS/2 file handle valid.
Arguments:
hFileRecord - pointer to record of OS/2 handle to mark valid
Return Value:
none.
Note:
File lock must be acquired BEFORE calling this routine
--*/
{
if (hFileRecord->Flags & FILE_HANDLE_ALLOCATED) {
hFileRecord->Flags |= FILE_HANDLE_VALID;
}
else
ASSERT(FALSE);
}
APIRET
AllocateHandle(
OUT PHFILE FileHandle
)
/*++
Routine Description:
This routine allocates an OS/2 file handle. The file handle is marked
reserved but not valid. If another thread tries to use the handle, an
error will be returned.
Arguments:
FileHandle - where to store the allocated handle (unprobed)
Return Value:
ERROR_TOO_MANY_OPEN_FILES - no free file handles.
Note:
File lock must be acquired BEFORE calling this routine
--*/
{
ULONG i;
for (i=0;i<HandleTableLength;i++) {
if (HandleTable[i].Flags == FILE_HANDLE_FREE) {
HandleTable[i].Flags = FILE_HANDLE_ALLOCATED;
try {
*FileHandle = (HFILE) i;
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
return NO_ERROR;
}
}
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] file handle allocation failed - no free handles.\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return ERROR_TOO_MANY_OPEN_FILES;
}
APIRET
FreeHandle(
IN HFILE FileHandle
)
/*++
Routine Description:
This routine frees an OS/2 file handle.
Arguments:
FileHandle - handle to free
Return Value:
ERROR_INVALID_HANDLE - handle is not allocated
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
if (HandleTable[(ULONG) FileHandle].Flags & FILE_HANDLE_ALLOCATED) {
HandleTable[(ULONG) FileHandle].Flags = FILE_HANDLE_FREE;
return NO_ERROR;
}
else
ASSERT (FALSE);
// return ERROR_INVALID_HANDLE;
}
APIRET
CheckMode(
IN ULONG RequestedMode
)
/*++
Routine Description:
This routine checks for valid access/sharing flags and checks that
reserved bits are off.
Arguments:
RequestedMode - openmode passed to DosOpen API
Return Value:
ERROR_INVALID_ACCESS - mode is invalid
--*/
{
ULONG check;
//
// Word 1 is all reserved
// nibble 3 of word 0 is all ok
//
if (RequestedMode & 0xFFFF0000) {
return ERROR_INVALID_PARAMETER;
}
//
// check nibble 2
//
check = RequestedMode & 0xF00;
if ( (check >= 0x400 && check <= 0xF00) ) {
return ERROR_INVALID_PARAMETER;
}
//
// check nibble 0
//
check = RequestedMode & 0xF;
if ( (check >= 0x3 && check <= 0x7) ||
(check >= 0xB && check <= 0xF) ) {
return ERROR_INVALID_ACCESS;
}
//
// check nibble 1
//
check = RequestedMode & 0xF0;
if ( (check == 0) ||
(check >= 0x50 && check <= 0x80) ||
(check >= 0xD0 && check <= 0xF0) ) {
return ERROR_INVALID_ACCESS;
}
/* if (((RequestedMode & SHARE_FLAGS) > OPEN_SHARE_DENYNONE) ||
((RequestedMode & SHARE_FLAGS) < OPEN_SHARE_DENYREADWRITE))
return ERROR_INVALID_ACCESS;
if ((RequestedMode & ACCESS_FLAGS) > OPEN_ACCESS_READWRITE)
return ERROR_INVALID_ACCESS;
*/
return NO_ERROR;
}
APIRET
UpdateFileSize(
IN HANDLE NtHandle,
IN ULONG NewFileSize
)
/*++
Routine Description:
This routine changes the size of a file.
Arguments:
NtHandle - NT handle to file to change the size of
NewFileSize - new size of file
Return Value:
ERROR_INVALID_ACCESS - the file was not open in a mode which allowed
the file size to be changed.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
FILE_END_OF_FILE_INFORMATION EofInfo;
APIRET rc;
//
// call NtSetInformationFile to set new size and EOF
//
EofInfo.EndOfFile = RtlConvertUlongToLargeInteger(NewFileSize);
do {
Status = NtSetInformationFile(NtHandle,
&IoStatus,
&EofInfo,
sizeof(EofInfo),
FileEndOfFileInformation
);
} while (RetryIO(Status, NtHandle));
if (!(NT_SUCCESS(Status))) {
rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS);
}
else {
rc = NO_ERROR;
}
return rc;
}
APIRET
DosOpen(
IN PSZ FileName,
OUT PHFILE FileHandle,
OUT PULONG ActionTaken,
IN ULONG CreateSize,
IN ULONG FileAttribute,
IN ULONG OpenFlags,
IN ULONG OpenMode,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL
)
/*++
Routine Description:
This routine opens a file.
Arguments:
FileName - name of file to open
FileHandle - where to store OS/2 handle
ActionTaken - whether file was opened, created, or replaced
CreateSize - size of file, if created or replaced.
FileAttribute - attribute of file, if created.
OpenFlags - whether to open, create, or replace the file if it exists or
doesn't exist.
OpenMode - mode in which to open the file (access, sharing, direct access,
etc.)
ExtendedFileAttr - extended attributes to set, if created or replaced.
Return Value:
ERROR_ACCESS_DENIED - requested operation could not be performed because
caller didn't have correct access rights
ERROR_PATH_NOT_FOUND - direct access requested and pathname is not "d:\"
or a device
ERROR_INVALID_PARAMETER - open mode or open flags contains an invalid
value.
--*/
{
NTSTATUS Status;
APIRET RetCode;
PSZ CanonicalName;
STRING CanonicalNameString;
UNICODE_STRING CanonicalNameString_U;
ULONG FileType;
ULONG FileFlags;
USHORT DeviceAttribute;
PFILE_HANDLE hFileRecord;
HANDLE NtFileHandle;
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK IoStatus;
ULONG ShareAccess;
ULONG Attributes;
ULONG DesiredAccess;
ULONG CreateDisposition;
ULONG CreateOptions;
IO_VECTOR_TYPE VectorType;
HFILE hLocalHandle;
HANDLE ComReadEvent;
HANDLE ComWriteEvent;
HANDLE ComIOCtlEvent;
ULONG DriveNumber = 0L;
SECURITY_QUALITY_OF_SERVICE DefaultSqos =
{ sizeof(SECURITY_QUALITY_OF_SERVICE),
SecurityImpersonation,
SECURITY_DYNAMIC_TRACKING,
TRUE };
#if DBG
PSZ RoutineName;
RoutineName = "DosOpen";
#endif
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] entering DosOpen(%s)\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
FileName));
}
#endif
try {
Od2ProbeForWrite((PVOID)FileHandle, sizeof(HFILE), 1);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
if (RetCode = CheckMode(OpenMode))
return RetCode;
//
// history of the following code:
// a bug in 1.2 was found whereby process A could open a file deny_write
// and process B could open the same file for read, specifying replace_if_exists.
// the net result is that process B could affect the contents of the file
// when A had specifically tried to prevent it. this bug was fixed by
// requiring that a process have a write access handle in order to replace.
// this was implemented by checking that if OPEN_ACTION_REPLACE_IF_EXISTS was
// specified that OpenMode wasn't OPEN_ACCESS_READONLY. thus the call to
// DosOpen would fail even if the file didn't exist.
// so we disallow OPEN_ACCESS_READONLY & OPEN_ACTION_REPLACE_IF_EXISTS
//
// we also disallow creates with a non-zero CreateSize for read-only handles.
// this is because the data in the file is undefined. if the file is open
// for write access, we can call NT to set the end-of-file pointer to the
// CreateSize. this call will zero out all the bytes up to the end-of-file
// pointer. or the user can write out data. but if the handle is read-only,
// we can't set the end-of-file pointer and the user won't be able to read
// the file. this is also a security issue.
//
if (((OpenMode & ACCESS_FLAGS) == OPEN_ACCESS_READONLY) &&
(OpenFlags & OPEN_ACTION_REPLACE_IF_EXISTS)) {
return ERROR_ACCESS_DENIED;
}
//
// check for invalid locality of reference value
//
if ((OpenMode & LOCALITY_FLAGS) > OPEN_FLAGS_RANDOMSEQUENTIAL) {
return ERROR_INVALID_PARAMETER;
}
//
// check file attributes. these don't need to be mapped because
// the NT values correspond to the v20 values.
//
// FILE_ATTRIBUTE_NORMAL is never passed to NT on a create because it
// maps to an attribute of zero and FILE_ARCHIVED is always set.
//
if (FileAttribute & ~ATTR_CHANGEABLE) {
return ERROR_ACCESS_DENIED;
}
Attributes = FileAttribute | FILE_ARCHIVED;
//
// check validity of OpenFlags
//
if ((OpenFlags & OPEN_ACTION_RESERVED) ||
((OpenFlags & (OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_REPLACE_IF_EXISTS)) > OPEN_ACTION_REPLACE_IF_EXISTS))
{
return(ERROR_INVALID_PARAMETER);
}
//
// map open flags
//
// if the user asked to replace a file, we need WRITE_DAC access to the
// file so we add it here.
//
switch (OpenFlags) {
case (OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS):
CreateDisposition = FILE_OVERWRITE_IF;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] setting file_overwrite_if\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
break;
case (OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS):
CreateDisposition = FILE_OVERWRITE;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] setting file_overwrite\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
break;
case (OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS):
CreateDisposition = FILE_OPEN_IF;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] setting file_open_if\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
break;
case (OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS):
CreateDisposition = FILE_OPEN;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] setting file_open\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
break;
case (OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS):
CreateDisposition = FILE_CREATE;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] setting file_create\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
break;
default:
return ERROR_OPEN_FAILED;
}
AcquireFileLockExclusive(
#if DBG
RoutineName
#endif
);
RetCode = AllocateHandle(&hLocalHandle);
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
if (RetCode) {
return RetCode;
}
//
// if direct access requested, make sure path is just a drive letter
// check CreateDisposition
//
if (OpenMode & OPEN_FLAGS_DASD) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] DASD open\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
if (CreateDisposition != FILE_OPEN) {
RetCode = ERROR_INVALID_PARAMETER;
}
else {
try {
if ((FileName[1] != ':') || (FileName[2] != '\0'))
RetCode = ERROR_PATH_NOT_FOUND;
else {
CanonicalName = RtlAllocateHeap(Od2Heap,0,17); // length of \os2ss\drives\x:
strcpy (CanonicalName,"\\OS2SS\\DRIVES\\");
CanonicalName[14] = FileName[0];
CanonicalName[15] = ':';
CanonicalName[16] = '\0';
DriveNumber = (((ULONG)toupper((UCHAR)FileName[0])) - 'A' + 1) | 0x80000000;
FileType = FILE_TYPE_FILE;
}
} except( EXCEPTION_EXECUTE_HANDLER ) {
AcquireFileLockExclusive(
#if DBG
RoutineName
#endif
);
FreeHandle(hLocalHandle);
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
if (CanonicalName == NULL) {
#if DBG
KdPrint(("[%d,%d] OS2: Od2Canonicalise, no memory in Od2Heap\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
ASSERT(FALSE);
#endif
return ERROR_NOT_ENOUGH_MEMORY;
}
else {
Od2ExitGP();
}
}
}
if (RetCode) {
AcquireFileLockExclusive(
#if DBG
RoutineName
#endif
);
FreeHandle(hLocalHandle);
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return RetCode;
}
Od2InitMBString(&CanonicalNameString,CanonicalName);
NtFileHandle = NULL; // don't have current directory open
}
else
{
RetCode = Od2Canonicalize(FileName,
CANONICALIZE_FILE_DEV_OR_PIPE,
&CanonicalNameString,
&NtFileHandle,
&FileFlags, // BUGBUG shouldn't we check for root dir
&FileType
);
if ((RetCode != NO_ERROR)|| (FileFlags & CANONICALIZE_META_CHARS_FOUND)) {
AcquireFileLockExclusive(
#if DBG
RoutineName
#endif
);
FreeHandle(hLocalHandle);
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
if (RetCode == NO_ERROR && (FileFlags & CANONICALIZE_META_CHARS_FOUND)) {
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
RetCode = ERROR_FILE_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,
((OpenMode & ACCESS_FLAGS) == OPEN_ACCESS_READONLY) ?
OPEN_ACCESS_READONLY :
OPEN_ACCESS_READWRITE,
&Status))
{
if (!NT_SUCCESS(Status))
{
// failed to init for config.sys
AcquireFileLockExclusive(
#if DBG
RoutineName
#endif
);
FreeHandle(hLocalHandle);
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
RtlFreeHeap(Od2Heap, 0, CanonicalNameString.Buffer);
return Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
}
NtFileHandle = NULL;
FileFlags = 0;
FileType = FILE_TYPE_FILE;
//OpenMode = (OpenMode & ~SHARE_FLAGS) | OPEN_SHARE_DENYREADWRITE;
}
}
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] canonical name is %s\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
CanonicalNameString.Buffer));
}
#endif
//
// UNICODE conversion -
//
RetCode = Od2MBStringToUnicodeString(
&CanonicalNameString_U,
&CanonicalNameString,
TRUE);
if (RetCode)
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
KdPrint(("[%d,%d] DosOpen: no memory for Unicode Conversion\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
RtlFreeHeap(Od2Heap, 0, CanonicalNameString.Buffer);
return RetCode;
}
InitializeObjectAttributes(&Obja,
&CanonicalNameString_U,
OBJ_CASE_INSENSITIVE,
NtFileHandle,
NULL);
//
// Set up a default Security-Quality-of-Service in case this
// DosOpen() will implicitly connect us to a protected server.
// The default SQoS is the same as in Win32 CreateFile(). We
// discovered this SQoS is necessary when it turned out that the
// os2ss couldn't print when a print manager printer is installed
// on LPT ports. The reason was that the LPT write requests were
// getting redirected to the print spooler (a protected server) and
// it requires an SQoS.
//
Obja.SecurityQualityOfService = &DefaultSqos;
//
// in OS/2, the device header is checked for a bit that indicates whether
// the device should be added to the sharing set. this is not supported
// in NT.
//
// map sharing flags
//
MapShareAccess(OpenMode,&DesiredAccess,&ShareAccess);
if (OpenMode & OPEN_FLAGS_DASD) {
//
// We must have FILE_SHARE_WRITE for DASD, or else
// NT won't allow us to lock the volume.
//
ShareAccess |= FILE_SHARE_WRITE;
}
//
// Nt does not allow pipes to have EAs access on them.
//
if ( FileType == FILE_TYPE_PIPE ||
FileType == FILE_TYPE_NMPIPE ||
FileType == FILE_TYPE_MAILSLOT) {
DesiredAccess &= ~( FILE_READ_EA | FILE_WRITE_EA);
/* This is commented out now, cause FILE_WRITE_ATTRIBUTES is always
given to DesiredAccess. (T-EYALA, 1/94)
//
// Nt require pipes to have WRITE_ATTRIBUTES access to perform
// operations like DosSetNPHState. No equivalent requirement on os/2
//
DesiredAccess |= FILE_WRITE_ATTRIBUTES;
*/ //
// Also, Nt does not support yet the sharing semantics of pipe
// clients under OS/2. To work around it, we do not allow
// the client to specify DENY_READ_WRITE --> specify DENY_NONE instead
//
if (ShareAccess == 0){
ShareAccess = FILE_SHARE_WRITE | FILE_SHARE_READ;
}
}
DesiredAccess |= SYNCHRONIZE;
//
// set up CreateOptions
// BUGBUG need to handle FAIL_ON_ERROR
//
if (FileType == FILE_TYPE_NMPIPE) {
CreateOptions = FILE_NON_DIRECTORY_FILE;
}
else {
CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE;
}
if (OpenMode & OPEN_FLAGS_WRITE_THROUGH)
CreateOptions |= FILE_WRITE_THROUGH;
if (OpenMode & OPEN_FLAGS_SEQUENTIAL)
CreateOptions |= FILE_SEQUENTIAL_ONLY;
switch (FileType) {
case FILE_TYPE_FILE:
VectorType = FileVectorType;
break;
case FILE_TYPE_PIPE:
VectorType = PipeVectorType;
break;
case FILE_TYPE_NMPIPE:
VectorType = FileVectorType;
break;
case FILE_TYPE_UNC:
VectorType = FileVectorType;
break;
case FILE_TYPE_DEV:
VectorType = DeviceVectorType;
break;
case FILE_TYPE_PSDEV:
VectorType = CanonicalNameString.Buffer[1] - '0';
break;
case FILE_TYPE_MAILSLOT:
VectorType = FileVectorType;
break;
case FILE_TYPE_COM:
VectorType = ComVectorType;
// Delete the SYNCHRONOUSE flags. The COM device
// is accessed ASYNCHRONOUS
CreateOptions &= ~(FILE_SYNCHRONOUS_IO_NONALERT |
FILE_SYNCHRONOUS_IO_ALERT);
DesiredAccess &= ~SYNCHRONIZE;
break;
default:
#if DBG
KdPrint(("[%d,%d] unsupported filetype in DosOpen\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
ASSERT (FALSE); // not supported
#endif
break;
}
RetCode = IoVectorArray[VectorType]->OpenRoutine(&NtFileHandle,
DesiredAccess,
&Obja,
&IoStatus,
CreateSize,
ActionTaken,
Attributes,
ShareAccess,
CreateDisposition,
CreateOptions,
ExtendedFileAttr,
(PUSHORT) &FileType,
&DeviceAttribute
);
RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
RtlFreeUnicodeString (&CanonicalNameString_U);
if (RetCode) {
AcquireFileLockExclusive(
#if DBG
RoutineName
#endif
);
FreeHandle(hLocalHandle);
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
//
// BUGBUG - ERROR_INVALID_NAME 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 FILE_NOT_FOUND).
// Nt returns to OpenCreatePath the same status - we need to check
// the pathname to determine the problem.
//
if (RetCode == ERROR_INVALID_NAME){
//
// Check for the case that the pathname includes
// characters that are valid for HPFS but not for FAT etc.
// We don't catch this is Od2Canonicalize for performance
// (not querying the volume for the file system)
//
CHAR FatInvalidChars[] = {
'[',
']',
'+',
'=',
';',
','};
CHAR *pc = FileName;
CHAR c;
while (*pc){
c = *pc++;
if (strchr( FatInvalidChars, c )) {
return ERROR_INVALID_NAME;
}
}
return(ERROR_FILE_NOT_FOUND);
}
if (!(OpenFlags & OPEN_ACTION_CREATE_IF_NEW) && RetCode == ERROR_FILE_NOT_FOUND) {
return(ERROR_OPEN_FAILED);
}
if (((OpenFlags | OPEN_ACTION_CREATE_IF_NEW) == OPEN_ACTION_CREATE_IF_NEW) && RetCode == ERROR_ACCESS_DENIED) {
return(ERROR_OPEN_FAILED);
}
return RetCode;
}
if (VectorType == FileVectorType) {
//
// if the path was not what we determined, update vector type.
// BUGBUG - is this an error?
//
if (FileType != FILE_TYPE_FILE) {
switch (FileType) {
case FILE_TYPE_PIPE:
VectorType = PipeVectorType;
break;
case FILE_TYPE_NMPIPE:
case FILE_TYPE_MAILSLOT:
break;
case FILE_TYPE_DEV:
VectorType = DeviceVectorType;
break;
default:
#if DBG
KdPrint(("[%d,%d] unsupported filetype in DosOpen\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
ASSERT (FALSE); // not supported
#endif
break;
}
}
}
if (FileType == FILE_TYPE_COM) {
Status = NtCreateEvent(&ComReadEvent,
EVENT_ALL_ACCESS,
NULL,
SynchronizationEvent,
FALSE
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComRead, Status = %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
#endif
}
Status = NtCreateEvent(&ComWriteEvent,
EVENT_ALL_ACCESS,
NULL,
SynchronizationEvent,
FALSE
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComWrite, Status = %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
#endif
}
Status = NtCreateEvent(&ComIOCtlEvent,
EVENT_ALL_ACCESS,
NULL,
SynchronizationEvent,
FALSE
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComIOCtl, Status = %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
#endif
}
}
else {
ComReadEvent = NULL;
ComWriteEvent = NULL;
if (DriveNumber != 0L) {
//
// NtAsyncIOCtlEvent also doubles as a storage point for
// the drive number when opening a DASD.
// Drives are based at 1 (which is drive A:)
//
// Note that the high bit is initially turned on, so that
// the disk ioctl routines know that they should check the
// device is really a floppy drive.
//
ComIOCtlEvent = (HANDLE) DriveNumber;
} else {
ComIOCtlEvent = NULL;
}
}
AcquireFileLockExclusive(
#if DBG
RoutineName
#endif
);
hFileRecord = DereferenceFileHandleNoCheck(hLocalHandle);
hFileRecord->NtHandle = NtFileHandle;
hFileRecord->NtAsyncReadEvent = ComReadEvent;
hFileRecord->NtAsyncWriteEvent = ComWriteEvent;
hFileRecord->NtAsyncIOCtlEvent = ComIOCtlEvent;
hFileRecord->FileType = (USHORT) FileType;
hFileRecord->Flags |= OpenMode & QFHSTATE_FLAGS;
hFileRecord->DeviceAttribute = DeviceAttribute;
hFileRecord->IoVectorType = VectorType;
//
// validate file handle
//
ValidateHandle(hFileRecord);
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
*FileHandle = hLocalHandle;
return NO_ERROR;
}
APIRET
Od2DeviceShare(
IN SHARE_OPERATION Operation,
IN IO_VECTOR_TYPE VectorType,
IN ULONG DesiredAccess,
IN ULONG ShareAccess
)
{
OS2_API_MSG m;
POS2_SHARE_MSG a = &m.u.DeviceShare;
a->Operation = Operation;
a->VectorType = VectorType;
a->DesiredAccess = DesiredAccess;
a->ShareAccess = ShareAccess;
Od2CallSubsystem( &m, NULL, Oi2DeviceShare, sizeof( *a ) );
if (m.ReturnedErrorValue != NO_ERROR) {
return( m.ReturnedErrorValue );
}
}
APIRET
NulOpenRoutine(
OUT PHANDLE FileHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatus,
IN ULONG CreateSize,
OUT PULONG ActionTaken,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute
)
{
APIRET RetCode;
UNREFERENCED_PARAMETER(FileHandle);
UNREFERENCED_PARAMETER(ObjectAttributes);
UNREFERENCED_PARAMETER(IoStatus);
UNREFERENCED_PARAMETER(CreateSize);
UNREFERENCED_PARAMETER(FileAttributes);
UNREFERENCED_PARAMETER(CreateOptions);
UNREFERENCED_PARAMETER(ExtendedFileAttr);
UNREFERENCED_PARAMETER(FileType);
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] DosOpen(NUL): NulOpenRoutine\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
//
// call the server to add the device to the sharer
//
RetCode = Od2DeviceShare(AddShare,NulVectorType,DesiredAccess,ShareAccess);
if (RetCode != NO_ERROR)
{
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] NulOpenRoutine: unable to share request\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return RetCode;
}
//
// return the correct device attribute
//
*DeviceAttribute = DEVICE_ATTRIBUTE_NUL | DEVICE_ATTRIBUTE_CHAR | 0x80;
/* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */
//
// map ActionTaken
//
*ActionTaken = MapDeviceAction(CreateDisposition);
return NO_ERROR;
}
APIRET
ConOpenRoutine(
OUT PHANDLE FileHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatus,
IN ULONG CreateSize,
OUT PULONG ActionTaken,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute
)
{
APIRET RetCode;
UNREFERENCED_PARAMETER(FileHandle);
UNREFERENCED_PARAMETER(ObjectAttributes);
UNREFERENCED_PARAMETER(IoStatus);
UNREFERENCED_PARAMETER(CreateSize);
UNREFERENCED_PARAMETER(FileAttributes);
UNREFERENCED_PARAMETER(CreateOptions);
UNREFERENCED_PARAMETER(ExtendedFileAttr);
UNREFERENCED_PARAMETER(FileType);
#if DBG
IF_OD2_DEBUG(VIO_FILE)
{
KdPrint(("[%d,%d] DosOpen(CON): ConOpenRoutine\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
//
// call the server to add the device to the sharer
//
RetCode = Od2DeviceShare(AddShare,ConVectorType,DesiredAccess,ShareAccess);
if (RetCode != NO_ERROR)
{
#if DBG
IF_OD2_DEBUG(VIO_FILE)
{
KdPrint(("[%d,%d] ConOpenRoutine: unable to share request\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return RetCode;
}
//
// return the correct device attribute
//
*DeviceAttribute = DEVICE_ATTRIBUTE_STDOUT | DEVICE_ATTRIBUTE_STDIN | DEVICE_ATTRIBUTE_CHAR |
0x80 /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */ ;
//
// set HANDLE
//
*FileHandle = SesGrp->hConsoleOutput;
//
// map ActionTaken
//
*ActionTaken = MapDeviceAction(CreateDisposition);
return NO_ERROR;
}
APIRET
ComOpenRoutine(
OUT PHANDLE FileHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatus,
IN ULONG CreateSize,
OUT PULONG ActionTaken,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute
)
{
APIRET RetCode;
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] DosOpen(COM): ComOpenRoutine\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
//
// we support inherited handles by duping. all Nt handles are opened
// noinherit.
//
// pass parameters, and pFileType
//
RetCode = OpenCreatePath(FileHandle,
DesiredAccess,
ObjectAttributes,
IoStatus,
CreateSize,
FileAttributes,
ShareAccess,
CreateDisposition,
CreateOptions,
ExtendedFileAttr,
FileType,
DeviceAttribute,
FALSE
);
if (RetCode) {
return RetCode;
}
//
// set up ActionTaken value.
//
try {
if (IoStatus->Information == FILE_SUPERSEDED)
*ActionTaken = FILE_EXISTED;
else
*ActionTaken = IoStatus->Information;
} except( EXCEPTION_EXECUTE_HANDLER ) {
NtClose(*FileHandle);
Od2ExitGP();
}
return NO_ERROR;
}
APIRET
LptOpenRoutine(
OUT PHANDLE FileHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatus,
IN ULONG CreateSize,
OUT PULONG ActionTaken,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute
)
{
APIRET RetCode;
UNREFERENCED_PARAMETER(FileHandle);
UNREFERENCED_PARAMETER(ObjectAttributes);
UNREFERENCED_PARAMETER(IoStatus);
UNREFERENCED_PARAMETER(CreateSize);
UNREFERENCED_PARAMETER(FileAttributes);
UNREFERENCED_PARAMETER(CreateOptions);
UNREFERENCED_PARAMETER(ExtendedFileAttr);
UNREFERENCED_PARAMETER(FileType);
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] DosOpen(LPT): LptOpenRoutine\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
//
// call the server to add the device to the sharer
//
RetCode = Od2DeviceShare(AddShare,LptVectorType,DesiredAccess,ShareAccess);
if (RetCode != NO_ERROR)
{
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] LptOpenRoutine: unable to share request\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return RetCode;
}
//
// BUGBUG call the windows input thread
//
//
// return the correct device attribute
//
*DeviceAttribute = DEVICE_ATTRIBUTE_DEFAULT_CHAR;
//
// map ActionTaken
//
*ActionTaken = MapDeviceAction(CreateDisposition);
return NO_ERROR;
}
APIRET
KbdOpenRoutine(
OUT PHANDLE FileHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatus,
IN ULONG CreateSize,
OUT PULONG ActionTaken,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute
)
{
APIRET RetCode;
UNREFERENCED_PARAMETER(ObjectAttributes);
UNREFERENCED_PARAMETER(IoStatus);
UNREFERENCED_PARAMETER(CreateSize);
UNREFERENCED_PARAMETER(FileAttributes);
UNREFERENCED_PARAMETER(CreateOptions);
UNREFERENCED_PARAMETER(ExtendedFileAttr);
UNREFERENCED_PARAMETER(FileType);
#if DBG
IF_OD2_DEBUG(KBD_FILE)
{
KdPrint(("[%d,%d] DosOpen(KBD$): KbdOpenRoutine\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
//
// call the server to add the device to the sharer
//
RetCode = Od2DeviceShare(AddShare,KbdVectorType,DesiredAccess,ShareAccess);
if (RetCode != NO_ERROR)
{
#if DBG
IF_OD2_DEBUG(KBD_FILE)
{
KdPrint(("[%d,%d] KbdOpenRoutine: unable to share request\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return RetCode;
}
//
// return the correct device attribute
//
*DeviceAttribute = DEVICE_ATTRIBUTE_STDIN | DEVICE_ATTRIBUTE_CHAR | DEVICE_ATTRIBUTE_CONSOLE |
DEVICE_ATTRIBUTE_OPEN | 0x80 ;
/* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */
//
// set HANDLE
//
*FileHandle = (HANDLE)SesGrp->PhyKbd;
//
// map ActionTaken
//
*ActionTaken = MapDeviceAction(CreateDisposition);
return NO_ERROR;
}
APIRET
MouseOpenRoutine(
OUT PHANDLE FileHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatus,
IN ULONG CreateSize,
OUT PULONG ActionTaken,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute
)
{
APIRET RetCode;
UNREFERENCED_PARAMETER(ObjectAttributes);
UNREFERENCED_PARAMETER(IoStatus);
UNREFERENCED_PARAMETER(CreateSize);
UNREFERENCED_PARAMETER(FileAttributes);
UNREFERENCED_PARAMETER(CreateOptions);
UNREFERENCED_PARAMETER(ExtendedFileAttr);
UNREFERENCED_PARAMETER(FileType);
#if DBG
IF_OD2_DEBUG(MOU_FILE)
{
KdPrint(("[%d,%d] DosOpen(MOUSE$): MouOpenRoutine\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
//
// call the server to add the device to the sharer
//
RetCode = Od2DeviceShare(AddShare,MouseVectorType,DesiredAccess,ShareAccess);
if (RetCode != NO_ERROR)
{
#if DBG
IF_OD2_DEBUG(MOU_FILE)
{
KdPrint(("[%d,%d] MouOpenRoutine: unable to share request\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return RetCode;
}
//
// call the windows input thread
//
RetCode = DevMouOpen(FileHandle);
if ( RetCode ) {
ASSERT(FALSE);
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] MouseOpenRouine: Error returned from DevMouOpen %d\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
RetCode));
}
#endif
return(RetCode);
}
//
// return the correct device attribute
//
*DeviceAttribute = DEVICE_ATTRIBUTE_CHAR | DEVICE_ATTRIBUTE_CONSOLE | DEVICE_ATTRIBUTE_OPEN |
0x80 /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */;
//
// map ActionTaken
//
*ActionTaken = MapDeviceAction(CreateDisposition);
return NO_ERROR;
}
APIRET
ClockOpenRoutine(
OUT PHANDLE FileHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatus,
IN ULONG CreateSize,
OUT PULONG ActionTaken,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute
)
{
APIRET RetCode;
UNREFERENCED_PARAMETER(FileHandle);
UNREFERENCED_PARAMETER(ObjectAttributes);
UNREFERENCED_PARAMETER(IoStatus);
UNREFERENCED_PARAMETER(CreateSize);
UNREFERENCED_PARAMETER(FileAttributes);
UNREFERENCED_PARAMETER(CreateOptions);
UNREFERENCED_PARAMETER(ExtendedFileAttr);
UNREFERENCED_PARAMETER(FileType);
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] DosOpen(CLOCK$): ClockOpenRoutine\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
//
// call the server to add the device to the sharer
//
RetCode = Od2DeviceShare(AddShare,ClockVectorType,DesiredAccess,ShareAccess);
if (RetCode != NO_ERROR)
{
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] ClockOpenRoutine: unable to share request\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return RetCode;
}
//
// BUGBUG call NT
//
//
// return the correct device attribute
//
*DeviceAttribute = DEVICE_ATTRIBUTE_CLOCK | DEVICE_ATTRIBUTE_CHAR |
0x80 /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */;
//
// map ActionTaken
//
*ActionTaken = MapDeviceAction(CreateDisposition);
return NO_ERROR;
}
APIRET
ScreenOpenRoutine(
OUT PHANDLE FileHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatus,
IN ULONG CreateSize,
OUT PULONG ActionTaken,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute
)
{
APIRET RetCode;
UNREFERENCED_PARAMETER(ObjectAttributes);
UNREFERENCED_PARAMETER(IoStatus);
UNREFERENCED_PARAMETER(CreateSize);
UNREFERENCED_PARAMETER(FileAttributes);
UNREFERENCED_PARAMETER(CreateOptions);
UNREFERENCED_PARAMETER(ExtendedFileAttr);
UNREFERENCED_PARAMETER(FileType);
#if DBG
IF_OD2_DEBUG(VIO_FILE)
{
KdPrint(("[%d,%d] DosOpen(SCREEN$): ScreenOpenRoutine\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
//
// call the server to add the device to the sharer
//
RetCode = Od2DeviceShare(AddShare,ScreenVectorType,DesiredAccess,ShareAccess);
if (RetCode != NO_ERROR)
{
#if DBG
IF_OD2_DEBUG(VIO_FILE)
{
KdPrint(("[%d,%d] ScreenOpenRoutine: unable to share request\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return RetCode;
}
//
// BUGBUG call windows input thread
//
//
// set HANDLE
//
*FileHandle = (HANDLE)SesGrp->hConsoleOutput;
//
// return the correct device attribute
//
*DeviceAttribute = DEVICE_ATTRIBUTE_STDOUT | DEVICE_ATTRIBUTE_CHAR |
0x80 /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */;
//
// map ActionTaken
//
*ActionTaken = MapDeviceAction(CreateDisposition);
return NO_ERROR;
}
APIRET
PointerOpenRoutine(
OUT PHANDLE FileHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatus,
IN ULONG CreateSize,
OUT PULONG ActionTaken,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute
)
{
APIRET RetCode;
UNREFERENCED_PARAMETER(FileHandle);
UNREFERENCED_PARAMETER(ObjectAttributes);
UNREFERENCED_PARAMETER(IoStatus);
UNREFERENCED_PARAMETER(CreateSize);
UNREFERENCED_PARAMETER(FileAttributes);
UNREFERENCED_PARAMETER(CreateOptions);
UNREFERENCED_PARAMETER(ExtendedFileAttr);
UNREFERENCED_PARAMETER(FileType);
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] DosOpen(POINTER$): PointerOpenRoutine\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
// BUGBUG might want to change device open to
// call one routine that calls sharer and maps action and calls
// device specific routine
//
// call the server to add the device to the sharer
//
RetCode = Od2DeviceShare(AddShare,PointerVectorType,DesiredAccess,ShareAccess);
if (RetCode != NO_ERROR)
{
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] PointerOpenRoutine: unable to share request\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return RetCode;
}
//
// BUGBUG call windows input thread
//
//
// return the correct device attribute
//
*DeviceAttribute = DEVICE_ATTRIBUTE_CHAR | 0x80 /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */;
//
// map ActionTaken
//
*ActionTaken = MapDeviceAction(CreateDisposition);
return NO_ERROR;
}
APIRET
MapFileType(
IN HANDLE FileHandle,
OUT PBOOLEAN Directory OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute
)
/*++
Routine Description:
This routine maps an NT device type to an OS/2 file type.
Arguments:
FileHandle - NT handle to file
Directory - where to return whether the handle is for a directory
FileType - where to store OS/2 file type
DeviceAttribute - where to store the device attribute
Return Value:
none.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
FILE_BASIC_INFORMATION BasicInfo;
FILE_FS_DEVICE_INFORMATION DeviceInfo;
//
// in Canonicalize, we try to determine the type of a filename based
// on naming conventions. we use this information to determine whether
// an operation is legal (i.e. renaming a device is illegal). we detect
// named pipes (\PIPE\), devices (\DEV\) plus list of pseudo-character
// devices or drive letter, and UNC. all other names are assumed to
// be filenames. We can't detect remote names.
//
// It is possible to open a path that is a device or named pipe without
// being able to detect it in Canonicalize. For path-based operations
// that don't create an object, we verify the filetype after the open
// has occurred. this is because an operation that's illegal in OS/2
// may not be illegal in NT. We use the information returned by this call
// to store as the filetype associated with the file handle.
//
// no access is required to query StandardInformation or DeviceInformation.
//
if (ARGUMENT_PRESENT(Directory)) {
do {
Status = NtQueryInformationFile(FileHandle,
&IoStatus,
&BasicInfo,
sizeof (BasicInfo),
FileBasicInformation);
} while (RetryIO(Status, FileHandle));
if (!NT_SUCCESS( Status )) {
return Or2MapNtStatusToOs2Error(Status, ERROR_FILE_NOT_FOUND);
}
*Directory = ((BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
}
do {
Status = NtQueryVolumeInformationFile(FileHandle,
&IoStatus,
&DeviceInfo,
sizeof (DeviceInfo),
FileFsDeviceInformation);
} while (RetryIO(Status, FileHandle));
if (!NT_SUCCESS( Status )) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] MapFileType: Error from NtQueryVolumeInformation, %lx\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
}
#endif
return Or2MapNtStatusToOs2Error(Status, ERROR_FILE_NOT_FOUND);
}
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] MapFileType: DeviceType=%ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
DeviceInfo.DeviceType));
}
#endif
switch (DeviceInfo.DeviceType) {
case FILE_DEVICE_DATALINK:
case FILE_DEVICE_DFS:
case FILE_DEVICE_PHYSICAL_NETCARD:
case FILE_DEVICE_TRANSPORT:
case FILE_DEVICE_UNKNOWN:
case FILE_DEVICE_CD_ROM:
case FILE_DEVICE_DISK:
case FILE_DEVICE_VIRTUAL_DISK:
case FILE_DEVICE_TAPE:
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] MapFileType: disk file \n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*DeviceAttribute = 0;
*FileType = FILE_TYPE_FILE;
break;
case FILE_DEVICE_NETWORK:
*DeviceAttribute = 0;
*FileType = FILE_TYPE_UNC;
break;
case FILE_DEVICE_NAMED_PIPE:
*DeviceAttribute = 0;
*FileType = FILE_TYPE_NMPIPE;
break;
case FILE_DEVICE_MAILSLOT:
*DeviceAttribute = 0;
*FileType = FILE_TYPE_MAILSLOT;
break;
case FILE_DEVICE_SERIAL_PORT:
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] MapFileType: COM device \n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*FileType = FILE_TYPE_COM;
*DeviceAttribute = DEVICE_ATTRIBUTE_CHAR | DEVICE_ATTRIBUTE_OPEN |
DEVICE_ATTRIBUTE_GENIOCTL | 0x80;
/* 0x80 stands for level 1 */
break;
case FILE_DEVICE_SCREEN:
case FILE_DEVICE_KEYBOARD:
case FILE_DEVICE_MOUSE:
case FILE_DEVICE_NULL:
case FILE_DEVICE_PRINTER:
case FILE_DEVICE_SOUND:
case FILE_DEVICE_PARALLEL_PORT:
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] MapFileType: character device \n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*FileType = FILE_TYPE_DEV;
*DeviceAttribute = DEVICE_ATTRIBUTE_NUL | DEVICE_ATTRIBUTE_STDIN;
if (DeviceInfo.DeviceType == FILE_DEVICE_NULL)
*DeviceAttribute = DEVICE_ATTRIBUTE_CHAR | DEVICE_ATTRIBUTE_NUL | 0x80;
/* 0x80 stands for level 1 */
else if (DeviceInfo.DeviceType == FILE_DEVICE_PARALLEL_PORT)
*DeviceAttribute = DEVICE_ATTRIBUTE_CHAR | DEVICE_ATTRIBUTE_OPEN | 0x80;
/* 0x80 stands for level 1 */
else if (DeviceInfo.DeviceType == FILE_DEVICE_KEYBOARD)
*DeviceAttribute |= DEVICE_ATTRIBUTE_STDIN;
else if (DeviceInfo.DeviceType == FILE_DEVICE_SCREEN)
*DeviceAttribute |= DEVICE_ATTRIBUTE_STDOUT;
else if (DeviceInfo.DeviceType == FILE_DEVICE_PRINTER)
*DeviceAttribute = 0;
break;
default:
#if DBG
KdPrint(("[%d,%d] error: unknown device type in MapFileType %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
DeviceInfo.DeviceType));
#endif
return ERROR_PATH_NOT_FOUND;
break;
}
return NO_ERROR;
}
BOOLEAN
CheckFileType(
IN HANDLE FileHandle,
IN USHORT FileTypes
)
/*++
Routine Description:
This routine verifies that the handle is one of the specified types
(file types == device, pipe, pseudochar device, file).
Note that since the filetype value for file is zero, there is no way
to check for files.
Arguments:
FileHandle - NT handle to file
FileTypes - file types to check for
Return Value:
TBS
--*/
{
USHORT FileType;
APIRET RetCode;
USHORT DeviceAttribute;
RetCode = MapFileType(FileHandle,NULL, &FileType,&DeviceAttribute);
ASSERT (!RetCode);
if (RetCode){
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] CheckFileType: Error returned from MapFileType %d\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
RetCode));
}
#endif
return FALSE;
}
return ((BOOLEAN )((FileType & FileTypes) != 0));
}
APIRET
FileOpenRoutine(
OUT PHANDLE FileHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatus,
IN ULONG CreateSize,
OUT PULONG ActionTaken,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute
)
{
APIRET RetCode;
//
// we support inherited handles by duping. all Nt handles are opened
// noinherit.
//
// pass parameters, and pFileType
//
RetCode = OpenCreatePath(FileHandle,
DesiredAccess,
ObjectAttributes,
IoStatus,
CreateSize,
FileAttributes,
ShareAccess,
CreateDisposition,
CreateOptions,
ExtendedFileAttr,
FileType,
DeviceAttribute,
FALSE
);
if (RetCode) {
if ((RetCode == ERROR_SHARING_VIOLATION) && (*FileType == FILE_TYPE_NMPIPE)){
return(ERROR_ACCESS_DENIED);
}
return RetCode;
}
//
// set up ActionTaken value.
//
try {
if (IoStatus->Information == FILE_SUPERSEDED)
*ActionTaken = FILE_EXISTED;
else
*ActionTaken = IoStatus->Information;
} except( EXCEPTION_EXECUTE_HANDLER ) {
NtClose(*FileHandle);
Od2ExitGP();
}
//
// if file was replaced or created, we need to set the end-of-file pointer.
// we know the file-size change will succeed because we require a writeable
// handle if replace or create (with a non-zero CreateSize) is requested.
// The call to UpdateFileSize shouldn't actually change the size of the
// file. It will just set the end-of-file pointer to the createsize. NT
// puts the end-of-file pointer at the beginning of the file on create,
// regardless of the file size.
//
// If the UpdateFileSize fails, we fail the open but don't try to delete
// the file. We can't open the file for delete because it will fail if
// any other process has the file open, so we can't delete the file.
// Also, if the UpdateFileSize fails, the system is probably messed up
// enough that a delete would fail. However, we don't expect the
// UpdateFileSize to ever fail because all it's doing is setting the file
// pointer.
//
if ((*ActionTaken == FILE_CREATED && CreateSize != 0) ||
(*ActionTaken == FILE_TRUNCATED)) {
if (RetCode = UpdateFileSize(*FileHandle,CreateSize)) {
// NtClose(*FileHandle);
return NO_ERROR;
// return ERROR_ACCESS_DENIED; // BUGBUG bogus error?
}
}
return NO_ERROR;
}
APIRET
OpenCreatePath(
OUT PHANDLE FileHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatus,
IN ULONG CreateSize,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
OUT PUSHORT FileType,
OUT PUSHORT DeviceAttribute,
IN BOOLEAN OpenDirectory
)
/*++
Routine Description:
This routine opens/creates a file/directory, puts EAs into NT format,
and maps the file type. It should be called when NtCreateFile would be
called, as opposed to when NtOpenFile would be called.
Arguments:
FileHandle - where to return NT handle to file
DesiredAccess - requested access to file
ObjectAttributes - NT attributes of file
IoStatus - io status block
CreateSize - size of file, if created.
FileAttributes - attributes of file, if created.
ShareAccess - access to file allowed to subsequent openers
CreateDisposition - whether to open/create/truncate if exists/doesn't exist
CreateOptions - state of open file (synchronous, write-through, etc)
ExtendedFileAttr - extended attributes to set, if created or replaced.
BUGBUG need to probe this
FileType - where to return type of open file
OpenDirectory - whether or not opened object can be directory
Return Value:
ERROR_ACCESS_DENIED - the open could not be performed because
caller didn't have correct access rights
--*/
{
NTSTATUS Status;
APIRET RetCode;
LARGE_INTEGER AllocationSize;
PVOID EaBuffer;
ULONG EaListLength;
BOOLEAN Directory;
DBG_UNREFERENCED_LOCAL_VARIABLE(Directory);
//
// convert EA format here.
//
if (ExtendedFileAttr) {
EaListLength = ExtendedFileAttr->fpFEA2List->cbList - MINFEALISTSIZE;
if (EaListLength) {
EaBuffer = ExtendedFileAttr->fpFEA2List->list;
}
else {
EaBuffer = NULL;
}
}
else {
EaBuffer = NULL;
EaListLength = 0;
}
if (!OpenDirectory) {
CreateOptions |= FILE_NON_DIRECTORY_FILE;
} else {
CreateOptions |= FILE_DIRECTORY_FILE;
}
//
// open/create file/dir
//
AllocationSize = RtlConvertUlongToLargeInteger(CreateSize);
do {
Status = NtCreateFile(FileHandle,
DesiredAccess,
ObjectAttributes,
IoStatus,
&AllocationSize,
FileAttributes,
ShareAccess,
CreateDisposition,
CreateOptions,
EaBuffer,
EaListLength
);
} while (RetryCreateOpen(Status, ObjectAttributes));
//
// If we got STATUS_ACCESS_DENIED it may have happened because of trying
// to open a file on a CD-ROM. In this case, the FILE_WRITE_ATTRIBUTES
// flag in the DesiredAccess causes this error code, and we should open the file
// without it (only in READONLY).
//
if ((Status == STATUS_ACCESS_DENIED) &&
((CreateDisposition == FILE_OPEN) ||
(CreateDisposition == FILE_OPEN_IF)) &&
(!(DesiredAccess & FILE_WRITE_DATA))) {
do {
Status = NtCreateFile(FileHandle,
DesiredAccess & ~(FILE_WRITE_ATTRIBUTES),
ObjectAttributes,
IoStatus,
&AllocationSize,
FileAttributes,
ShareAccess,
CreateDisposition,
CreateOptions,
EaBuffer,
EaListLength
);
} while (RetryCreateOpen(Status, ObjectAttributes));
}
if (!(NT_SUCCESS(Status)))
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
KdPrint(("[%d,%d] St == %X\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
}
#endif
switch (Status) {
case STATUS_OBJECT_NAME_COLLISION:
RetCode = ERROR_ACCESS_DENIED;
break;
case STATUS_DISK_FULL:
if (CreateOptions & FILE_DIRECTORY_FILE) {
// FILIO014(test 2)
RetCode = ERROR_ACCESS_DENIED;
break;
}
case STATUS_OBJECT_NAME_INVALID:
RetCode = ERROR_FILENAME_EXCED_RANGE;
break;
case STATUS_FILE_IS_A_DIRECTORY:
if (!OpenDirectory) {
RetCode = ERROR_ACCESS_DENIED;
break;
}
// fall through
default:
RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND);
}
return (RetCode);
}
if (RetCode = MapFileType(*FileHandle,NULL, FileType, DeviceAttribute)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] Retcode == %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
RetCode));
KdPrint(("[%d,%d] returned from MapFileType\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
NtClose(*FileHandle);
return( ERROR_ACCESS_DENIED );
}
// //
// // the only time the following test should fail is if this routine
// // was called by Dos32Open and the path specified by the user was
// // a directory.
// //
//
// if (OpenDirectory != Directory) {
// NtClose(*FileHandle);
// return( ERROR_ACCESS_DENIED );
// }
return( NO_ERROR ); // success
}
APIRET
DosQueryFHState(
IN HFILE FileHandle,
OUT PULONG OpenMode
)
/*++
Routine Description:
This routine returns the open mode for a file handle.
Arguments:
FileHandle - OS/2 file handle
OpenMode - where to return open mode
Return Value:
ERROR_INVALID_HANDLE - the file handle is not open
--*/
{
APIRET RetCode;
PFILE_HANDLE hFileRecord;
#if DBG
PSZ RoutineName;
RoutineName = "DosQueryFHState";
#endif
AcquireFileLockShared(
#if DBG
RoutineName
#endif
);
//
// Check for invalid handle.
//
RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
if (RetCode) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
if (hFileRecord->FileType == FILE_TYPE_MAILSLOT) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return (ERROR_INVALID_HANDLE);
}
try {
*OpenMode = hFileRecord->Flags & QFHSTATE_FLAGS;
} except( EXCEPTION_EXECUTE_HANDLER ) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
Od2ExitGP();
}
// BUGBUG add test for psdev. if psdev, return device and no header.
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return NO_ERROR;
}
APIRET
NonFileSetHandleStateRoutine(
IN PFILE_HANDLE hFileRecord,
IN ULONG OpenMode
)
/*++
Routine Description:
This routine sets the open mode for a pipe handle.
Arguments:
hFileRecord - pointer to record of OS/2 pipe handle
OpenMode - open mode to set
Return Value:
TBS
Note:
FileLock must be owned exclusively when calling this routine.
--*/
{
hFileRecord->Flags &= ~SETFHSTATE_FLAGS;
hFileRecord->Flags |= OpenMode;
return NO_ERROR;
}
APIRET
FileSetHandleStateRoutine(
IN PFILE_HANDLE hFileRecord,
IN ULONG OpenMode
)
/*++
Routine Description:
This routine sets the open mode for a file handle.
Arguments:
hFileRecord - pointer to record of OS/2 file handle
OpenMode - open mode to set
Return Value:
TBS
Note:
FileLock must be owned exclusively when calling this routine.
--*/
{
NTSTATUS Status;
FILE_MODE_INFORMATION ModeInfo;
IO_STATUS_BLOCK IoStatus;
if (hFileRecord->FileType == FILE_TYPE_MAILSLOT) {
return (ERROR_INVALID_HANDLE);
}
if ((hFileRecord->FileType != FILE_TYPE_NMPIPE) &&
(hFileRecord->FileType != FILE_TYPE_PIPE)){
ModeInfo.Mode = FILE_SYNCHRONOUS_IO_NONALERT;
}
else {
ModeInfo.Mode = 0;
}
if (OpenMode & OPEN_FLAGS_WRITE_THROUGH)
ModeInfo.Mode |= FILE_WRITE_THROUGH;
do {
Status = NtSetInformationFile(hFileRecord->NtHandle,
&IoStatus,
&ModeInfo,
sizeof (ModeInfo),
FileModeInformation);
} while (RetryIO(Status, hFileRecord->NtHandle));
if (!(NT_SUCCESS(Status))) {
return (Or2MapNtStatusToOs2Error(Status, ERROR_GEN_FAILURE));
}
hFileRecord->Flags &= ~SETFHSTATE_FLAGS;
hFileRecord->Flags |= OpenMode;
return NO_ERROR;
}
APIRET
NoSuppSetHandleStateRoutine(
IN PFILE_HANDLE hFileRecord,
IN ULONG OpenMode
)
/*++
Routine Description:
This routine sets the open mode for a file handle.
Arguments:
hFileRecord - pointer to record of OS/2 file handle
OpenMode - open mode to set
Return Value:
TBS
Note:
FileLock must be owned exclusively when calling this routine.
--*/
{
UNREFERENCED_PARAMETER(hFileRecord);
UNREFERENCED_PARAMETER(OpenMode);
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] DosSetHandleState: not support for this handle\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return ERROR_NOT_SUPPORTED;
}
APIRET
DosSetFHState(
IN HFILE FileHandle,
IN ULONG OpenMode
)
/*++
Routine Description:
This routine sets the open mode for a file handle.
Arguments:
FileHandle - OS/2 file handle
OpenMode - open mode to set
Return Value:
ERROR_INVALID_PARAMETER - the open mode contains an illegal value
ERROR_INVALID_HANDLE - the file handle is not open
--*/
{
APIRET RetCode;
PFILE_HANDLE hFileRecord;
#if DBG
PSZ RoutineName;
RoutineName = "DosSetFHState";
#endif
AcquireFileLockExclusive(
#if DBG
RoutineName
#endif
);
//
// Check for invalid handle.
//
RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
if (RetCode) {
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return RetCode;
}
if (OpenMode & ~SETFHSTATE_FLAGS) {
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return ERROR_INVALID_PARAMETER;
}
RetCode = IoVectorArray[hFileRecord->IoVectorType]->SetHandleStateRoutine(hFileRecord,OpenMode);
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return RetCode;
}
APIRET
DeviceQueryHTypeRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PULONG HandleType,
OUT PULONG DeviceFlags
)
/*++
Routine Description:
This routine returns the handle type of con
Arguments:
hFileRecord - pointer to record of OS/2 con handle
HandleType - where to store the handle type
DeviceFlags - where to store the device flags
Return Value:
none
--*/
{
*DeviceFlags = hFileRecord->DeviceAttribute;
*HandleType = HANDTYPE_DEVICE;
return NO_ERROR;
}
APIRET
FileQueryHTypeRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PULONG HandleType,
OUT PULONG DeviceFlags
)
/*++
Routine Description:
This routine returns the handle type of file
Arguments:
hFileRecord - pointer to record of OS/2 kbd handle
HandleType - where to store the handle type
DeviceFlags - where to store the device flags
Return Value:
none
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
*DeviceFlags = hFileRecord->DeviceAttribute;
if ((hFileRecord->FileType == FILE_TYPE_NMPIPE) ||
(hFileRecord->FileType == FILE_TYPE_PIPE)) {
*HandleType = HANDTYPE_PIPE;
}
else if (hFileRecord->FileType == FILE_TYPE_MAILSLOT) {
return ERROR_INVALID_HANDLE;
}
else {
*HandleType = HANDTYPE_FILE;
do {
Status = NtQueryVolumeInformationFile(
hFileRecord->NtHandle,
&IoStatus,
&FsDeviceInfo,
sizeof(FsDeviceInfo),
FileFsDeviceInformation
);
} while (RetryIO(Status, hFileRecord->NtHandle));
if (NT_SUCCESS(Status) &&
(FsDeviceInfo.Characteristics & FILE_REMOTE_DEVICE)) {
*HandleType |= HANDTYPE_NETWORK;
}
}
return NO_ERROR;
}
APIRET
NoSuppQueryHTypeRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PULONG HandleType,
OUT PULONG DeviceFlags
)
/*++
Routine Description:
This routine returns the handle type of co
Arguments:
hFileRecord - pointer to record of OS/2 con handle
HandleType - where to store the handle type
DeviceFlags - where to store the device flags
Return Value:
none
--*/
{
UNREFERENCED_PARAMETER(hFileRecord);
UNREFERENCED_PARAMETER(HandleType);
UNREFERENCED_PARAMETER(DeviceFlags);
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] DosQueryHType: not support for this handle\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return ERROR_NOT_SUPPORTED;
}
APIRET
DosQueryHType(
IN HFILE FileHandle,
OUT PULONG HandleType,
OUT PULONG DeviceFlags
)
/*++
Routine Description:
This routine returns the handle type of a file (file, pipe, device, etc.)
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
C I O G C N S K
H B P LEVEL I L U C B
R M N O K L R D
*DeviceAttr = DEFAULT_DEVICE_ATTRIBUTE;
NUL and CLOCK devices are emulated by subsystem, so we set the bits on open
MapFileType figures out if block/char dev and removable media (if block device)
if (handle == 0)
Arguments:
FileHandle - OS/2 file handle
HandleType - where to store the handle type
DeviceFlags - where to store the device flags
Return Value:
ERROR_INVALID_HANDLE - the file handle is not open
--*/
{
PFILE_HANDLE hFileRecord;
APIRET RetCode;
#if DBG
PSZ RoutineName;
RoutineName = "DosQueryHType";
#endif
AcquireFileLockShared(
#if DBG
RoutineName
#endif
);
//
// Check for invalid handle.
//
RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
if (RetCode) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
//
// probe out parms here so code isn't duplicated.
//
try {
Od2ProbeForWrite(HandleType, sizeof(ULONG), 1);
Od2ProbeForWrite(DeviceFlags, sizeof(ULONG), 1);
} except( EXCEPTION_EXECUTE_HANDLER ) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
Od2ExitGP();
}
RetCode = IoVectorArray[hFileRecord->IoVectorType]->QueryHandleTypeRoutine(hFileRecord,HandleType,DeviceFlags);
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
APIRET
FileCloseRoutine(
IN PFILE_HANDLE hFileRecord
)
/*++
Routine Description:
This routine closes an OS/2 file handle. The handle is not freed.
Arguments:
VectorType - handle type
hFileRecord - pointer to record of OS/2 file handle to close.
Return Value:
TBS
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
InvalidateHandle(hFileRecord);
NtClose(hFileRecord->NtHandle);
return( NO_ERROR );
}
APIRET
DeviceCloseRoutine(
IN PFILE_HANDLE hFileRecord
)
/*++
Routine Description:
This routine closes an OS/2 handle to a device. The handle is not freed.
Arguments:
VectorType - device type
hFileRecord - pointer to record of OS/2 handle to close.
Return Value:
TBS
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
ULONG ShareAccess;
ULONG DesiredAccess;
//
// map share accesses
//
MapShareAccess(hFileRecord->Flags,&DesiredAccess,&ShareAccess);
InvalidateHandle(hFileRecord);
return Od2DeviceShare(RemoveShare,
hFileRecord->IoVectorType,
DesiredAccess,
ShareAccess
);
}
APIRET
KbdCloseRoutine(
IN PFILE_HANDLE hFileRecord
)
/*++
Routine Description:
This routine closes an OS/2 handle to a device. The handle is not freed.
Arguments:
VectorType - device type
hFileRecord - pointer to record of OS/2 handle to close.
Return Value:
TBS
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
ULONG ShareAccess;
ULONG DesiredAccess;
SCREQUESTMSG Request;
NTSTATUS Status;
//
// map share accesses
//
MapShareAccess(hFileRecord->Flags,&DesiredAccess,&ShareAccess);
InvalidateHandle(hFileRecord);
if (hFileRecord->DeviceAttribute & DEVICE_ATTRIBUTE_GENIOCTL)
{
return Od2DeviceShare(RemoveShare,
hFileRecord->IoVectorType,
DesiredAccess,
ShareAccess
);
} else
{
/*
* prepare Message parameters & send request to server (OS2)
*/
Request.d.Kbd.hKbd = hFileRecord->NtHandle;
Request.Request = KbdRequest;
Request.d.Kbd.Request = KBDClose;
Status = SendCtrlConsoleRequest(&Request, NULL, NULL, NULL);
return NO_ERROR;
}
}
APIRET
MouseCloseRoutine(
IN PFILE_HANDLE hFileRecord
)
/*++
Routine Description:
This routine closes an OS/2 handle to a device. The handle is not freed.
Arguments:
VectorType - device type
hFileRecord - pointer to record of OS/2 handle to close.
Return Value:
TBS
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
ULONG ShareAccess;
ULONG DesiredAccess;
APIRET ApiRet;
//
// map share accesses
//
MapShareAccess(hFileRecord->Flags,&DesiredAccess,&ShareAccess);
InvalidateHandle(hFileRecord);
ApiRet = Od2DeviceShare(RemoveShare,
hFileRecord->IoVectorType,
DesiredAccess,
ShareAccess
);
if (!ApiRet)
{
ApiRet = DevMouClose();
}
return ApiRet;
}
APIRET
ComCloseRoutine(
IN PFILE_HANDLE hFileRecord
)
/*++
Routine Description:
This routine closes an OS/2 COM handle. The handle is not freed.
Arguments:
VectorType - handle type
hFileRecord - pointer to record of OS/2 file handle to close.
Return Value:
TBS
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
InvalidateHandle(hFileRecord);
NtClose(hFileRecord->NtAsyncReadEvent);
NtClose(hFileRecord->NtAsyncWriteEvent);
NtClose(hFileRecord->NtAsyncIOCtlEvent);
NtClose(hFileRecord->NtHandle);
return( NO_ERROR );
}
APIRET
NoSuppCloseRoutine(
IN PFILE_HANDLE hFileRecord
)
/*++
Routine Description:
This routine closes an OS/2 handle to a device. The handle is not freed.
Arguments:
VectorType - device type
hFileRecord - pointer to record of OS/2 handle to close.
Return Value:
TBS
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
UNREFERENCED_PARAMETER(hFileRecord);
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] DosClose: not support for this handle\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return ERROR_NOT_SUPPORTED;
}
APIRET
Od2CloseHandle(
IN PFILE_HANDLE hFileRecord
)
/*++
Routine Description:
This routine closes an OS/2 file handle. The handle is not freed.
Arguments:
hFileRecord - pointer to record of OS/2 file handle to close.
Return Value:
TBS
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
return (IoVectorArray[hFileRecord->IoVectorType]->CloseRoutine(hFileRecord));
}
APIRET
FileDupHandleRoutine(
IN PFILE_HANDLE hOldFileRecord,
IN PFILE_HANDLE hNewFileRecord
)
/*++
Routine Description:
This routine duplicates an OS/2 file handle.
Arguments:
VectorType - handle type
hOldFileRecord - pointer to OS/2 file handle record to duplicate
hNewFileRecord - pointer to allocated new OS/2 file handle record
Return Value:
TBS.
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
NTSTATUS Status;
//
// duplicate the NT handle and copy the flags, etc here.
//
// duped handles are always inherited.
//
Status = NtDuplicateObject(NtCurrentProcess(),
hOldFileRecord->NtHandle,
NtCurrentProcess(),
&(hNewFileRecord->NtHandle),
(ACCESS_MASK) NULL,
OBJ_CASE_INSENSITIVE,
DUPLICATE_SAME_ACCESS
);
if (!NT_SUCCESS(Status)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] NtDuplicateObject failed in FileDupHandle. Status is = %X.\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
}
#endif
return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
}
hNewFileRecord->FileType = hOldFileRecord->FileType;
hNewFileRecord->IoVectorType = hOldFileRecord->IoVectorType;
//
// OS/2 sets the flags to zero in duped handle. this applies to the flags that are
// stored in the handle (inheritance, writethrough, cache, fail-error), but
// not to those stored in the SFT (access and sharing).
//
hNewFileRecord->Flags = hOldFileRecord->Flags & ~SETFHSTATE_FLAGS;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] HandleTable[OldFileHandle] flags = %ld NtHandle = %ld FileType = %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
hOldFileRecord->Flags,hOldFileRecord->NtHandle,hOldFileRecord->FileType));
KdPrint(("[%d,%d] HandleTable[NewFileHandle] flags = %ld NtHandle = %ld FileType = %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
hNewFileRecord->Flags,hNewFileRecord->NtHandle,hNewFileRecord->FileType));
}
#endif
ValidateHandle(hNewFileRecord);
return NO_ERROR;
}
APIRET
ComDupHandleRoutine(
IN PFILE_HANDLE hOldFileRecord,
IN PFILE_HANDLE hNewFileRecord
)
/*++
Routine Description:
This routine duplicates an OS/2 COM handle.
Arguments:
VectorType - handle type
hOldFileRecord - pointer to OS/2 file handle record to duplicate
hNewFileRecord - pointer to allocated new OS/2 file handle record
Return Value:
TBS.
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
NTSTATUS Status;
//
// duplicate the NT handle and copy the flags, etc here.
//
// duped handles are always inherited.
//
Status = NtDuplicateObject(NtCurrentProcess(),
hOldFileRecord->NtHandle,
NtCurrentProcess(),
&(hNewFileRecord->NtHandle),
(ACCESS_MASK) NULL,
OBJ_CASE_INSENSITIVE,
DUPLICATE_SAME_ACCESS
);
if (!NT_SUCCESS(Status)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] NtDuplicateObject failed in FileDupHandle. Status is = %X.\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
}
#endif
return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
}
hNewFileRecord->FileType = hOldFileRecord->FileType;
hNewFileRecord->IoVectorType = hOldFileRecord->IoVectorType;
Status = NtCreateEvent(&hNewFileRecord->NtAsyncReadEvent,
EVENT_ALL_ACCESS,
NULL,
SynchronizationEvent,
FALSE
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComRead, Status = %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
#endif
}
Status = NtCreateEvent(&hNewFileRecord->NtAsyncWriteEvent,
EVENT_ALL_ACCESS,
NULL,
SynchronizationEvent,
FALSE
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComWrite, Status = %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
#endif
}
Status = NtCreateEvent(&hNewFileRecord->NtAsyncIOCtlEvent,
EVENT_ALL_ACCESS,
NULL,
SynchronizationEvent,
FALSE
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComIOCtl, Status = %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
#endif
}
//
// OS/2 sets the flags to zero in duped handle. this applies to the flags that are
// stored in the handle (inheritance, writethrough, cache, fail-error), but
// not to those stored in the SFT (access and sharing).
//
hNewFileRecord->Flags = hOldFileRecord->Flags & ~SETFHSTATE_FLAGS;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] HandleTable[OldFileHandle] flags = %ld NtHandle = %ld FileType = %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
hOldFileRecord->Flags,hOldFileRecord->NtHandle,hOldFileRecord->FileType));
KdPrint(("[%d,%d] HandleTable[NewFileHandle] flags = %ld NtHandle = %ld FileType = %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
hNewFileRecord->Flags,hNewFileRecord->NtHandle,hNewFileRecord->FileType));
}
#endif
ValidateHandle(hNewFileRecord);
return NO_ERROR;
}
VOID
MapShareAccess(
IN ULONG OpenMode,
OUT PULONG DesiredAccess,
OUT PULONG ShareAccess
)
{
*ShareAccess = 0;
if (((OpenMode & SHARE_FLAGS) != (OPEN_SHARE_DENYREADWRITE)) &&
((OpenMode & SHARE_FLAGS) != (OPEN_SHARE_DENYREAD))) {
*ShareAccess |= FILE_SHARE_READ;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] setting read share access\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
}
if (((OpenMode & SHARE_FLAGS) != (OPEN_SHARE_DENYREADWRITE)) &&
((OpenMode & SHARE_FLAGS) != (OPEN_SHARE_DENYWRITE))) {
*ShareAccess |= FILE_SHARE_WRITE;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] setting write share access\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
}
//
// map requested access
//
*DesiredAccess = FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES;
if (((OpenMode & ACCESS_FLAGS) == OPEN_ACCESS_READONLY) ||
(OpenMode & OPEN_ACCESS_READWRITE)) {
*DesiredAccess |= FILE_READ_DATA;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] setting request read access\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
}
if (OpenMode & (OPEN_ACCESS_WRITEONLY | OPEN_ACCESS_READWRITE)) {
*DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] setting request write access\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
}
}
APIRET
DeviceDupHandleRoutine(
IN PFILE_HANDLE hOldFileRecord,
IN PFILE_HANDLE hNewFileRecord
)
/*++
Routine Description:
This routine duplicates an OS/2 handle to a device.
Arguments:
hOldFileRecord - pointer to OS/2 handle record to duplicate
hNewFileRecord - pointer to allocated new OS/2 handle record
Return Value:
TBS.
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
ULONG ShareAccess;
ULONG DesiredAccess;
APIRET RetCode;
// map share accesses
MapShareAccess(hOldFileRecord->Flags,&DesiredAccess,&ShareAccess);
RetCode = Od2DeviceShare(DupShare,
hOldFileRecord->IoVectorType,
DesiredAccess,
ShareAccess
);
if (RetCode != NO_ERROR)
{
ASSERT (FALSE);
return RetCode;
}
hNewFileRecord->Flags = hOldFileRecord->Flags & ~SETFHSTATE_FLAGS;
hNewFileRecord->NtHandle = hOldFileRecord->NtHandle;
hNewFileRecord->FileType = hOldFileRecord->FileType;
hNewFileRecord->IoVectorType = hOldFileRecord->IoVectorType;
ValidateHandle(hNewFileRecord);
return NO_ERROR;
}
APIRET
KbdDupHandleRoutine(
IN PFILE_HANDLE hOldFileRecord,
IN PFILE_HANDLE hNewFileRecord
)
/*++
Routine Description:
This routine duplicates an OS/2 handle to a device.
Arguments:
hOldFileRecord - pointer to OS/2 handle record to duplicate
hNewFileRecord - pointer to allocated new OS/2 handle record
Return Value:
TBS.
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
ULONG ShareAccess;
ULONG DesiredAccess;
APIRET RetCode;
// map share accesses
MapShareAccess(hOldFileRecord->Flags,&DesiredAccess,&ShareAccess);
if (hOldFileRecord->DeviceAttribute & DEVICE_ATTRIBUTE_GENIOCTL)
{
RetCode = Od2DeviceShare(DupShare,
hOldFileRecord->IoVectorType,
DesiredAccess,
ShareAccess
);
} else
{
RetCode = KbdDupLogHandle(hOldFileRecord->NtHandle);
}
if (RetCode != NO_ERROR)
{
ASSERT (FALSE);
return RetCode;
}
hNewFileRecord->Flags = hOldFileRecord->Flags & ~SETFHSTATE_FLAGS;
hNewFileRecord->NtHandle = hOldFileRecord->NtHandle;
hNewFileRecord->FileType = hOldFileRecord->FileType;
hNewFileRecord->IoVectorType = hOldFileRecord->IoVectorType;
ValidateHandle(hNewFileRecord);
return NO_ERROR;
}
APIRET
MouseDupHandleRoutine(
IN PFILE_HANDLE hOldFileRecord,
IN PFILE_HANDLE hNewFileRecord
)
/*++
Routine Description:
This routine duplicates an OS/2 handle to a device.
Arguments:
hOldFileRecord - pointer to OS/2 handle record to duplicate
hNewFileRecord - pointer to allocated new OS/2 handle record
Return Value:
TBS.
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
ULONG ShareAccess;
ULONG DesiredAccess;
APIRET RetCode;
// map share accesses
MapShareAccess(hOldFileRecord->Flags,&DesiredAccess,&ShareAccess);
RetCode = Od2DeviceShare(DupShare,
hOldFileRecord->IoVectorType,
DesiredAccess,
ShareAccess
);
if (RetCode != NO_ERROR)
{
ASSERT (FALSE);
return RetCode;
}
RetCode = DevMouOpen(&(hNewFileRecord->NtHandle));
if ( RetCode )
{
ASSERT(FALSE);
return(RetCode);
}
hNewFileRecord->Flags = hOldFileRecord->Flags & ~SETFHSTATE_FLAGS;
// hNewFileRecord->NtHandle = hOldFileRecord->NtHandle;
hNewFileRecord->FileType = hOldFileRecord->FileType;
hNewFileRecord->IoVectorType = hOldFileRecord->IoVectorType;
ValidateHandle(hNewFileRecord);
return NO_ERROR;
}
APIRET
NoSuppDupHandleRoutine(
IN PFILE_HANDLE hOldFileRecord,
IN PFILE_HANDLE hNewFileRecord
)
/*++
Routine Description:
This routine duplicates an OS/2 handle to a device.
Arguments:
hOldFileRecord - pointer to OS/2 handle record to duplicate
hNewFileRecord - pointer to allocated new OS/2 handle record
Return Value:
TBS.
Note:
exclusive File lock must be acquired BEFORE calling this routine
--*/
{
UNREFERENCED_PARAMETER(hOldFileRecord);
UNREFERENCED_PARAMETER(hNewFileRecord);
#if DBG
IF_OD2_DEBUG(FILESYS)
{
KdPrint(("[%d,%d] DosDupHandle: no support for this handle\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
return ERROR_NOT_SUPPORTED;
}
APIRET
DosDupHandle(
IN HFILE OldFileHandle,
IN OUT PHFILE NewFileHandle
)
/*++
Routine Description:
This routine duplicates an OS/2 file handle.
Arguments:
OldFileHandle - OS/2 file handle to duplicate
NewFileHandle - where to store new OS/2 file handle
Return Value:
ERROR_INVALID_HANDLE - the OldFileHandle is not open
ERROR_INVALID_TARGET_HANDLE - the NewFileHandle is not open
--*/
{
APIRET RetCode;
PFILE_HANDLE hOldFileRecord;
PFILE_HANDLE hNewFileRecord;
HFILE TargetHandle;
#if DBG
PSZ RoutineName;
RoutineName = "DosDupHandle";
#endif
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] entering DosDupHandle. OldFileHandle = %ld. NewFileHandle = %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
OldFileHandle,*NewFileHandle));
}
#endif
AcquireFileLockExclusive(
#if DBG
RoutineName
#endif
);
//
// Check for invalid source handle.
//
RetCode = DereferenceFileHandle(OldFileHandle,&hOldFileRecord);
if (RetCode) {
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return RetCode;
}
try {
TargetHandle = *NewFileHandle;
} except( EXCEPTION_EXECUTE_HANDLER ) {
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
Od2ExitGP();
}
//
// If user requested a new target handle, allocate one.
//
if (TargetHandle == (HFILE) DDH_NEW_HANDLE) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] allocating a new handle\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
if (RetCode = AllocateHandle(NewFileHandle)) {
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return RetCode;
}
hNewFileRecord = DereferenceFileHandleNoCheck(*NewFileHandle);
}
//
// Else, if the existing handle in the new slow is open, close it, but don't free it.
//
else {
//
// Check for invalid target handle
//
RetCode = DereferenceFileHandle(TargetHandle,&hNewFileRecord);
if (RetCode && (((ULONG) TargetHandle) >= HandleTableLength)) {
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return ERROR_INVALID_TARGET_HANDLE;
}
if (TargetHandle == OldFileHandle) {
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return ERROR_INVALID_TARGET_HANDLE;
}
if (RetCode) {
//
// A forced dup to a free handle - allocate
//
if (RetCode = AllocateHandle(NewFileHandle)) {
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return RetCode;
}
hNewFileRecord = DereferenceFileHandleNoCheck(*NewFileHandle);
}
else {
//
// The file handle is open - close it
//
RetCode = Od2CloseHandle(hNewFileRecord); // closes handle without freeing
}
}
//
// now duplicate the handle itself
//
RetCode = IoVectorArray[hOldFileRecord->IoVectorType]->DupHandleRoutine(hOldFileRecord,hNewFileRecord);
if (RetCode)
FreeHandle(*NewFileHandle);
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return RetCode;
}
APIRET
DosSetMaxFH(
IN ULONG MaxFileHandles
)
/*++
Routine Description:
This routine increases the size of the file handle table.
Arguments:
MaxFileHandles - new size of the file handle table.
Return Value:
ERROR_INVALID_PARAMETER - the new size is smaller than the old size.
--*/
{
PFILE_HANDLE NewTable;
ULONG i;
#if DBG
PSZ RoutineName;
RoutineName = "DosSetMaxFH";
#endif
//
// The maximum number of file handles
//
if (MaxFileHandles > 32768) {
return ERROR_INVALID_PARAMETER;
}
AcquireFileLockExclusive(
#if DBG
RoutineName
#endif
);
//
// if trying to shrink table, return error.
//
if (MaxFileHandles < HandleTableLength) {
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return ERROR_INVALID_PARAMETER;
}
//
// if no change in table size, return no error.
//
if (MaxFileHandles == HandleTableLength) {
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return NO_ERROR;
}
//
// allocate heap space for new table and copy old one over it.
// initialize new handles.
// if the old table was allocated from heap space, as opposed to instance
// data, free the space.
//
NewTable = RtlAllocateHeap(Od2Heap,0,MaxFileHandles * sizeof(FILE_HANDLE));
if (NewTable == NULL) {
#if DBG
KdPrint(("[%d,%d] OS2: DosSetMaxFH, no memory in Od2Heap\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
ASSERT(FALSE);
#endif
return ERROR_NOT_ENOUGH_MEMORY;
}
RtlMoveMemory(NewTable,HandleTable,HandleTableLength * sizeof(FILE_HANDLE));
for (i=HandleTableLength;i<MaxFileHandles;i++)
NewTable[i].Flags = FILE_HANDLE_FREE;
if (HandleTableLength != INITIALFILEHANDLES)
RtlFreeHeap(Od2Heap,0,HandleTable);
HandleTable = NewTable;
HandleTableLength = MaxFileHandles;
//
// print out handle table
//
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] new max file handles is %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
HandleTableLength));
}
#endif
for (i=0;i<MaxFileHandles;i++) {
if (NewTable[i].Flags == FILE_HANDLE_FREE) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] NewTable[%ld] is free\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
i));
}
#endif
}
else {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] NewTable[%ld] flags = %ld NtHandle = %ld FileType = %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
i,
NewTable[i].Flags,NewTable[i].NtHandle,NewTable[i].FileType));
}
#endif
}
}
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return NO_ERROR;
}
APIRET
DosClose(
IN HFILE FileHandle
)
/*++
Routine Description:
This routine closes an OS/2 file handle.
Arguments:
FileHandle - OS/2 file handle to close.
Return Value:
ERROR_INVALID_HANDLE - the file handle is not open
--*/
{
APIRET RetCode;
PFILE_HANDLE hFileRecord;
#if DBG
PSZ RoutineName;
RoutineName = "DosClose";
#endif
AcquireFileLockExclusive(
#if DBG
RoutineName
#endif
);
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] handle is %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
FileHandle));
KdPrint(("[%d,%d] HandleTableLength is %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
HandleTableLength));
}
#endif
//
// Check for invalid handle.
//
RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
if (RetCode) {
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return RetCode;
}
RetCode = Od2CloseHandle(hFileRecord); // this retcode is intentionally ignored
RetCode = FreeHandle(FileHandle);
ASSERT (!(RetCode));
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return NO_ERROR;
}
APIRET
ConReadRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesRead
)
/*++
Routine Description:
This routine reads from kbd.
Arguments:
hFileRecord - pointer to OS/2 file handle record to read from
Buffer - buffer to read data into
Length - length of buffer
BytesRead - where to store number of bytes read
Return Value:
TBS.
Note:
This routine releases the filelock.
--*/
{
NTSTATUS Status;
FILE_HANDLE KbdHandle;
#if DBG
PSZ RoutineName;
RoutineName = "ConReadRoutine";
#endif
#if DBG
IF_OD2_DEBUG(KBD)
{
KdPrint(("[%d,%d] ConReadRoutine: Length %lu, Handle %p\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Length,
hFileRecord ));
}
#endif
if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_WRITEONLY)
{
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return ERROR_ACCESS_DENIED;
}
/*
* CON handle cannot keep 2 handles in NtHandle field (for Screen & Kbd).
* So, we kkep only the VIO handle.
* For the read function, we prepare a dummy entry.
*/
KbdHandle = *hFileRecord;
KbdHandle.NtHandle = (HANDLE)SesGrp->PhyKbd;
Status = KbdRead(&KbdHandle, Buffer, Length, BytesRead, KBDRead);
return(Status);
}
APIRET
KbdReadRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesRead
)
/*++
Routine Description:
This routine reads from kbd.
Arguments:
hFileRecord - pointer to OS/2 file handle record to read from
Buffer - buffer to read data into
Length - length of buffer
BytesRead - where to store number of bytes read
Return Value:
TBS.
Note:
This routine releases the filelock.
--*/
{
NTSTATUS Status;
#if DBG
PSZ RoutineName;
RoutineName = "KbdReadRoutine";
#endif
#if DBG
IF_OD2_DEBUG(KBD)
{
KdPrint(("[%d,%d] KbdReadRoutine: Length %lu, Handle %p\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Length,
hFileRecord ));
}
#endif
if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_WRITEONLY)
{
ReleaseFileLockExclusive(
#if DBG
RoutineName
#endif
);
return ERROR_ACCESS_DENIED;
}
Status = KbdRead(hFileRecord, Buffer, Length, BytesRead, KBDRead);
return(Status);
}
APIRET
TmpReadRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesRead
)
/*++
Routine Description:
This routine returns an error.
Arguments:
hFileRecord - pointer to OS/2 file handle record to read from
Buffer - buffer to read data into
Length - length of buffer
BytesRead - where to store number of bytes read
Return Value:
TBS.
Note:
This routine releases the filelock.
--*/
{
APIRET RetCode;
#if DBG
PSZ RoutineName;
RoutineName = "TmpReadRoutine";
#endif
UNREFERENCED_PARAMETER(hFileRecord);
UNREFERENCED_PARAMETER(Buffer);
UNREFERENCED_PARAMETER(Length);
UNREFERENCED_PARAMETER(BytesRead);
if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_WRITEONLY)
{
RetCode = ERROR_ACCESS_DENIED;
} else
{
RetCode = ERROR_NOT_SUPPORTED;
}
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
APIRET
NulReadRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesRead
)
/*++
Routine Description:
This routine always returns success with the number of bytes read
equal to 0
Arguments:
hFileRecord - pointer to OS/2 file handle record to read from
Buffer - buffer to read data into
Length - length of buffer
BytesRead - where to store number of bytes read
Return Value:
TBS.
Note:
This routine releases the filelock.
--*/
{
APIRET RetCode;
#if DBG
PSZ RoutineName;
RoutineName = "NulReadRoutine";
#endif
UNREFERENCED_PARAMETER(Buffer);
UNREFERENCED_PARAMETER(Length);
if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_WRITEONLY)
{
RetCode = ERROR_ACCESS_DENIED;
} else
{
*BytesRead = 0;
RetCode = NO_ERROR;
}
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
APIRET
FileReadRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesRead
)
/*++
Routine Description:
This routine reads from an OS/2 file handle.
Arguments:
hFileRecord - pointer to OS/2 file handle record to read from
Buffer - buffer to read data into
Length - length of buffer
BytesRead - where to store number of bytes read
Return Value:
TBS.
Note:
This routine releases the filelock.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
LARGE_INTEGER FileOffset;
HANDLE NtHandle;
HANDLE Event;
BOOLEAN fNPipe;
#if DBG
PSZ RoutineName;
RoutineName = "FileReadRoutine";
#endif
// BUGBUG need to check for alignment and probe validity
FileOffset = RtlConvertLongToLargeInteger(FILE_USE_FILE_POINTER_POSITION);
NtHandle = hFileRecord->NtHandle;
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
fNPipe = ((hFileRecord->FileType == FILE_TYPE_NMPIPE) ||
(hFileRecord->FileType == FILE_TYPE_PIPE)) ? TRUE : FALSE;
if (fNPipe) {
Status = NtCreateEvent(&Event,
EVENT_ALL_ACCESS,
NULL,
SynchronizationEvent,
FALSE
);
if (Status != STATUS_SUCCESS) {
#if DBG
DbgPrint("[%d,%d] FileReadRoutine: Unable to NtCreateEvent(), Status 0x%x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status);
#endif
return( Status );
}
}
do {
Status = NtReadFile(NtHandle,
(fNPipe ? Event : (HANDLE)NULL),
(PIO_APC_ROUTINE) NULL,
(PVOID) NULL,
&IoStatus,
Buffer,
Length,
(fNPipe ? NULL : &FileOffset),
NULL
);
} while (RetryIO(Status, NtHandle));
//
// If the operation was successful, return the total number of bytes
// read, otherwise, if the error was STATUS_END_OF_FILE, return success,
// but no bytes transferred, otherwise, return an appropriate error.
//
if (NT_SUCCESS(Status) && !(Status == STATUS_PENDING)) {
*BytesRead = IoStatus.Information;
if (fNPipe) {
NtClose(Event);
}
return NO_ERROR;
} else if (Status == STATUS_END_OF_FILE) {
*BytesRead = 0;
if (fNPipe) {
NtClose(Event);
}
return NO_ERROR;
} else if ((Status == STATUS_PENDING) && fNPipe) {
Status = Od2AlertableWaitForSingleObject(Event);
NtClose(Event);
if (!NT_SUCCESS(Status)) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] ReadFileRoutine, Pipe, Status %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
}
#endif
*BytesRead = IoStatus.Information;
return ERROR_ACCESS_DENIED;
}
else {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] ReadFileRoutine, Pipe, Block completed successfully \n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesRead = IoStatus.Information;
return NO_ERROR;
}
} else {
if (fNPipe) {
NtClose(Event);
}
if (fNPipe) {
if (Status == STATUS_PIPE_EMPTY) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosRead Named pipe: STATUS_PIPE_EMPTY\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
// *BytesRead = IoStatus.Information;
*BytesRead = 0;
return ERROR_NO_DATA;
}
else if (Status == STATUS_END_OF_FILE) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosRead Named pipe: STATUS_END_OF_FILE\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesRead = 0;
return NO_ERROR;
}
else if (Status == STATUS_PIPE_BROKEN) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosRead Named pipe: STATUS_PIPE_BROKEN\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesRead = 0;
//return ERROR_BROKEN_PIPE;
//
// Return NO_ERROR for compatibility (SQL server, setup).
//
return NO_ERROR;
}
else if (Status == STATUS_PIPE_LISTENING) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosRead Named pipe: STATUS_PIPE_LISTEMING\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesRead = 0;
return NO_ERROR;
}
else if (Status == STATUS_INVALID_PIPE_STATE) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosRead Named pipe: STATUS_INVALID_PIPE_STATE\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesRead = 0;
return ERROR_PIPE_NOT_CONNECTED;
}
else if (Status == STATUS_PIPE_DISCONNECTED) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosRead Named pipe: STATUS_PIPE_DISCONNECTED\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesRead = 0;
return ERROR_PIPE_NOT_CONNECTED;
}
else if (Status == STATUS_ACCESS_DENIED) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosRead Named pipe: STATUS_ACCESS_DENIED\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesRead = 0;
return ERROR_ACCESS_DENIED;
}
else if (Status == STATUS_BUFFER_OVERFLOW) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosRead Named pipe: STATUS_BUFFER_OVERFLOW\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesRead = IoStatus.Information;
return ERROR_MORE_DATA;
}
else {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosRead on a named pipe - map status %lx to ERROR_ACCESS_DENIED\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
}
#endif
*BytesRead = 0;
return ERROR_ACCESS_DENIED; // BUGBUG bogus error
}
}
else {
*BytesRead = 0;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] DosRead (not a named pipe) - returned status %lx\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
}
#endif
return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
}
}
}
APIRET
DosRead(
IN HFILE FileHandle,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesRead
)
/*++
Routine Description:
This routine reads from an OS/2 file handle.
Arguments:
FileHandle - OS/2 file handle to read from.
Buffer - buffer to read data into
Length - length of buffer
BytesRead - where to store number of bytes read
Return Value:
ERROR_INVALID_HANDLE - the file handle is not open
ERROR_ACCESS_DENIED - the file handle is not open in a mode which allows
reading
--*/
{
APIRET RetCode;
PFILE_HANDLE hFileRecord;
#if DBG
PSZ RoutineName;
RoutineName = "DosRead";
#endif
AcquireFileLockShared(
#if DBG
RoutineName
#endif
);
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] DosRead: handle is %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
FileHandle));
}
#endif
//
// Check for invalid handle.
//
try {
Od2ProbeForWrite(BytesRead, sizeof(ULONG), 1);
Od2ProbeForWrite(Buffer,Length,1);
} except( EXCEPTION_EXECUTE_HANDLER ) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
Od2ExitGP();
}
RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
if (RetCode) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
if (Length == 0) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
*BytesRead = 0;
return NO_ERROR;
}
RetCode = IoVectorArray[hFileRecord->IoVectorType]->ReadRoutine(hFileRecord,
Buffer,
Length,
BytesRead);
#if DBG
IF_OD2_DEBUG( PIPES ) {
if ((hFileRecord->FileType == FILE_TYPE_NMPIPE) ||
(hFileRecord->FileType == FILE_TYPE_PIPE)) {
KdPrint(("[%d,%d] DosRead on Named pipe: Handle %ld Status %ld Bytes Requested %d Bytes Read %d\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
FileHandle, RetCode, Length, *BytesRead));
}
}
#endif
return RetCode;
}
APIRET
FileWriteRoutine(
IN PFILE_HANDLE hFileRecord,
IN PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesWritten
)
/*++
Routine Description:
This routine writes to an OS/2 file handle.
Arguments:
hFileRecord - pointer to OS/2 file handle record to write to
Buffer - buffer to write data to
Length - length of buffer
BytesWritten - where to store number of bytes written
Return Value:
TBS
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
LARGE_INTEGER FileOffset;
HANDLE NtHandle;
HANDLE Event;
BOOLEAN fNPipe;
#if DBG
PSZ RoutineName;
RoutineName = "FileWriteRoutine";
#endif
// BUGBUG need to check for alignment and probe validity
FileOffset = RtlConvertLongToLargeInteger(FILE_USE_FILE_POINTER_POSITION);
NtHandle = hFileRecord->NtHandle;
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
fNPipe = ((hFileRecord->FileType == FILE_TYPE_NMPIPE) ||
(hFileRecord->FileType == FILE_TYPE_PIPE)) ? TRUE : FALSE;
if (fNPipe) {
Status = NtCreateEvent(&Event,
EVENT_ALL_ACCESS,
NULL,
SynchronizationEvent,
FALSE
);
if (Status != STATUS_SUCCESS) {
#if DBG
DbgPrint("[%d,%d] FileWriteRoutine: Unable to NtCreateEvent(), Status 0x%x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status);
#endif
return( Status );
}
}
do {
Status = NtWriteFile(NtHandle,
(fNPipe ? Event : (HANDLE)NULL),
(PIO_APC_ROUTINE) NULL,
(PVOID) NULL,
&IoStatus,
Buffer,
Length,
(fNPipe ? NULL : &FileOffset),
NULL
);
} while (RetryIO(Status, NtHandle));
//
// If the write was successful, then return the correct number of bytes to
// the caller. If the error was STATUS_DISK_FULL, return 0 bytes written,
// but no error to the caller. Otherwise, figure out an appropriate error
// and return that error.
//
if (NT_SUCCESS(Status) && !(Status == STATUS_PENDING)) {
*BytesWritten = IoStatus.Information;
if (!NT_SUCCESS(IoStatus.Status)){
#if DBG
KdPrint(("[%d,%d] WriteFileRoutine, Pipe, Status SUCCESS, IoStatus %lx\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
IoStatus.Status));
#endif
}
if (fNPipe) {
NtClose(Event);
}
return NO_ERROR;
} else if (Status == STATUS_DISK_FULL) {
*BytesWritten = 0;
if (fNPipe) {
NtClose(Event);
}
return NO_ERROR;
} else if ((Status == STATUS_PENDING) && fNPipe) {
Status = Od2AlertableWaitForSingleObject(Event);
NtClose(Event);
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_PIPE_DISCONNECTED) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_PIPE_DISCONNECTED\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesWritten = 0;
return ERROR_PIPE_NOT_CONNECTED;
}
else {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] WriteFileRoutine, Pipe, Status %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
}
#endif
*BytesWritten = 0;
return ERROR_ACCESS_DENIED;
}
}
else {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] WriteFileRoutine, Pipe, Blocking succeeded\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesWritten = IoStatus.Information;
return NO_ERROR;
}
} else {
if (fNPipe) {
NtClose(Event);
}
if (fNPipe) {
if (Status == STATUS_PIPE_EMPTY) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_PIPE_EMPTY\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesWritten = IoStatus.Information;
return ERROR_NO_DATA;
}
if (Status == STATUS_END_OF_FILE) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_END_OF_FILE\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesWritten = 0;
return NO_ERROR;
}
if (Status == STATUS_PIPE_DISCONNECTED) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_PIPE_DISCONNECTED\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesWritten = 0;
return ERROR_PIPE_NOT_CONNECTED;
}
if (Status == STATUS_PIPE_BROKEN) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_PIPE_BROKEN\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesWritten = 0;
//return ERROR_BROKEN_PIPE;
//
// Return NO_ERROR for compatibility (SQL server, setup).
//
return NO_ERROR;
}
if (Status == STATUS_PIPE_CLOSING) {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_PIPE_CLOSING\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
*BytesWritten = 0;
return ERROR_BROKEN_PIPE;
}
else {
#if DBG
IF_OD2_DEBUG( PIPES ) {
KdPrint(("[%d,%d] WriteFileRoutine, Pipe, Status %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
}
#endif
*BytesWritten = 0;
return ERROR_ACCESS_DENIED; // BUGBUG bogus error
}
}
else {
*BytesWritten = 0;
return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
}
}
}
APIRET
TmpWriteRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesWritten
)
/*++
Routine Description:
This routine returns an error.
Arguments:
hFileRecord - pointer to OS/2 pipe handle record to write to
Buffer - buffer to write data to
Length - length of buffer
BytesWritten - where to store number of bytes written
Return Value:
TBS.
Note:
This routine releases the filelock.
--*/
{
APIRET RetCode;
#if DBG
PSZ RoutineName;
RoutineName = "TmpWriteRoutine";
#endif
UNREFERENCED_PARAMETER(Buffer);
UNREFERENCED_PARAMETER(Length);
UNREFERENCED_PARAMETER(BytesWritten);
if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_READONLY)
{
RetCode = ERROR_ACCESS_DENIED;
} else
{
RetCode = ERROR_NOT_SUPPORTED;
}
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
APIRET
NulWriteRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesWritten
)
/*++
Routine Description:
This routine always returns success with the number of bytes written
equal to Length.
Arguments:
hFileRecord - pointer to OS/2 pipe handle record to write to
Buffer - buffer to write data to
Length - length of buffer
BytesWritten - where to store number of bytes written
Return Value:
TBS.
Note:
This routine releases the filelock.
--*/
{
APIRET RetCode;
#if DBG
PSZ RoutineName;
RoutineName = "NulWriteRoutine";
#endif
UNREFERENCED_PARAMETER(Buffer);
UNREFERENCED_PARAMETER(Length);
if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_READONLY)
{
RetCode = ERROR_ACCESS_DENIED;
} else
{
*BytesWritten = Length;
RetCode = NO_ERROR;
}
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
APIRET
ScreenWriteRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesWritten
)
/*++
Routine Description:
This routine write to the con.
Arguments:
hFileRecord - pointer to OS/2 pipe handle record to write to
Buffer - buffer to write data to
Length - length of buffer
BytesWritten - where to store number of bytes written
Return Value:
TBS.
Note:
This routine releases the filelock.
--*/
{
APIRET RetCode;
ULONG Flags;
#if DBG
PSZ RoutineName;
RoutineName = "ScreenWriteRoutine";
#endif
#if DBG
IF_OD2_DEBUG(VIO_FILE)
{
KdPrint(("[%d,%d] ScreenWriteRoutine: Length %lu, Handle %p\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Length, hFileRecord ));
}
#endif
Flags = hFileRecord->Flags;
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
if ((Flags & ACCESS_FLAGS ) == OPEN_ACCESS_READONLY)
{
RetCode = ERROR_ACCESS_DENIED;
} else
{
RetCode = VioWrite(hFileRecord, Buffer, Length, BytesWritten, VIOWrtScreen);
}
return(RetCode);
}
APIRET
DosWrite(
IN HFILE FileHandle,
IN PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesWritten
)
/*++
Routine Description:
This routine writes to an OS/2 file handle.
Arguments:
FileHandle - OS/2 file handle to write to.
Buffer - buffer to write data to
Length - length of buffer
BytesWritten - where to store number of bytes written
Return Value:
ERROR_INVALID_HANDLE - the file handle is not open
ERROR_ACCESS_DENIED - the file handle is not open in a mode which allows
writing
--*/
{
APIRET RetCode;
PFILE_HANDLE hFileRecord;
#if DBG
PSZ RoutineName;
RoutineName = "DosWrite";
#endif
AcquireFileLockShared(
#if DBG
RoutineName
#endif
);
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] Entering DosWrite with handle %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
FileHandle));
}
#endif
//
// Check for invalid handle.
//
try {
Od2ProbeForWrite(BytesWritten, sizeof(ULONG), 1);
Od2ProbeForRead(Buffer,Length,1);
} except( EXCEPTION_EXECUTE_HANDLER ) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
Od2ExitGP();
}
RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
if (RetCode) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
if (Length == 0) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
*BytesWritten = 0;
return NO_ERROR;
}
RetCode = IoVectorArray[hFileRecord->IoVectorType]->WriteRoutine(hFileRecord,
Buffer,
Length,
BytesWritten);
#if DBG
IF_OD2_DEBUG( PIPES ) {
if ((hFileRecord->FileType == FILE_TYPE_NMPIPE) ||
(hFileRecord->FileType == FILE_TYPE_PIPE)) {
KdPrint(("[%d,%d] DosWrite on Named pipe: Handle %ld Status %ld Bytes Requested %d Bytes Written %d\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
FileHandle, RetCode, Length, *BytesWritten));
}
}
#endif
return RetCode;
}
APIRET
DosSetFileSize(
IN HFILE FileHandle,
IN ULONG NewFileSize
)
/*++
Routine Description:
This routine changes the size of a file.
Arguments:
FileHandle - OS/2 file handle of file to change size of
NewFileSize - new size of file
Return Value:
ERROR_INVALID_HANDLE - the file handle is not open
--*/
{
APIRET RetCode;
PFILE_HANDLE hFileRecord;
HANDLE NtHandle;
#if DBG
PSZ RoutineName;
RoutineName = "DosSetFileSize";
#endif
//
// do a very stupid parameter check for compatibility.
//
if ((LONG)NewFileSize < 0)
return ERROR_INVALID_PARAMETER;
// OS/2 doesn't change file pointer for this call
AcquireFileLockShared(
#if DBG
RoutineName
#endif
);
//
// Check for invalid handle.
//
RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
if (RetCode) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
if (hFileRecord->FileType &
(FILE_TYPE_DEV | FILE_TYPE_PIPE | FILE_TYPE_NMPIPE | FILE_TYPE_MAILSLOT)) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return ERROR_INVALID_HANDLE;
}
NtHandle = hFileRecord->NtHandle;
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
RetCode = UpdateFileSize(NtHandle,NewFileSize);
return RetCode;
}
APIRET
FlushOneFile(
IN PFILE_HANDLE hFileRecord
)
/*++
Routine Description:
This routine flushes the buffers for one file
Arguments:
FileHandle - OS/2 file handle of file to flush buffers for
Return Value:
ERROR_INVALID_ACCESS - ??
--*/
{
IO_STATUS_BLOCK IoStatus;
NTSTATUS Status;
if (hFileRecord->Flags & (OPEN_ACCESS_WRITEONLY | OPEN_ACCESS_READWRITE)) {
Status = NtFlushBuffersFile(hFileRecord->NtHandle,
&IoStatus);
if (!(NT_SUCCESS(Status))) {
return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS));
}
}
return NO_ERROR;
}
APIRET
DosResetBuffer(
IN HFILE FileHandle
)
/*++
Routine Description:
This routine flushes the buffers for one file or all of a process's files
Arguments:
FileHandle - OS/2 file handle of file to flush buffers for
Return Value:
ERROR_INVALID_HANDLE - the file handle is not open
--*/
{
ULONG i;
APIRET RetCode;
PFILE_HANDLE hFileRecord;
#if DBG
PSZ RoutineName;
RoutineName = "DosResetBuffer";
#endif
AcquireFileLockShared(
#if DBG
RoutineName
#endif
);
//
// 0xFFFF means Flush All handles
//
if (((USHORT) FileHandle) != 0xFFFF) {
//
// Check for invalid handle.
//
RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
if (RetCode) {
;
}
else if (hFileRecord->FileType &
(FILE_TYPE_DEV | FILE_TYPE_MAILSLOT)) {
RetCode = ERROR_INVALID_HANDLE;
}
else {
RetCode = FlushOneFile(hFileRecord);
}
}
else {
RetCode = NO_ERROR;
for (i=0;i<HandleTableLength;i++) {
hFileRecord = DereferenceFileHandleNoCheck((HFILE) i);
if ((hFileRecord->Flags & FILE_HANDLE_VALID) &&
(!(hFileRecord->FileType &
(FILE_TYPE_DEV | FILE_TYPE_MAILSLOT)))) {
if (RetCode = FlushOneFile(hFileRecord)) {
break;
}
}
}
}
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
APIRET
DosSetFilePtr(
IN HFILE FileHandle,
IN LONG StartingFilePosition,
IN ULONG NewFilePosition,
IN OUT PULONG CurrentFilePosition
)
/*++
Routine Description:
This routine sets the file pointer for a file
Arguments:
FileHandle - OS/2 file handle of file to set file pointer for
StartingFilePosition - number of bytes to seek by
NewFilePosition - whether to seek from the beginning, current file
position, or end of the file.
CurrentFilePosition - where to store the new current file position
Return Value:
ERROR_INVALID_HANDLE - the file handle is not open
ERROR_SEEK_ON_DEVICE - the handle is for a device or pipe
ERROR_INVALID_FUNCTION - the NewFilePosition parameter contains an
invalid value
--*/
{
FILE_POSITION_INFORMATION PositionInfo;
FILE_STANDARD_INFORMATION StandardInfo;
IO_STATUS_BLOCK IoStatus;
LONG NewPosition;
NTSTATUS Status;
HANDLE NtHandle;
APIRET RetCode;
PFILE_HANDLE hFileRecord;
#if DBG
PSZ RoutineName;
RoutineName = "DosSetFilePtr";
#endif
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] *** entering DosSetFilePtr , handle is %d ***\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
FileHandle
));
}
#endif
AcquireFileLockShared(
#if DBG
RoutineName
#endif
);
//
// Check for invalid handle.
//
RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
if (RetCode != NO_ERROR) {
;
}
else if (hFileRecord->FileType &
(FILE_TYPE_DEV | FILE_TYPE_PIPE | FILE_TYPE_NMPIPE | FILE_TYPE_MAILSLOT)) {
RetCode = ERROR_SEEK_ON_DEVICE;
}
else if (NewFilePosition > FILE_END) {
RetCode = ERROR_INVALID_FUNCTION;
}
if (RetCode != NO_ERROR) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
//
// no serialization around the query/set calls is needed because
// if the app duped/inherited handles, so that there are multiple processes
// have handles to the same seek pointer, it can't depend on the order in
// which multiple I/O operations to that handle happen.
//
NtHandle = hFileRecord->NtHandle;
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
if (NewFilePosition == FILE_BEGIN) {
NewPosition = StartingFilePosition;
}
else if (NewFilePosition == FILE_CURRENT) {
//
// READ or WRITE access is required to get position information.
//
do {
Status = NtQueryInformationFile(NtHandle,
&IoStatus,
&PositionInfo,
sizeof (PositionInfo),
FilePositionInformation);
} while (RetryIO(Status, NtHandle));
if (!(NT_SUCCESS(Status))) {
return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS));
}
// BUGBUG - Therese, what do we do here if .HighPart is non-zero
NewPosition = PositionInfo.CurrentByteOffset.LowPart +
StartingFilePosition;
}
else if (NewFilePosition == FILE_END) {
//
// no access is required to get standard information.
//
do {
Status = NtQueryInformationFile(NtHandle,
&IoStatus,
&StandardInfo,
sizeof (StandardInfo),
FileStandardInformation
);
} while (RetryIO(Status, NtHandle));
if (!(NT_SUCCESS(Status))) {
return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS));
}
// BUGBUG - Therese, what do we do here if an overflow occurs or if
// the .HighPart is non-zero? The old code potentially had
// the overflow problem as well.
NewPosition = StandardInfo.EndOfFile.LowPart + StartingFilePosition;
}
else
ASSERT ( FALSE ); // we should never get here because we checked
// the NewPosition parameter above
if (NewPosition < 0) {
return ERROR_NEGATIVE_SEEK;
}
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] new position is %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
NewPosition));
}
#endif
if (NewPosition == 0) {
PositionInfo.CurrentByteOffset.LowPart = 0;
PositionInfo.CurrentByteOffset.HighPart = 0;
}
else {
// BUGBUG - Therese, same .HighPart problem. Also, why the -1?
PositionInfo.CurrentByteOffset.LowPart = NewPosition;
PositionInfo.CurrentByteOffset.HighPart = 0;;
// PositionInfo.CurrentBlock = BYTES_TO_BLOCKS(NewPosition) - 1;
// PositionInfo.CurrentByte = BYTES_TO_OFFSET(NewPosition);
}
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] Current Byte Low = %ld Current Byte High = %ld\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
PositionInfo.CurrentByteOffset.LowPart,PositionInfo.CurrentByteOffset.HighPart));
}
#endif
do {
Status = NtSetInformationFile(NtHandle,
&IoStatus,
&PositionInfo,
sizeof (PositionInfo),
FilePositionInformation);
} while (RetryIO(Status, NtHandle));
if (!(NT_SUCCESS(Status))) {
return (Or2MapNtStatusToOs2Error(Status, ERROR_GEN_FAILURE));
}
try {
*CurrentFilePosition = NewPosition;
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
return NO_ERROR;
}
APIRET
DosFileLocks(
IN HFILE FileHandle,
IN PFILELOCK UnlockRequest,
IN PFILELOCK LockRequest
)
/*++
Routine Description:
This routine locks and/or unlocks a region of a file
Arguments:
FileHandle - OS/2 file handle of file to lock/unlock region of
UnlockRequest - range to unlock in file
LockRequest - range to lock in file
Return Value:
ERROR_INVALID_HANDLE - the file handle is not open
ERROR_LOCK_VIOLATION - lock conflicted with existing lock or unlock
specified non-locked region.
--*/
{
IO_STATUS_BLOCK IoStatus;
LARGE_INTEGER FileOffset;
LARGE_INTEGER FileLength;
NTSTATUS Status;
ULONG Key;
HANDLE NtHandle;
APIRET RetCode;
PFILE_HANDLE hFileRecord;
LONG Range;
#if DBG
PSZ RoutineName = "DosFileLocks";
#endif
//
// The usage of Key: A combination of KEY == NULL and EXCLUSIVE == TRUE
// in NtLockFile() let us NtReadFile()/NtWriteFile() on that
// region with KEY == NULL from the same process but not from
// another process. A combination of KEY == pid and EXCLUSIVE == FALSE
// in NtLockFile() let us NtReadFile() with KEY == NULL from every
// process, and doesn't let us NtWriteFile() with KEY == NULL from any
// process, incuding the owner of the locked region.
//
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("[%d,%d] *** entering DosFileLocks ***\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId()
));
}
#endif
AcquireFileLockShared( // prevent file handle from going away
#if DBG
RoutineName
#endif
);
//
// Check for invalid handle.
//
RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
if (RetCode) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
if (hFileRecord->FileType &
(FILE_TYPE_DEV | FILE_TYPE_PIPE | FILE_TYPE_NMPIPE | FILE_TYPE_MAILSLOT)) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return ERROR_INVALID_HANDLE;
}
Key = (ULONG) Od2Process->Pib.ProcessId;
NtHandle = hFileRecord->NtHandle;
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
if (UnlockRequest != NULL) {
try {
FileOffset = RtlConvertLongToLargeInteger(UnlockRequest->lOffset);
Range = UnlockRequest->lRange;
FileLength = RtlConvertLongToLargeInteger(Range);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
if (Range == 0)
return ERROR_LOCK_VIOLATION;
Status = NtUnlockFile(NtHandle,
&IoStatus,
&FileOffset,
&FileLength,
(ULONG) NULL // try it once with key == NULL
);
if (!(NT_SUCCESS(Status))) {
Status = NtUnlockFile(NtHandle,
&IoStatus,
&FileOffset,
&FileLength,
Key // try it again with key == pid
);
}
if (!(NT_SUCCESS(Status))) {
return (Or2MapNtStatusToOs2Error(Status, ERROR_LOCK_VIOLATION));
}
}
if (LockRequest != NULL) {
try {
FileOffset = RtlConvertLongToLargeInteger(LockRequest->lOffset);
Range = LockRequest->lRange;
FileLength = RtlConvertLongToLargeInteger(Range);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
if (Range == 0)
return ERROR_LOCK_VIOLATION;
Status = NtLockFile(NtHandle,
(HANDLE) NULL,
(PIO_APC_ROUTINE) NULL,
(PVOID) NULL,
&IoStatus,
&FileOffset,
&FileLength,
(ULONG)NULL,
(BOOLEAN)TRUE,
(BOOLEAN)TRUE
);
if (!(NT_SUCCESS(Status))) {
return (Or2MapNtStatusToOs2Error(Status, ERROR_LOCK_VIOLATION));
}
}
return NO_ERROR;
}
APIRET
DosSetFileLocks(
IN HFILE FileHandle,
IN PFILELOCK UnlockRequest,
IN PFILELOCK LockRequest
)
{
return (DosFileLocks(FileHandle, UnlockRequest, LockRequest));
}
APIRET
DummyApiRoutine(
IN PULONG OutData
);
APIRET
DummyApiRoutine(
IN PULONG OutData
)
{
try {
*OutData = 0;
}
except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
return( NO_ERROR );
}
APIRET
ComReadRoutine(
IN PFILE_HANDLE hFileRecord,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesRead
)
/*++
Routine Description:
This routine reads from an OS/2 file handle.
Arguments:
hFileRecord - pointer to OS/2 file handle record to read from
Buffer - buffer to read data into
Length - length of buffer
BytesRead - where to store number of bytes read
Return Value:
TBS.
Note:
This routine releases the filelock.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus, IoStatus2;
LARGE_INTEGER FileOffset;
HANDLE NtHandle;
HANDLE ComReadEvent;
#if DBG
PSZ RoutineName;
RoutineName = "ComReadRoutine";
#endif
// BUGBUG need to check for alignment and probe validity
FileOffset = RtlConvertLongToLargeInteger(0);
NtHandle = hFileRecord->NtHandle;
ComReadEvent = hFileRecord->NtAsyncReadEvent;
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
IoStatus.Status = STATUS_PENDING;
IoStatus.Information = 0L;
Status = NtReadFile(NtHandle,
ComReadEvent,
(PIO_APC_ROUTINE) NULL,
(PVOID) NULL,
&IoStatus,
Buffer,
Length,
&FileOffset,
NULL
);
//
// If the operation was successful, return the total number of bytes
// read, otherwise, if the error was STATUS_END_OF_FILE, return success,
// but no bytes transferred, otherwise, return an appropriate error.
//
if (Status == STATUS_SUCCESS) {
*BytesRead = IoStatus.Information;
return NO_ERROR;
} else if (Status == STATUS_END_OF_FILE) {
*BytesRead = 0;
return NO_ERROR;
} else if (Status == STATUS_PENDING) {
Status = Od2AlertableWaitForSingleObject(ComReadEvent);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("[%d,%d] OS2DLL: COM Read error: Status = %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
#endif
*BytesRead = IoStatus.Information;
return ERROR_ACCESS_DENIED;
}
else {
if (IoStatus.Status == STATUS_PENDING) {
Status = NtCancelIoFile(
NtHandle,
&IoStatus2
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("[%d,%d] OS2DLL: COM Cancel Read Io error: Status = %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
#endif
*BytesRead = IoStatus.Information;
return ERROR_ACCESS_DENIED;
} else {
do {
Status = Od2AlertableWaitForSingleObject(ComReadEvent);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("[%d,%d] OS2DLL: COM Read error (2): Status = %x\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
Status));
#endif
*BytesRead = IoStatus.Information;
return ERROR_ACCESS_DENIED;
}
} while ( IoStatus.Status == STATUS_PENDING );
}
}
*BytesRead = IoStatus.Information;
return NO_ERROR;
}
}
else {
*BytesRead = 0;
return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
}
}
APIRET
ComWriteRoutine(
IN PFILE_HANDLE hFileRecord,
IN PVOID Buffer,
IN ULONG Length,
OUT PULONG BytesWritten
)
/*++
Routine Description:
This routine writes to an OS/2 file handle.
Arguments:
hFileRecord - pointer to OS/2 file handle record to write to
Buffer - buffer to write data to
Length - length of buffer
BytesWritten - where to store number of bytes written
Return Value:
TBS
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
LARGE_INTEGER FileOffset;
HANDLE NtHandle;
HANDLE ComWriteEvent;
#if DBG
PSZ RoutineName;
RoutineName = "ComWriteRoutine";
#endif
// BUGBUG need to check for alignment and probe validity
FileOffset = RtlConvertLongToLargeInteger(0);
NtHandle = hFileRecord->NtHandle;
ComWriteEvent = hFileRecord->NtAsyncWriteEvent;
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
Status = NtWriteFile(NtHandle,
ComWriteEvent,
(PIO_APC_ROUTINE) NULL,
(PVOID) NULL,
&IoStatus,
Buffer,
Length,
&FileOffset,
NULL
);
//
// If the write was successful, then return the correct number of bytes to
// the caller. If the error was STATUS_DISK_FULL, return 0 bytes written,
// but no error to the caller. Otherwise, figure out an appropriate error
// and return that error.
//
if (Status == STATUS_SUCCESS) {
*BytesWritten = IoStatus.Information;
if (!NT_SUCCESS(IoStatus.Status)){
#if DBG
KdPrint(("[%d,%d] ComWriteRoutine, Status SUCCESS, IoStatus %lx\n",
Od2Process->Pib.ProcessId,
Od2CurrentThreadId(),
IoStatus.Status));
#endif
}
return NO_ERROR;
} else if (Status == STATUS_PENDING) {
Status = Od2AlertableWaitForSingleObject(ComWriteEvent);
if (!NT_SUCCESS(Status)) {
*BytesWritten = 0;
return ERROR_ACCESS_DENIED;
}
else {
*BytesWritten = IoStatus.Information;
return NO_ERROR;
}
} else {
*BytesWritten = 0;
return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
}
}