xbox-kernel/private/ntos/gdfx/fcbsup.c
2020-09-30 17:17:25 +02:00

266 lines
6.0 KiB
C

/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
fcbsup.c
Abstract:
This module implements routines which provide support for file control
blocks.
--*/
#include "gdfx.h"
NTSTATUS
GdfxCreateFcb(
IN PGDF_FCB ParentFcb OPTIONAL,
IN POBJECT_STRING FileName,
IN PGDF_DIRECTORY_ENTRY DirectoryEntry,
OUT PGDF_FCB *ReturnedFcb
)
/*++
Routine Description:
This routine reads the file entry descriptor at the supplied extent and
constructs a file control block that represents the file.
Arguments:
ParentFcb - Specifies the parent directory that contains the supplied file.
FileName - Specifies the name of the file.
DirectoryEntry - Specifies the directory entry to obtain more attributes
about the file. The directory entry does not include the full file
name.
ReturnedFcb - Specifies the buffer to receive the created file control
block.
Return Value:
Status of operation.
--*/
{
NTSTATUS status;
SIZE_T FcbSize;
ULONG FcbPoolTag;
PGDF_FCB Fcb;
//
// Compute the size of the file control block.
//
if (GdfxIsFlagSet(DirectoryEntry->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
FcbPoolTag = 'cDxG';
} else {
FcbPoolTag = 'cFxG';
}
FcbSize = sizeof(GDF_FCB) + FileName->Length;
//
// Allocate the file control block.
//
Fcb = ExAllocatePoolWithTag(FcbSize, FcbPoolTag);
if (Fcb != NULL) {
//
// Initialize the file control block.
//
RtlZeroMemory(Fcb, FcbSize);
//
// A file control block starts with the single reference for the caller.
//
Fcb->ReferenceCount = 1;
//
// Copy the file name to the file control block.
//
RtlCopyMemory(Fcb->FileName, FileName->Buffer, FileName->Length);
Fcb->FileNameLength = (UCHAR)FileName->Length;
//
// Copy the file's starting sector and size to the file control block.
//
Fcb->FirstSector = DirectoryEntry->FirstSector;
Fcb->FileSize = DirectoryEntry->FileSize;
//
// Increment the reference count for the parent file control block and
// attach it to this file control block.
//
ParentFcb->ReferenceCount++;
Fcb->ParentFcb = ParentFcb;
InsertHeadList(&ParentFcb->ChildFcbList, &Fcb->SiblingFcbLink);
//
// For directories, mark the file control block as a directory and
// initialize the child file control block list.
//
if (GdfxIsFlagSet(DirectoryEntry->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
Fcb->Flags |= GDF_FCB_DIRECTORY;
InitializeListHead(&Fcb->ChildFcbList);
}
status = STATUS_SUCCESS;
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
*ReturnedFcb = Fcb;
return status;
}
BOOLEAN
GdfxFindOpenChildFcb(
IN PGDF_FCB DirectoryFcb,
IN POBJECT_STRING FileName,
OUT PGDF_FCB *ReturnedFcb
)
/*++
Routine Description:
This routine searches the child file control block for the supplied
directory for a file that has the supplied file name.
Arguments:
DirectoryFcb - Specifies the file control block of the directory to search.
FileName - Specifies the name to search for in the directory.
ReturnedFcb - Specifies the buffer to receive the found file control block.
Return Value:
Returns TRUE if the file control block was found, else FALSE.
--*/
{
PLIST_ENTRY NextFcbLink;
PGDF_FCB Fcb;
OBJECT_STRING FcbFileName;
//
// Walk through the file control blocks actively in use by the volume and
// find a match.
//
NextFcbLink = DirectoryFcb->ChildFcbList.Flink;
while (NextFcbLink != &DirectoryFcb->ChildFcbList) {
Fcb = CONTAINING_RECORD(NextFcbLink, GDF_FCB, SiblingFcbLink);
FcbFileName.Length = Fcb->FileNameLength;
FcbFileName.Buffer = Fcb->FileName;
if ((FcbFileName.Length == FileName->Length) &&
RtlEqualObjectString(&FcbFileName, FileName, TRUE)) {
*ReturnedFcb = Fcb;
return TRUE;
}
NextFcbLink = Fcb->SiblingFcbLink.Flink;
}
*ReturnedFcb = NULL;
return FALSE;
}
VOID
GdfxDereferenceFcb(
IN PGDF_FCB Fcb
)
/*++
Routine Description:
This routine decrements the reference count on the supplied file control
block. If the reference count reaches zero, then the file control block is
deleted.
Arguments:
Fcb - Specifies the file control block to dereference.
Return Value:
None.
--*/
{
PGDF_FCB ParentFcb;
ASSERT(Fcb->ReferenceCount > 0);
do {
//
// Decrement the reference count and bail out if there are still
// outstanding references to the file control block.
//
if (--Fcb->ReferenceCount != 0) {
return;
}
//
// Verify that the child file control block list is empty if this is a
// directory.
//
if (GdfxIsFlagSet(Fcb->Flags, GDF_FCB_DIRECTORY)) {
ASSERT(IsListEmpty(&Fcb->ChildFcbList));
}
//
// Save off the parent file control block so that we can dereference it
// in a bit.
//
ParentFcb = Fcb->ParentFcb;
//
// Remove this file control block from the list of siblings.
//
if (ParentFcb != NULL) {
RemoveEntryList(&Fcb->SiblingFcbLink);
}
//
// Free the file control block.
//
ExFreePool(Fcb);
//
// Switch to the parent file control block and restart the loop to
// dereference this object.
//
Fcb = ParentFcb;
} while (Fcb != NULL);
}