|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
fdio.c
Abstract:
Implementation of PSX file descriptor io.
Author:
Mark Lucovsky (markl) 08-Mar-1989
Revision History:
--*/
#include "psxsrv.h"
//
// This lock must be held while updating handle counts on system open file
// descriptors.
//
RTL_CRITICAL_SECTION SystemOpenFileLock;
//
// This lock must be held while updating reference counts on IONODES, and
// when scanning the IoNodeHashTable searching for an IoNode.
//
RTL_CRITICAL_SECTION IoNodeHashTableLock;
//
// IoNode Id Hash Table.
//
// Given a FileSerialNumber and DeviceSerialNumber, an IONODE can be located in
// the IoNodeHashTable.
//
LIST_ENTRY IoNodeHashTable[IONODEHASHSIZE];
BOOLEAN ReferenceOrCreateIoNode ( IN dev_t DeviceSerialNumber, IN ULONG_PTR FileSerialNumber, IN BOOLEAN FindOnly, OUT PIONODE *IoNode )
/*++
Routine Description:
This routine references an existing IoNode, or creates a new IoNode if one can not be found. It returns with the IoNode's reference count adjusted, and the IoNodes lock held.
Arguments:
DeviceSerialNumber - Supplies the device serial number of the IoNode.
FileSerialNumber - Supplies the file serial number of the IoNode.
FindOnly - If set, just return pointer to ionode; do not update ref count.
IoNode - Returns the address of either the new or existing IoNode associated with the specified serial numbers.
Return Value:
TRUE - An existing IoNode was located.
FALSE - A new IoNode was created.
--*/
{ PIONODE ionode; PLIST_ENTRY head, next; NTSTATUS st;
head = &IoNodeHashTable[ SERIALNUMBERTOHASHINDEX(DeviceSerialNumber,FileSerialNumber)];
//
// Lock IoNodeHashTable
//
RtlEnterCriticalSection(&IoNodeHashTableLock);
next = head->Flink; while (next != head) { ionode = CONTAINING_RECORD(next,IONODE,IoNodeHashLinks); if ( (ionode->DeviceSerialNumber == DeviceSerialNumber) && (ionode->FileSerialNumber == FileSerialNumber) ) {
RtlEnterCriticalSection(&ionode->IoNodeLock);
if (!FindOnly) { // Increment the IoNode reference count
ionode->ReferenceCount++; }
RtlLeaveCriticalSection(&IoNodeHashTableLock); *IoNode = ionode; return TRUE; } next = next->Flink; }
if (FindOnly) { RtlLeaveCriticalSection(&IoNodeHashTableLock); return FALSE; }
//
// Allocate a new IoNode
//
ionode = RtlAllocateHeap(PsxHeap, 0,sizeof(IONODE)); if (! ionode) { RtlLeaveCriticalSection(&IoNodeHashTableLock); *IoNode = NULL; return FALSE; }
//
// Initialize the IoNode reference count
// Initialize the IoNodeLock and insert the IoNode into the IoNodeHashTable
// Initialize the device and file serial number fields
// Initialize the list of flocks
//
ionode->ReferenceCount = 1;
st = RtlInitializeCriticalSection(&ionode->IoNodeLock); ASSERT(NT_SUCCESS(st));
InsertTailList(head, &ionode->IoNodeHashLinks);
ionode->DeviceSerialNumber = DeviceSerialNumber; ionode->FileSerialNumber = FileSerialNumber;
InitializeListHead(&ionode->Flocks); InitializeListHead(&ionode->Waiters);
//
// Lock the IoNode and release the IoNodeHashTableLock
//
RtlEnterCriticalSection(&ionode->IoNodeLock); RtlLeaveCriticalSection(&IoNodeHashTableLock);
InitializeListHead(&ionode->Flocks);
ionode->Junked = FALSE;
*IoNode = ionode;
return FALSE; }
VOID DereferenceIoNode ( IN PIONODE IoNode )
/*++
Routine Description:
This routine dereferences and possibly deallocates the specified IoNode.
Arguments:
IoNode - Supplies the address of the IoNode to be dereferenced.
Return Value:
None.
--*/
{ RtlEnterCriticalSection(&IoNodeHashTableLock);
if (0 == --IoNode->ReferenceCount) { RemoveEntryList(&IoNode->IoNodeHashLinks);
// Call close routine.
RtlDeleteCriticalSection(&IoNode->IoNodeLock);
if (IoNode->IoVectors->IoNodeCloseRoutine) { (IoNode->IoVectors->IoNodeCloseRoutine)(IoNode); }
//
// All flocks should have been freed by now.
//
ASSERT(IsListEmpty(&IoNode->Flocks));
RtlFreeHeap(PsxHeap, 0,IoNode); } RtlLeaveCriticalSection(&IoNodeHashTableLock); }
PFILEDESCRIPTOR AllocateFd( IN PPSX_PROCESS p, IN ULONG Start, OUT PULONG Index )
/*++
Routine Description:
This function scans the specified process' open file table searching for the lowest free slot. Once a free slot is located, its address is returned. If no free slot is found, NULL is returned.
Arguments:
p - Supplies a pointer to the process whose open file table is to be scanned.
Start - The file table is scanned starting from descriptor 'Start': Zero for the beginning of the table, and so forth.
Index - If a file descriptor is located, this parameter returns the index of the allocated file descriptor.
Return Value:
NULL - No free file descriptor was located.
NON-NULL - The address of the lowest free file descriptor greater than or equal to 'Start' is returned.
--*/
{ ULONG i; PFILEDESCRIPTOR fd;
fd = &p->ProcessFileTable[Start];
for (i = Start; i < OPEN_MAX; i++, fd++) {
//
// XXX.mjb: CLIENT_OPEN: would also have to make sure not to
// allocate an FD here that was obtained via clientopen.
//
if (NULL == fd->SystemOpenFileDesc) { *Index = i; fd->Flags = 0; return fd; } } return NULL; }
BOOLEAN DeallocateFd( IN PPSX_PROCESS p, IN ULONG Index )
/*++
Routine Description:
This function deallocates the file descriptor from the specified process' open file table. If the file is not allocated, then an error is returned.
If the file descriptor was allocated, then the system open file that it refers to is dereferenced. This could cause the system open file, and possibly the associated IoNode, to be deallocated.
Arguments:
p - Supplies a pointer to the process whose open file table is being scanned.
Index - Supplies the index of the file descriptor to be deallocated.
Return Value:
TRUE - The file descriptor was successfully deallocated.
FALSE - The file descriptor did not refer to an allocated file descriptor.
--*/
{
PFILEDESCRIPTOR Fd; PSYSTEMOPENFILE SystemOpenFile;
Fd = &p->ProcessFileTable[Index];
SystemOpenFile = Fd->SystemOpenFileDesc; if (NULL == SystemOpenFile) { return FALSE; }
IoClose(p,Fd);
Fd->SystemOpenFileDesc = (PSYSTEMOPENFILE)NULL;
RtlEnterCriticalSection(&SystemOpenFileLock);
if (--SystemOpenFile->HandleCount == 0) { DeallocateSystemOpenFile(p, SystemOpenFile); }
RtlLeaveCriticalSection(&SystemOpenFileLock);
return TRUE; }
PFILEDESCRIPTOR FdIndexToFd( IN PPSX_PROCESS p, IN ULONG Index )
/*++
Routine Description:
This function translates a file descriptor index into a pointer to a file descriptor.
Arguments:
p - Supplies the process whose file descriptor table is to be used
Index - Supplies the file descriptor index to translate
Return Value:
NULL - the file descriptor index is not in range, or specifies a file descriptor that is not open.
NON-NULL - Returns the address of the file descriptor associated with the index.
--*/
{
PFILEDESCRIPTOR Fd;
if ( !ISFILEDESINRANGE(Index) ) {
return NULL; }
Fd = &p->ProcessFileTable[Index];
if ( !Fd->SystemOpenFileDesc ) {
return NULL; }
return Fd; }
PSYSTEMOPENFILE AllocateSystemOpenFile( VOID )
/*++
Routine Description:
This function allocates and references a system open file.
Arguments:
None.
Return Value:
NON-NULL - Returns the address of a system open file.
--*/
{
PSYSTEMOPENFILE SystemOpenFile;
//
// Grab system open file lock
//
RtlEnterCriticalSection(&SystemOpenFileLock);
SystemOpenFile = RtlAllocateHeap(PsxHeap, 0, sizeof(SYSTEMOPENFILE)); if (NULL == SystemOpenFile) { RtlLeaveCriticalSection(&SystemOpenFileLock); return NULL; }
SystemOpenFile->HandleCount = 1; SystemOpenFile->ReadHandleCount = 0; SystemOpenFile->WriteHandleCount = 0; SystemOpenFile->Flags = 0;
//
// Release system open file lock
//
RtlLeaveCriticalSection(&SystemOpenFileLock);
return SystemOpenFile;
}
VOID DeallocateSystemOpenFile( IN PPSX_PROCESS p, IN PSYSTEMOPENFILE SystemOpenFile )
/*++
Routine Description:
This function deallocates a system open file. If may cause the deallocation of the open file's associated IoNode.
This function is called with the system open file lock held.
Arguments:
SystemOpenFile - Supplies the address of the system open file to deallocate.
Return Value:
None.
--*/
{ PIONODE IoNode;
IoNode = SystemOpenFile->IoNode;
IoLastClose(p, SystemOpenFile);
RtlFreeHeap(PsxHeap, 0,SystemOpenFile);
DereferenceIoNode(IoNode);
}
VOID ForkProcessFileTable( IN PPSX_PROCESS ForkProcess, IN PPSX_PROCESS NewProcess )
/*++
Routine Description:
This function forks the open file table of the calling process. It does this by copying each file descriptor in the fork process' table to a descriptor in the new process' table. For each descriptor that is opened (references a system open file descriptor), the reference count is incremented.
Arguments:
ForkProcess - Supplies a pointer to the process that is the parent in the fork operation.
NewProcess - Supplies a pointer to the process that is the new process in the fork operation.
Return Value:
None.
--*/
{
LONG i; PFILEDESCRIPTOR ForkFd, NewFd;
ForkFd = ForkProcess->ProcessFileTable; NewFd = NewProcess->ProcessFileTable;
//
// Grab system open file lock
//
RtlEnterCriticalSection(&SystemOpenFileLock);
for (i = 0; i < OPEN_MAX; i++, NewFd++, ForkFd++) { //
// Copy the file descriptor, then up the reference
// to the associated system open file descriptor
//
*NewFd = *ForkFd;
if (NULL != ForkFd->SystemOpenFileDesc && (PSYSTEMOPENFILE)1 != ForkFd->SystemOpenFileDesc) { ForkFd->SystemOpenFileDesc->HandleCount++; IoNewHandle(NewProcess, NewFd); } }
//
// Release system open file lock
//
RtlLeaveCriticalSection(&SystemOpenFileLock); }
VOID ExecProcessFileTable( IN PPSX_PROCESS p )
/*++
Routine Description:
This function execs the open file table of the calling process. It does this by closing each file descriptor whose close on exec flag is set.
Arguments:
p - Supplies the process that is doing an exec.
Return Value:
None.
--*/
{ LONG i; PFILEDESCRIPTOR Fd;
Fd = p->ProcessFileTable;
RtlEnterCriticalSection(&SystemOpenFileLock);
for (i = 0; i < OPEN_MAX; i++, Fd++) { if (NULL != Fd->SystemOpenFileDesc && Fd->Flags & PSX_FD_CLOSE_ON_EXEC) {
IoClose(p,Fd); if (--(Fd->SystemOpenFileDesc->HandleCount) == 0) { DeallocateSystemOpenFile(p, Fd->SystemOpenFileDesc); } } }
RtlLeaveCriticalSection(&SystemOpenFileLock); }
VOID CloseProcessFileTable( IN PPSX_PROCESS p )
/*++
Routine Description:
This function is called during process termination to close all open filehandles held by the process.
Arguments:
p - Supplies the address of the process whose open file table is being closed.
Return Value:
None.
--*/
{ LONG i; PFILEDESCRIPTOR Fd;
Fd = p->ProcessFileTable;
// Grab system open file lock
RtlEnterCriticalSection(&SystemOpenFileLock);
for (i = 0; i < OPEN_MAX; i++, Fd++) { if (NULL != Fd->SystemOpenFileDesc) { (void)DeallocateFd(p, i); } }
// Release system open file lock
RtlLeaveCriticalSection(&SystemOpenFileLock); }
BOOLEAN IoOpenNewHandle ( IN PPSX_PROCESS p, IN PFILEDESCRIPTOR Fd, IN PPSX_API_MSG m )
/*++
Routine Description:
This function is called after a new handle has been created and initialized. Its function is to adjust the read/write handle counts and then call the type specific open new handle routine.
This function is only called from open.
Arguments:
p - Supplies the process creating a new handle
Fd - Supplies the address of the initialized file descriptor
m - Supplies the open message
Return Value:
TRUE - A reply to the open message should be generated.
FALSE - No reply should be generated.
--*/
{ RtlEnterCriticalSection(&SystemOpenFileLock);
if (Fd->SystemOpenFileDesc->Flags & PSX_FD_READ) { Fd->SystemOpenFileDesc->ReadHandleCount++; }
if (Fd->SystemOpenFileDesc->Flags & PSX_FD_WRITE) { Fd->SystemOpenFileDesc->WriteHandleCount++; }
RtlLeaveCriticalSection(&SystemOpenFileLock);
if (Fd->SystemOpenFileDesc->IoNode->IoVectors->OpenNewHandleRoutine) { return (Fd->SystemOpenFileDesc->IoNode->IoVectors->OpenNewHandleRoutine)(p,Fd,m); } return TRUE; }
VOID IoNewHandle ( IN PPSX_PROCESS p, IN PFILEDESCRIPTOR Fd )
/*++
Routine Description:
This function is called after a new handle has been created and initialized. Its function is to adjust the read/write handle counts and then call the type specific new handle routine.
This function is not called in response to an open. Only handles created through pipe, dup, or fork get called in this way. Open is different because it might need to block so it can implement an open protocol (named pipe opens...);
Arguments:
p - Supplies the process creating a new handle
Fd - Supplies the address of the initialized file descriptor
Return Value:
None.
--*/
{ RtlEnterCriticalSection(&SystemOpenFileLock);
if (Fd->SystemOpenFileDesc->Flags & PSX_FD_READ) { Fd->SystemOpenFileDesc->ReadHandleCount++; }
if (Fd->SystemOpenFileDesc->Flags & PSX_FD_WRITE) { Fd->SystemOpenFileDesc->WriteHandleCount++; }
RtlLeaveCriticalSection(&SystemOpenFileLock);
if (Fd->SystemOpenFileDesc->IoNode->IoVectors->NewHandleRoutine) { (Fd->SystemOpenFileDesc->IoNode->IoVectors->NewHandleRoutine)(p,Fd); } }
VOID IoClose( IN PPSX_PROCESS p, IN PFILEDESCRIPTOR Fd )
/*++
Routine Description:
This function is called whenever a handle is deleted. Its function is to adjust the read/write handle counts and then call the type specific close routine.
Arguments:
p - Supplies the process closing a handle
Fd - Supplies the address of the initialized file descriptor
Return Value:
None.
--*/
{ RtlEnterCriticalSection(&SystemOpenFileLock);
if (Fd->SystemOpenFileDesc->Flags & PSX_FD_READ) { Fd->SystemOpenFileDesc->ReadHandleCount--; }
if (Fd->SystemOpenFileDesc->Flags & PSX_FD_WRITE) { Fd->SystemOpenFileDesc->WriteHandleCount--; }
RtlLeaveCriticalSection(&SystemOpenFileLock); ReleaseFlocksByPid(Fd->SystemOpenFileDesc->IoNode, p->Pid);
if (Fd->SystemOpenFileDesc->IoNode->IoVectors->CloseRoutine) { (Fd->SystemOpenFileDesc->IoNode->IoVectors->CloseRoutine)(p,Fd); } }
VOID IoLastClose ( IN PPSX_PROCESS p, IN PSYSTEMOPENFILE SystemOpenFile )
/*++
Routine Description:
This function is called whenever the last handle is deleted. Its function is to call the type specific close routine.
Arguments:
p - Supplies the process closing a handle
Fd - Supplies the address of the initialized file descriptor
Return Value:
None.
--*/
{ if (SystemOpenFile->IoNode->IoVectors->LastCloseRoutine) { (SystemOpenFile->IoNode->IoVectors->LastCloseRoutine) (p, SystemOpenFile); } }
|