/** * @public * @brief Equivalent to fclose() * * @param pFile FF_FILE object that was created by FF_Open(). * * @return 0 on sucess. * @return -1 if a null pointer was provided. * **/ FF_ERROR FF_Close(FF_FILE *pFile) { FF_FILE *pFileChain; FF_DIRENT OriginalEntry; FF_ERROR Error; if(!pFile) { return FF_ERR_NULL_POINTER; } // UpDate Dirent if File-size has changed? // Update the Dirent! Error = FF_GetEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); if(Error) { return Error; } if(!pFile->FileDeleted) { if(pFile->Filesize != OriginalEntry.Filesize) { OriginalEntry.Filesize = pFile->Filesize; Error = FF_PutEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); if(Error) { return Error; } } } Error = FF_FlushCache(pFile->pIoman); // Ensure all modfied blocks are flushed to disk! // Handle Linked list! FF_PendSemaphore(pFile->pIoman->pSemaphore); { // Semaphore is required, or linked list could become corrupted. if(pFile->pIoman->FirstFile == pFile) { pFile->pIoman->FirstFile = pFile->Next; } else { pFileChain = (FF_FILE *) pFile->pIoman->FirstFile; while(pFileChain->Next != pFile) { pFileChain = pFileChain->Next; } pFileChain->Next = pFile->Next; } } // Semaphore released, linked list was shortened! FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); // If file written, flush to disk FF_FREE(pFile); if(Error) { return Error; } // Simply free the pointer! return FF_ERR_NONE; }
static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) { FF_IOMAN *pIoman = pFile->pIoman; FF_T_UINT32 nBytesPerCluster = pIoman->pPartition->BlkSize * pIoman->pPartition->SectorsPerCluster; FF_T_UINT32 nTotalClustersNeeded = Size / nBytesPerCluster; FF_T_UINT32 nClusterToExtend; FF_T_UINT32 CurrentCluster, NextCluster; FF_T_UINT32 i; FF_DIRENT OriginalEntry; if((pFile->Mode & FF_MODE_WRITE) != FF_MODE_WRITE) { return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE; } if(pFile->Filesize == 0 && pFile->ObjectCluster == 0) { // No Allocated clusters. // Create a Cluster chain! pFile->AddrCurrentCluster = FF_CreateClusterChain(pFile->pIoman); if(!FF_GetEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry)) { OriginalEntry.ObjectCluster = pFile->AddrCurrentCluster; FF_PutEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); } else { return FF_ERR_FILE_EXTEND_FAILED; } pFile->ObjectCluster = pFile->AddrCurrentCluster; pFile->iChainLength = 1; pFile->CurrentCluster = 0; pFile->iEndOfChain = pFile->AddrCurrentCluster; } if(Size % nBytesPerCluster) { nTotalClustersNeeded += 1; } if(pFile->iChainLength == 0) { // First extension requiring the chain length, pFile->iChainLength = FF_GetChainLength(pIoman, pFile->ObjectCluster, &pFile->iEndOfChain); } nClusterToExtend = (nTotalClustersNeeded - pFile->iChainLength); if(nTotalClustersNeeded > pFile->iChainLength) { NextCluster = pFile->AddrCurrentCluster; FF_lockFAT(pIoman); { for(i = 0; i <= nClusterToExtend; i++) { CurrentCluster = FF_FindEndOfChain(pIoman, NextCluster); NextCluster = FF_FindFreeCluster(pIoman); if(!NextCluster) { FF_unlockFAT(pIoman); return FF_ERR_FAT_NO_FREE_CLUSTERS; } FF_putFatEntry(pIoman, CurrentCluster, NextCluster); FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); } pFile->iEndOfChain = FF_FindEndOfChain(pIoman, NextCluster); } FF_unlockFAT(pIoman); pFile->iChainLength += i; FF_DecreaseFreeClusters(pIoman, i); // Keep Tab of Numbers for fast FreeSize() } return FF_ERR_NONE; }
VOID NTAPI FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext, IN PFCB Fcb) { FF_DIRENT DirEnt; FF_ERROR Err; POEM_STRING ShortName; CHAR ShortNameRaw[13]; UCHAR EntryBuffer[32]; UCHAR NumLFNs; PUNICODE_STRING UnicodeName; OEM_STRING LongNameOem; NTSTATUS Status; /* Get the dir entry */ Err = FF_GetEntry(Fcb->Vcb->Ioman, Fcb->FatHandle->DirEntry, Fcb->FatHandle->DirCluster, &DirEnt); if (Err != FF_ERR_NONE) { DPRINT1("Error %d getting dirent of a file\n", Err); return; } /* Read the dirent to fetch the raw short name */ FF_FetchEntry(Fcb->Vcb->Ioman, Fcb->FatHandle->DirCluster, Fcb->FatHandle->DirEntry, EntryBuffer); NumLFNs = (UCHAR)(EntryBuffer[0] & ~0x40); RtlCopyMemory(ShortNameRaw, EntryBuffer, 11); /* Initialize short name string */ ShortName = &Fcb->ShortName.Name.Ansi; ShortName->Buffer = Fcb->ShortNameBuffer; ShortName->Length = 0; ShortName->MaximumLength = sizeof(Fcb->ShortNameBuffer); /* Convert raw short name to a proper string */ Fati8dot3ToString(ShortNameRaw, FALSE, ShortName); /* Add the short name link */ FatInsertName(IrpContext, &Fcb->ParentFcb->Dcb.SplayLinksAnsi, &Fcb->ShortName); Fcb->ShortName.Fcb = Fcb; /* Get the long file name (if any) */ if (NumLFNs > 0) { /* Prepare the oem string */ LongNameOem.Buffer = DirEnt.FileName; LongNameOem.MaximumLength = FF_MAX_FILENAME; LongNameOem.Length = strlen(DirEnt.FileName); /* Prepare the unicode string */ UnicodeName = &Fcb->LongName.Name.String; UnicodeName->Length = (LongNameOem.Length + 1) * sizeof(WCHAR); UnicodeName->MaximumLength = UnicodeName->Length; UnicodeName->Buffer = FsRtlAllocatePool(PagedPool, UnicodeName->Length); /* Convert it to unicode */ Status = RtlOemStringToUnicodeString(UnicodeName, &LongNameOem, FALSE); if (!NT_SUCCESS(Status)) { ASSERT(FALSE); } /* Set its length */ Fcb->FileNameLength = UnicodeName->Length; /* Save case-preserved copy */ Fcb->ExactCaseLongName.Length = UnicodeName->Length; Fcb->ExactCaseLongName.MaximumLength = UnicodeName->Length; Fcb->ExactCaseLongName.Buffer = FsRtlAllocatePoolWithTag(PagedPool, UnicodeName->Length, TAG_FILENAME); RtlCopyMemory(Fcb->ExactCaseLongName.Buffer, UnicodeName->Buffer, UnicodeName->Length); /* Perform a trick which is done by MS's FASTFAT driver to monocase the filename */ RtlDowncaseUnicodeString(UnicodeName, UnicodeName, FALSE); RtlUpcaseUnicodeString(UnicodeName, UnicodeName, FALSE); DPRINT("Converted long name: %wZ\n", UnicodeName); /* Add the long unicode name link */ FatInsertName(IrpContext, &Fcb->ParentFcb->Dcb.SplayLinksUnicode, &Fcb->LongName); Fcb->LongName.Fcb = Fcb; /* Indicate that this FCB has a unicode long name */ SetFlag(Fcb->State, FCB_STATE_HAS_UNICODE_NAME); } else { /* No LFN, set exact case name to 0 length */ Fcb->ExactCaseLongName.Length = 0; Fcb->ExactCaseLongName.MaximumLength = 0; /* Set the length based on the short name */ Fcb->FileNameLength = RtlOemStringToCountedUnicodeSize(ShortName); } /* Mark the fact that names were added to splay trees*/ SetFlag(Fcb->State, FCB_STATE_HAS_NAMES); }
VOID NTAPI FatGetFcbUnicodeName(IN PFAT_IRP_CONTEXT IrpContext, IN PFCB Fcb, OUT PUNICODE_STRING LongName) { FF_DIRENT DirEnt; FF_ERROR Err; OEM_STRING ShortName; CHAR ShortNameBuf[13]; UCHAR EntryBuffer[32]; UCHAR NumLFNs; OEM_STRING LongNameOem; NTSTATUS Status; /* Make sure this FCB has a FullFAT handle associated with it */ if (Fcb->FatHandle == NULL && FatNodeType(Fcb) == FAT_NTC_DCB) { /* Open the dir with FullFAT */ Fcb->FatHandle = FF_OpenW(Fcb->Vcb->Ioman, &Fcb->FullFileName, FF_MODE_DIR, NULL); if (!Fcb->FatHandle) { ASSERT(FALSE); } } /* Get the dir entry */ Err = FF_GetEntry(Fcb->Vcb->Ioman, Fcb->FatHandle->DirEntry, Fcb->FatHandle->DirCluster, &DirEnt); if (Err != FF_ERR_NONE) { DPRINT1("Error %d getting dirent of a file\n", Err); return; } /* Read the dirent to fetch the raw short name */ FF_FetchEntry(Fcb->Vcb->Ioman, Fcb->FatHandle->DirCluster, Fcb->FatHandle->DirEntry, EntryBuffer); NumLFNs = (UCHAR)(EntryBuffer[0] & ~0x40); /* Check if we only have a short name. Convert it to unicode and return if that's the case */ if (NumLFNs == 0) { /* Initialize short name string */ ShortName.Buffer = ShortNameBuf; ShortName.Length = 0; ShortName.MaximumLength = 12; /* Convert raw short name to a proper string */ Fati8dot3ToString((PCHAR)EntryBuffer, FALSE, &ShortName); /* Convert it to unicode */ Status = RtlOemStringToCountedUnicodeString(LongName, &ShortName, FALSE); /* Ensure conversion was successful */ ASSERT(Status == STATUS_SUCCESS); /* Exit */ return; } /* Convert LFN from OEM to unicode and return */ LongNameOem.Buffer = DirEnt.FileName; LongNameOem.MaximumLength = FF_MAX_FILENAME; LongNameOem.Length = strlen(DirEnt.FileName); /* Convert it to unicode */ Status = RtlOemStringToUnicodeString(LongName, &LongNameOem, FALSE); /* Ensure conversion was successful */ ASSERT(Status == STATUS_SUCCESS); }