#define NDEBUG
#include "fastfat.h"
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUpcaseUnicodeStringToCountedOemString(
+ IN OUT POEM_STRING DestinationString,
+ IN PCUNICODE_STRING SourceString,
+ IN BOOLEAN AllocateDestinationString
+);
+
+
/* FUNCTIONS *****************************************************************/
+IO_STATUS_BLOCK
+NTAPI
+FatiOpenRootDcb(IN PFAT_IRP_CONTEXT IrpContext,
+ IN PFILE_OBJECT FileObject,
+ IN PVCB Vcb,
+ IN PACCESS_MASK DesiredAccess,
+ IN USHORT ShareAccess,
+ IN ULONG CreateDisposition)
+{
+ IO_STATUS_BLOCK Iosb;
+
+ DPRINT1("Opening root directory\n");
+
+ Iosb.Status = STATUS_NOT_IMPLEMENTED;
+
+ return Iosb;
+}
+
+IO_STATUS_BLOCK
+NTAPI
+FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext,
+ IN PFILE_OBJECT FileObject,
+ IN PVCB Vcb,
+ IN PFCB ParentDcb,
+ IN PACCESS_MASK DesiredAccess,
+ IN USHORT ShareAccess,
+ IN ULONG AllocationSize,
+ IN PFILE_FULL_EA_INFORMATION EaBuffer,
+ IN ULONG EaLength,
+ IN UCHAR FileAttributes,
+ IN ULONG CreateDisposition,
+ IN BOOLEAN IsPagingFile,
+ IN BOOLEAN DeleteOnClose,
+ IN BOOLEAN IsDosName)
+{
+ IO_STATUS_BLOCK Iosb = {{0}};
+ OEM_STRING AnsiName;
+ CHAR AnsiNameBuf[512];
+ PFCB Fcb;
+ NTSTATUS Status;
+ FF_FILE *FileHandle;
+
+ /* Check for create file option and fail */
+ if (CreateDisposition == FILE_CREATE)
+ {
+ Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
+ return Iosb;
+ }
+
+ // TODO: Check more params
+
+ /* Convert the name to ANSI */
+ AnsiName.Buffer = AnsiNameBuf;
+ AnsiName.Length = 0;
+ AnsiName.MaximumLength = sizeof(AnsiNameBuf);
+ RtlZeroMemory(AnsiNameBuf, sizeof(AnsiNameBuf));
+ Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiName, &FileObject->FileName, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ ASSERT(FALSE);
+ }
+
+ /* Open the file with FullFAT */
+ FileHandle = FF_Open(Vcb->Ioman, AnsiName.Buffer, FF_MODE_READ, NULL);
+
+ if (!FileHandle)
+ {
+ Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND; // FIXME: A shortcut for now
+ return Iosb;
+ }
+
+ /* Create a new FCB for this file */
+ Fcb = FatCreateFcb(IrpContext, Vcb, ParentDcb, FileHandle);
+
+ // TODO: Check if overwrite is needed
+
+ // This is usual file open branch, without overwriting!
+ /* Set context and section object pointers */
+ FatSetFileObject(FileObject,
+ UserFileOpen,
+ Fcb,
+ FatCreateCcb());
+ FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
+
+ Iosb.Status = STATUS_SUCCESS;
+ Iosb.Information = FILE_OPENED;
+
+ return Iosb;
+}
+
NTSTATUS
NTAPI
FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
/* Control blocks */
PVCB Vcb, DecodedVcb;
- PFCB Fcb;
+ PFCB Fcb, NextFcb;
PCCB Ccb;
+ PFCB ParentDcb;
/* IRP data */
PFILE_OBJECT FileObject;
/* Misc */
NTSTATUS Status;
- //IO_STATUS_BLOCK Iosb;
+ IO_STATUS_BLOCK Iosb;
PIO_STACK_LOCATION IrpSp;
+ BOOLEAN EndBackslash = FALSE, OpenedAsDos;
+ UNICODE_STRING RemainingPart, FirstName, NextName;
+ OEM_STRING AnsiFirstName;
+
+ Iosb.Status = STATUS_SUCCESS;
/* Get current IRP stack location */
IrpSp = IoGetCurrentIrpStackLocation(Irp);
// TODO: Make sure EAs aren't supported on FAT32
+ /* Check if it's a volume open request */
if (FileName.Length == 0)
{
- /* It is a volume open request, check related FO to be sure */
-
+ /* Test related FO to be sure */
if (!RelatedFO ||
FatDecodeFileObject(RelatedFO, &DecodedVcb, &Fcb, &Ccb) == UserVolumeOpen)
{
}
}
- //return Iosb.Status;
- return STATUS_SUCCESS;
+ /* Check if this is a relative open */
+ if (RelatedFO)
+ {
+ // RelatedFO will be a parent directory
+ UNIMPLEMENTED;
+ }
+ else
+ {
+ /* Absolute open */
+ if ((FileName.Length == sizeof(WCHAR)) &&
+ (FileName.Buffer[0] == L'\\'))
+ {
+ /* Check if it's ok to open it */
+ if (NonDirectoryFile)
+ {
+ DPRINT1("Trying to open root dir as a file\n");
+
+ /* Cleanup and return */
+ FatReleaseVcb(IrpContext, Vcb);
+ return STATUS_FILE_IS_A_DIRECTORY;
+ }
+
+ /* Check delete on close on a root dir */
+ if (DeleteOnClose)
+ {
+ /* Cleanup and return */
+ FatReleaseVcb(IrpContext, Vcb);
+ return STATUS_CANNOT_DELETE;
+ }
+
+ /* Call root directory open routine */
+ Iosb = FatiOpenRootDcb(IrpContext,
+ FileObject,
+ Vcb,
+ DesiredAccess,
+ ShareAccess,
+ CreateDisposition);
+
+ Irp->IoStatus.Information = Iosb.Information;
+
+ /* Cleanup and return */
+ FatReleaseVcb(IrpContext, Vcb);
+ return Iosb.Status;
+ }
+ else
+ {
+ /* Not a root dir */
+ ParentDcb = Vcb->RootDcb;
+ DPRINT1("ParentDcb %p\n", ParentDcb);
+ }
+
+ /* Check for backslash at the end */
+ if (FileName.Length &&
+ FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1] == L'\\')
+ {
+ /* Cut it out */
+ FileName.Length -= sizeof(WCHAR);
+
+ /* Remember we cut it */
+ EndBackslash = TRUE;
+ }
+
+ /* Ensure the name is set */
+ if (!ParentDcb->FullFileName.Buffer)
+ {
+ DPRINT1("ParentDcb->FullFileName.Buffer is NULL\n");
+ }
+
+ /* Check max path length */
+ if (ParentDcb->FullFileName.Length + FileName.Length + sizeof(WCHAR) <= FileName.Length)
+ {
+ DPRINT1("Max length is way off\n");
+ Iosb.Status = STATUS_OBJECT_NAME_INVALID;
+ ASSERT(FALSE);
+ }
+
+ /* Loop through FCBs to find a good one */
+ while (TRUE)
+ {
+ Fcb = ParentDcb;
+
+ /* Dissect the name */
+ RemainingPart = FileName;
+ while (RemainingPart.Length)
+ {
+ FsRtlDissectName(RemainingPart, &FirstName, &NextName);
+
+ /* Check for validity */
+ if ((NextName.Length && NextName.Buffer[0] == L'\\') ||
+ (NextName.Length > 255 * sizeof(WCHAR)))
+ {
+ /* The name is invalid */
+ DPRINT1("Invalid name found\n");
+ Iosb.Status = STATUS_OBJECT_NAME_INVALID;
+ ASSERT(FALSE);
+ }
+
+ /* Convert the name to ANSI */
+ AnsiFirstName.Buffer = ExAllocatePool(PagedPool, FirstName.Length);
+ AnsiFirstName.Length = 0;
+ AnsiFirstName.MaximumLength = FirstName.Length;
+ Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName, &FirstName, FALSE);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlUpcaseUnicodeStringToCountedOemString() failed with 0x%08x\n", Status);
+ ASSERT(FALSE);
+ NextFcb = NULL;
+ AnsiFirstName.Length = 0;
+ }
+ else
+ {
+ /* Find the coresponding FCB */
+ NextFcb = FatFindFcb(IrpContext,
+ &Fcb->Dcb.SplayLinksAnsi,
+ (PSTRING)&AnsiFirstName,
+ &OpenedAsDos);
+ }
+
+ /* Check if we found anything */
+ if (!NextFcb && Fcb->Dcb.SplayLinksUnicode)
+ {
+ ASSERT(FALSE);
+ }
+
+ /* Move to the next FCB */
+ if (NextFcb)
+ {
+ Fcb = NextFcb;
+ RemainingPart = NextName;
+ }
+
+ /* Break out of this loop if nothing can be found */
+ if (!NextFcb ||
+ NextName.Length == 0 ||
+ FatNodeType(NextFcb) == FAT_NTC_FCB)
+ {
+ break;
+ }
+ }
+
+ /* Ensure remaining name doesn't start from a backslash */
+ if (RemainingPart.Length &&
+ RemainingPart.Buffer[0] == L'\\')
+ {
+ /* Cut it */
+ RemainingPart.Buffer++;
+ RemainingPart.Length -= sizeof(WCHAR);
+ }
+
+ if (Fcb->Condition == FcbGood)
+ {
+ /* Good FCB, break out of the loop */
+ break;
+ }
+ else
+ {
+ ASSERT(FALSE);
+ }
+ }
+
+ /* We have a valid FCB now */
+ if (!RemainingPart.Length)
+ {
+ DPRINT1("It's possible to open an existing FCB\n");
+ ASSERT(FALSE);
+ }
+
+ /* During parsing we encountered a part which has no attached FCB/DCB.
+ Check that the parent is really DCB and not FCB */
+ if (FatNodeType(Fcb) != FAT_NTC_ROOT_DCB &&
+ FatNodeType(Fcb) != FAT_NTC_DCB)
+ {
+ DPRINT1("Weird FCB node type %x, expected DCB or root DCB\n", FatNodeType(Fcb));
+ ASSERT(FALSE);
+ }
+
+ /* Create additional DCBs for all path items */
+ ParentDcb = Fcb;
+ while (TRUE)
+ {
+ FsRtlDissectName(RemainingPart, &FirstName, &RemainingPart);
+
+ /* Check for validity */
+ if ((RemainingPart.Length && RemainingPart.Buffer[0] == L'\\') ||
+ (NextName.Length > 255 * sizeof(WCHAR)))
+ {
+ /* The name is invalid */
+ DPRINT1("Invalid name found\n");
+ Iosb.Status = STATUS_OBJECT_NAME_INVALID;
+ ASSERT(FALSE);
+ }
+
+ /* Convert the name to ANSI */
+ AnsiFirstName.Buffer = ExAllocatePool(PagedPool, FirstName.Length);
+ AnsiFirstName.Length = 0;
+ AnsiFirstName.MaximumLength = FirstName.Length;
+ Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName, &FirstName, FALSE);
+
+ if (!NT_SUCCESS(Status))
+ {
+ ASSERT(FALSE);
+ }
+
+ DPRINT1("FirstName %wZ, RemainingPart %wZ\n", &FirstName, &RemainingPart);
+
+ /* Break if came to the end */
+ if (!RemainingPart.Length) break;
+
+ /* Create a DCB for this entry */
+ ParentDcb = FatCreateDcb(IrpContext,
+ Vcb,
+ ParentDcb);
+
+ /* Set its name */
+ FatSetFullNameInFcb(ParentDcb, &FirstName);
+ }
+
+ // TODO: Try to open directory
+
+ /* If end backslash here, then it's definately not permitted,
+ since we're opening files here */
+ if (EndBackslash)
+ {
+ /* Unlock VCB */
+ FatReleaseVcb(IrpContext, Vcb);
+
+ /* Complete the request */
+ Iosb.Status = STATUS_OBJECT_NAME_INVALID;
+ FatCompleteRequest(IrpContext, Irp, Iosb.Status);
+ return Iosb.Status;
+ }
+
+ /* Try to open the file */
+ Iosb = FatiOpenExistingFile(IrpContext,
+ FileObject,
+ Vcb,
+ ParentDcb,
+ DesiredAccess,
+ ShareAccess,
+ AllocationSize,
+ EaBuffer,
+ EaLength,
+ FileAttributes,
+ CreateDisposition,
+ FALSE,
+ DeleteOnClose,
+ OpenedAsDos);
+
+ Irp->IoStatus.Information = Iosb.Information;
+ }
+
+ /* Unlock VCB */
+ FatReleaseVcb(IrpContext, Vcb);
+
+ /* Complete the request */
+ FatCompleteRequest(IrpContext, Irp, Iosb.Status);
+
+ return Iosb.Status;
}
NTSTATUS
{
PFAT_IRP_CONTEXT IrpContext;
NTSTATUS Status;
- //PVOLUME_DEVICE_OBJECT VolumeDO = (PVOLUME_DEVICE_OBJECT)DeviceObject;
DPRINT1("FatCreate()\n");