IO_STATUS_BLOCK NTAPI FatiOpenExistingDcb(IN PFAT_IRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN PVCB Vcb, IN PFCB Dcb, IN PACCESS_MASK DesiredAccess, IN USHORT ShareAccess, IN ULONG CreateDisposition, IN BOOLEAN NoEaKnowledge, IN BOOLEAN DeleteOnClose) { IO_STATUS_BLOCK Iosb = {{0}}; PCCB Ccb; /* Exclusively lock this FCB */ FatAcquireExclusiveFcb(IrpContext, Dcb); /* Check if it's a delete-on-close of a root DCB */ if (FatNodeType(Dcb) == FAT_NTC_ROOT_DCB && DeleteOnClose) { Iosb.Status = STATUS_CANNOT_DELETE; /* Release the lock and return */ FatReleaseFcb(IrpContext, Dcb); return Iosb; } /*if (NoEaKnowledge && NodeType(Dcb) != FAT_NTC_ROOT_DCB && !FatIsFat32(Vcb)) { UNIMPLEMENTED; }*/ /* Check the create disposition and desired access */ if ((CreateDisposition != FILE_OPEN) && (CreateDisposition != FILE_OPEN_IF)) { Iosb.Status = STATUS_OBJECT_NAME_COLLISION; /* Release the lock and return */ FatReleaseFcb(IrpContext, Dcb); return Iosb; } #if 0 if (!FatCheckFileAccess(IrpContext, Dcb->DirentFatFlags, DesiredAccess)) { Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); } #endif /* If it's already opened - check share access */ if (Dcb->OpenCount > 0) { Iosb.Status = IoCheckShareAccess(*DesiredAccess, ShareAccess, FileObject, &Dcb->ShareAccess, TRUE); if (!NT_SUCCESS(Iosb.Status)) { /* Release the lock and return */ FatReleaseFcb(IrpContext, Dcb); return Iosb; } } else { IoSetShareAccess(*DesiredAccess, ShareAccess, FileObject, &Dcb->ShareAccess); } /* Set the file object */ Ccb = FatCreateCcb(); FatSetFileObject(FileObject, UserDirectoryOpen, Dcb, Ccb); /* Increase counters */ Dcb->UncleanCount++; Dcb->OpenCount++; Vcb->OpenFileCount++; if (IsFileObjectReadOnly(FileObject)) Vcb->ReadOnlyCount++; /* Set delete on close */ if (DeleteOnClose) SetFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE); /* Clear delay close flag */ ClearFlag(Dcb->State, FCB_STATE_DELAY_CLOSE); /* That's it */ Iosb.Status = STATUS_SUCCESS; Iosb.Information = FILE_OPENED; /* Release the lock */ FatReleaseFcb(IrpContext, Dcb); return Iosb; }
VOID FatOpenDirectoryFile ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb ) /*++ Routine Description: This routine opens a new directory file if one is not already open. Arguments: Dcb - Pointer to the DCB for the directory Return Value: None. --*/ { PAGED_CODE(); DebugTrace(+1, Dbg, "FatOpenDirectoryFile\n", 0); DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb); // // If we don't have some hold on this Dcb (there are several ways), there is nothing // to prevent child files from closing and tearing this branch of the tree down in the // midst of our slapping this reference onto it. // // I really wish we had a proper Fcb synchronization model (like CDFS/UDFS/NTFS). // ASSERT( FatIsCurrentOperationSynchedForDcbTeardown( IrpContext, Dcb )); // // If we haven't yet set the correct AllocationSize, do so. // if (Dcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) { FatLookupFileAllocationSize( IrpContext, Dcb ); Dcb->Header.FileSize.LowPart = Dcb->Header.AllocationSize.LowPart; } // // Setup the Bitmap buffer if it is not big enough already // FatCheckFreeDirentBitmap( IrpContext, Dcb ); // // Check if we need to create a directory file. // // We first do a spot check and then synchronize and check again. // if (Dcb->Specific.Dcb.DirectoryFile == NULL) { PFILE_OBJECT DirectoryFileObject = NULL; FatAcquireDirectoryFileMutex( Dcb->Vcb ); try { if (Dcb->Specific.Dcb.DirectoryFile == NULL) { PDEVICE_OBJECT RealDevice; // // Create the special file object for the directory file, and set // up its pointers back to the Dcb and the section object pointer. // Note that setting the DirectoryFile pointer in the Dcb has // to be the last thing done. // // Preallocate a close context since we have no Ccb for this object. // RealDevice = Dcb->Vcb->CurrentDevice; DirectoryFileObject = IoCreateStreamFileObject( NULL, RealDevice ); FatPreallocateCloseContext(); FatSetFileObject( DirectoryFileObject, DirectoryFile, Dcb, NULL ); // // Remember this internal open. // InterlockedIncrement( &(Dcb->Vcb->InternalOpenCount) ); // // If this is the root directory, it is also a residual open. // if (NodeType( Dcb ) == FAT_NTC_ROOT_DCB) { InterlockedIncrement( &(Dcb->Vcb->ResidualOpenCount) ); } DirectoryFileObject->SectionObjectPointer = &Dcb->NonPaged->SectionObjectPointers; DirectoryFileObject->ReadAccess = TRUE; DirectoryFileObject->WriteAccess = TRUE; DirectoryFileObject->DeleteAccess = TRUE; InterlockedIncrement( &Dcb->Specific.Dcb.DirectoryFileOpenCount ); Dcb->Specific.Dcb.DirectoryFile = DirectoryFileObject; // // Indicate we're happy with the fileobject now. // DirectoryFileObject = NULL; } } finally { FatReleaseDirectoryFileMutex( Dcb->Vcb ); // // Rip the object up if we couldn't get the close context. // if (DirectoryFileObject) { ObDereferenceObject( DirectoryFileObject ); } } }
IO_STATUS_BLOCK NTAPI FatiOpenExistingFcb(IN PFAT_IRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN PVCB Vcb, IN PFCB Fcb, 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 NoEaKnowledge, IN BOOLEAN DeleteOnClose, IN BOOLEAN OpenedAsDos, OUT PBOOLEAN OplockPostIrp) { IO_STATUS_BLOCK Iosb = {{0}}; ACCESS_MASK AddedAccess = 0; BOOLEAN Hidden; BOOLEAN System; PCCB Ccb = NULL; NTSTATUS Status, StatusPrev; /* Acquire exclusive FCB lock */ (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb); *OplockPostIrp = FALSE; /* Check if there is a batch oplock */ if (FsRtlCurrentBatchOplock(&Fcb->Fcb.Oplock)) { /* Return with a special information field */ Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY; /* Check the oplock */ Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock, IrpContext->Irp, IrpContext, FatOplockComplete, FatPrePostIrp); if (Iosb.Status != STATUS_SUCCESS && Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) { /* The Irp needs to be queued */ *OplockPostIrp = TRUE; /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } } /* Validate parameters and modify access */ if (CreateDisposition == FILE_CREATE) { Iosb.Status = STATUS_OBJECT_NAME_COLLISION; /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } else if (CreateDisposition == FILE_SUPERSEDE) { SetFlag(AddedAccess, DELETE & ~(*DesiredAccess)); *DesiredAccess |= DELETE; } else if ((CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) { SetFlag(AddedAccess, (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) & ~(*DesiredAccess) ); *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES; } // TODO: Check desired access // TODO: Check if this file is readonly and DeleteOnClose is set /* Validate disposition information */ if ((CreateDisposition == FILE_SUPERSEDE) || (CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) { // TODO: Get this attributes from the dirent Hidden = FALSE; System = FALSE; if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) || (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))) { DPRINT1("Hidden/system attributes don't match\n"); Iosb.Status = STATUS_ACCESS_DENIED; /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } // TODO: Check for write protected volume } /* Check share access */ Iosb.Status = IoCheckShareAccess(*DesiredAccess, ShareAccess, FileObject, &Fcb->ShareAccess, FALSE); if (!NT_SUCCESS(Iosb.Status)) { /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } /* Check the oplock status after checking for share access */ Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock, IrpContext->Irp, IrpContext, FatOplockComplete, FatPrePostIrp ); if (Iosb.Status != STATUS_SUCCESS && Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) { /* The Irp needs to be queued */ *OplockPostIrp = TRUE; /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } /* Set Fast I/O flag */ Fcb->Header.IsFastIoPossible = FALSE; //FatiIsFastIoPossible(Fcb); /* Make sure image is not mapped */ if (DeleteOnClose || FlagOn(*DesiredAccess, FILE_WRITE_DATA)) { /* Try to flush the image section */ if (!MmFlushImageSection(&Fcb->SectionObjectPointers, MmFlushForWrite)) { /* Yes, image section exists, set correct status code */ if (DeleteOnClose) Iosb.Status = STATUS_CANNOT_DELETE; else Iosb.Status = STATUS_SHARING_VIOLATION; /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } } /* Flush the cache if it's non-cached non-pagefile access */ if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING) && Fcb->SectionObjectPointers.DataSectionObject && !FlagOn(Fcb->State, FCB_STATE_PAGEFILE)) { /* Set the flag that create is in progress */ SetFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS); /* Flush the cache */ CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL); /* Acquire and release Paging I/O resource before purging the cache section to let lazy writer finish */ ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE); ExReleaseResourceLite( Fcb->Header.PagingIoResource ); /* Delete the cache section */ CcPurgeCacheSection(&Fcb->SectionObjectPointers, NULL, 0, FALSE); /* Clear the flag */ ClearFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS); } /* Check create disposition flags and branch accordingly */ if (CreateDisposition == FILE_OPEN || CreateDisposition == FILE_OPEN_IF) { DPRINT("Opening a file\n"); /* Check if we need to bother with EA */ if (NoEaKnowledge && FALSE /* FatIsFat32(Vcb)*/) { UNIMPLEMENTED; } /* Set up file object */ Ccb = FatCreateCcb(); FatSetFileObject(FileObject, UserFileOpen, Fcb, Ccb); FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; /* The file is opened */ Iosb.Information = FILE_OPENED; goto SuccComplete; } else if ((CreateDisposition == FILE_SUPERSEDE) || (CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) { /* Remember previous status */ StatusPrev = Iosb.Status; // TODO: Check system security access /* Perform overwrite operation */ Iosb = FatiOverwriteFile(IrpContext, FileObject, Fcb, AllocationSize, EaBuffer, EaLength, FileAttributes, CreateDisposition, NoEaKnowledge); /* Restore previous status in case of success */ if (Iosb.Status == STATUS_SUCCESS) Iosb.Status = StatusPrev; /* Fall down to completion */ } else { /* We can't get here */ KeBugCheckEx(FAT_FILE_SYSTEM, CreateDisposition, 0, 0, 0); } SuccComplete: /* If all is fine */ if (Iosb.Status != STATUS_PENDING && NT_SUCCESS(Iosb.Status)) { /* Update access if needed */ if (AddedAccess) { /* Remove added access flags from desired access */ ClearFlag(*DesiredAccess, AddedAccess); /* Check share access */ Status = IoCheckShareAccess(*DesiredAccess, ShareAccess, FileObject, &Fcb->ShareAccess, TRUE); /* Make sure it's success */ ASSERT(Status == STATUS_SUCCESS); } else { /* Update the share access */ IoUpdateShareAccess(FileObject, &Fcb->ShareAccess); } /* Clear the delay close */ ClearFlag(Fcb->State, FCB_STATE_DELAY_CLOSE); /* Increase counters */ Fcb->UncleanCount++; Fcb->OpenCount++; Vcb->OpenFileCount++; if (IsFileObjectReadOnly(FileObject)) Vcb->ReadOnlyCount++; if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) Fcb->NonCachedUncleanCount++; // TODO: Handle DeleteOnClose and OpenedAsDos by storing those flags in CCB } return Iosb; }