FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_INT8 *path) { FF_FILE *pFile; FF_ERROR Error = 0; FF_T_UINT8 EntryBuffer[32]; pFile = FF_Open(pIoman, path, FF_MODE_READ, &Error); if(!pFile) { return Error; // File in use or File not found! } pFile->FileDeleted = FF_TRUE; FF_lockFAT(pIoman); // Lock the FAT so its thread-safe. { FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! } FF_unlockFAT(pIoman); // Edit the Directory Entry! (So it appears as deleted); FF_lockDIR(pIoman); { FF_RmLFNs(pIoman, pFile->DirCluster, pFile->DirEntry); FF_FetchEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); EntryBuffer[0] = 0xE5; FF_PushEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); } FF_unlockDIR(pIoman); FF_FlushCache(pIoman); FF_Close(pFile); // Free the file pointer resources return 0; }
/** * @public * @brief Moves a file or directory from source to destination. * * @param pIoman The FF_IOMAN object pointer. * @param szSourceFile String of the source file to be moved or renamed. * @param szDestinationFile String of the destination file to where the source should be moved or renamed. * * @return FF_ERR_NONE on success. * @return FF_ERR_FILE_DESTINATION_EXISTS if the destination file exists. * @return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT if dirent creation failed (fatal error!). * @return FF_ERR_FILE_DIR_NOT_FOUND if destination directory was not found. * @return FF_ERR_FILE_SOURCE_NOT_FOUND if the source file was not found. * **/ FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile) { FF_ERROR Error; FF_FILE *pSrcFile, *pDestFile; FF_DIRENT MyFile; FF_T_UINT8 EntryBuffer[32]; FF_T_UINT16 i; FF_T_UINT32 DirCluster; if(!pIoman) { return FF_ERR_NULL_POINTER; } // Check destination file doesn't exist! pDestFile = FF_Open(pIoman, szDestinationFile, FF_MODE_READ, &Error); if(pDestFile || (Error == FF_ERR_FILE_OBJECT_IS_A_DIR)) { FF_Close(pDestFile); return FF_ERR_FILE_DESTINATION_EXISTS; // YES -- FAIL } pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_READ, &Error); if(Error == FF_ERR_FILE_OBJECT_IS_A_DIR) { // Open a directory for moving! pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_DIR, &Error); } if(pSrcFile) { // Create the new dirent. FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); MyFile.Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); MyFile.Filesize = pSrcFile->Filesize; MyFile.ObjectCluster = pSrcFile->ObjectCluster; MyFile.CurrentItem = 0; i = (FF_T_UINT16) strlen(szDestinationFile); while(i != 0) { if(szDestinationFile[i] == '\\' || szDestinationFile[i] == '/') { break; } i--; } strncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); if(i == 0) { i = 1; } DirCluster = FF_FindDir(pIoman, szDestinationFile, i); if(DirCluster) { // Destination Dir was found, we can now create the new entry. if(FF_CreateDirent(pIoman, DirCluster, &MyFile)) { FF_Close(pSrcFile); return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT; // FAILED } // Edit the Directory Entry! (So it appears as deleted); FF_lockDIR(pIoman); { FF_RmLFNs(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry); FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); EntryBuffer[0] = 0xE5; FF_PushEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); } FF_unlockDIR(pIoman); FF_Close(pSrcFile); FF_FlushCache(pIoman); return FF_ERR_NONE; } return FF_ERR_FILE_DIR_NOT_FOUND; } return FF_ERR_FILE_SOURCE_NOT_FOUND; // Source not found! }
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); }
FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) { FF_FILE *pFile; FF_ERROR Error = FF_ERR_NONE; FF_T_UINT8 EntryBuffer[32]; FF_T_SINT8 RetVal = FF_ERR_NONE; #ifdef FF_PATH_CACHE FF_T_UINT32 i; #endif if(!pIoman) { return FF_ERR_NULL_POINTER; } pFile = FF_Open(pIoman, path, FF_MODE_DIR, &Error); if(!pFile) { return Error; // File in use or File not found! } pFile->FileDeleted = FF_TRUE; FF_lockDIR(pIoman); { if(FF_isDirEmpty(pIoman, path)) { FF_lockFAT(pIoman); { FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! } FF_unlockFAT(pIoman); // Edit the Directory Entry! (So it appears as deleted); FF_RmLFNs(pIoman, pFile->DirCluster, pFile->DirEntry); FF_FetchEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); EntryBuffer[0] = 0xE5; FF_PushEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); #ifdef FF_PATH_CACHE FF_PendSemaphore(pIoman->pSemaphore); // Thread safety on shared object! { for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)strlen(path))) { pIoman->pPartition->PathCache[i].Path[0] = '\0'; pIoman->pPartition->PathCache[i].DirCluster = 0; FF_ReleaseSemaphore(pIoman->pSemaphore); } } } FF_ReleaseSemaphore(pIoman->pSemaphore); #endif FF_IncreaseFreeClusters(pIoman, pFile->iChainLength); FF_FlushCache(pIoman); } else { RetVal = FF_ERR_DIR_NOT_EMPTY; } } FF_unlockDIR(pIoman); FF_Close(pFile); // Free the file pointer resources // File is now lost! return RetVal; }
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); }