/** * @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; }