Beispiel #1
0
/**
 *	@public
 *	@brief	Unmounts the active partition.
 *
 *	@param	pIoman	FF_IOMAN Object.
 *
 *	@return FF_ERR_NONE on success.
 **/
FF_ERROR FF_UnmountPartition(FF_IOMAN *pIoman) {
	FF_T_SINT8 RetVal = FF_ERR_NONE;

	if(!pIoman) {
		return FF_ERR_NULL_POINTER;
	}

	FF_PendSemaphore(pIoman->pSemaphore);	// Ensure that there are no File Handles
	{
		if(!FF_ActiveHandles(pIoman)) {
			if(pIoman->FirstFile == NULL) {
				// Release Semaphore to call this function!
				FF_ReleaseSemaphore(pIoman->pSemaphore);
				FF_FlushCache(pIoman);			// Flush any unwritten sectors to disk.
				// Reclaim Semaphore
				FF_PendSemaphore(pIoman->pSemaphore);
				pIoman->pPartition->PartitionMounted = FF_FALSE;
			} else {
				RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES;
			}
		} else {
			RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES;	// Active handles found on the cache.
		}
	}
	FF_ReleaseSemaphore(pIoman->pSemaphore);

	return RetVal;
}
Beispiel #2
0
void FF_lockFAT(FF_IOMAN *pIoman) {
	FF_PendSemaphore(pIoman->pSemaphore);	// Use Semaphore to protect FAT modifications.
	{
		while((pIoman->Locks & FF_FAT_LOCK)) {
			FF_ReleaseSemaphore(pIoman->pSemaphore);
			FF_Yield();						// Keep Releasing and Yielding until we have the Fat protector.
			FF_PendSemaphore(pIoman->pSemaphore);
		}
		pIoman->Locks |= FF_FAT_LOCK;
	}
	FF_ReleaseSemaphore(pIoman->pSemaphore);
}
Beispiel #3
0
/**
 *	@public
 *	@brief	Unmounts the active partition.
 *
 *	@param	pIoman	FF_IOMAN Object.
 *
 *	@return FF_ERR_NONE on success.
 **/
FF_ERROR FF_UnmountPartition(FF_IOMAN *pIoman) {
	FF_ERROR RetVal = FF_ERR_NONE;
#ifdef FF_MIRROR_FATS_UMOUNT
	FF_T_UINT i, y;
	FF_BUFFER *pBuffer;
#endif 

	if(!pIoman || !pIoman->pPartition) {
		return FF_ERR_NULL_POINTER | FF_UNMOUNTPARTITION;
	}
	if (!pIoman->pPartition->PartitionMounted)
		return FF_ERR_NONE;

	FF_PendSemaphore(pIoman->pSemaphore);	// Ensure that there are no File Handles
	{
		if(!FF_ActiveHandles(pIoman)) {
			if(pIoman->FirstFile == NULL) {
				// Release Semaphore to call this function!
				FF_ReleaseSemaphore(pIoman->pSemaphore);
				RetVal = FF_FlushCache(pIoman);			// Flush any unwritten sectors to disk.
				if(FF_isERR(RetVal)) {
					return RetVal;
				}
				// Reclaim Semaphore
				FF_PendSemaphore(pIoman->pSemaphore);
				pIoman->pPartition->PartitionMounted = FF_FALSE;

#ifdef FF_MIRROR_FATS_UMOUNT
				FF_ReleaseSemaphore(pIoman->pSemaphore);
				for(i = 0; i < pIoman->pPartition->SectorsPerFAT; i++) {
					 pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ);
					 if(!pBuffer) {
						  RetVal = FF_ERR_DEVICE_DRIVER_FAILED | FF_UNMOUNTPARTITION;
						  break;
					 }
					 for(y = 0; y < pIoman->pPartition->NumFATS; y++) {
						  FF_BlockWrite(pIoman, pIoman->pPartition->FatBeginLBA + (y*pIoman->pPartition->SectorsPerFAT) + i, 1, pBuffer->pBuffer, FF_FALSE);
					 }					 
				}
				FF_PendSemaphore(pIoman->pSemaphore);
#endif
			} else {
				RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNTPARTITION;
			}
		} else {
			RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNTPARTITION;	// Active handles found on the cache.
		}
	}
	FF_ReleaseSemaphore(pIoman->pSemaphore);

	return RetVal;
}
Beispiel #4
0
FF_T_SINT32 FF_BlockWrite(FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer, FF_T_BOOL aSemLocked) {
	FF_T_SINT32 slRetVal = 0;

	if(pIoman->pPartition->TotalSectors) {
		if((ulSectorLBA + ulNumSectors) > (pIoman->pPartition->TotalSectors + pIoman->pPartition->BeginLBA)) {
			return (FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_BLOCKWRITE);
		}
	}
	
	if(pIoman->pBlkDevice->fnpWriteBlocks) do {	// Make sure we don't execute a NULL.
#ifdef	FF_BLKDEV_USES_SEM
		if (!aSemLocked || pIoman->pSemaphore != pIoman->pBlkDevSemaphore)
			FF_PendSemaphore(pIoman->pBlkDevSemaphore);
#endif
		slRetVal = pIoman->pBlkDevice->fnpWriteBlocks(pBuffer, ulSectorLBA, ulNumSectors, pIoman->pBlkDevice->pParam);
#ifdef	FF_BLKDEV_USES_SEM
		if (!aSemLocked || pIoman->pSemaphore != pIoman->pBlkDevSemaphore)
			FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore);
#endif
		if(!FF_isERR(slRetVal) && FF_GETERROR(slRetVal) != FF_ERR_DRIVER_BUSY) {
			break;
		}
		FF_Sleep(FF_DRIVER_BUSY_SLEEP);
	} while (FF_TRUE);

	return slRetVal;
}
Beispiel #5
0
/**
 *	@private
 *	@brief		Flushes all Write cache buffers with no active Handles.
 *
 *	@param		pIoman	IOMAN Object.
 *
 *	@return		FF_ERR_NONE on Success.
 **/
FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) {

	FF_T_UINT16 i,x;

	if(!pIoman) {
		return FF_ERR_NULL_POINTER | FF_FLUSHCACHE;
	}

	FF_PendSemaphore(pIoman->pSemaphore);
	{
		for(i = 0; i < pIoman->CacheSize; i++) {
			if((pIoman->pBuffers + i)->NumHandles == 0 && (pIoman->pBuffers + i)->Modified == FF_TRUE) {

				FF_BlockWrite(pIoman, (pIoman->pBuffers + i)->Sector, 1, (pIoman->pBuffers + i)->pBuffer);

				// Buffer has now been flushed, mark it as a read buffer and unmodified.
				(pIoman->pBuffers + i)->Mode = FF_MODE_READ;
				(pIoman->pBuffers + i)->Modified = FF_FALSE;

				// Search for other buffers that used this sector, and mark them as modified
				// So that further requests will result in the new sector being fetched.
				for(x = 0; x < pIoman->CacheSize; x++) {
					if(x != i) {
						if((pIoman->pBuffers + x)->Sector == (pIoman->pBuffers + i)->Sector && (pIoman->pBuffers + x)->Mode == FF_MODE_READ) {
							(pIoman->pBuffers + x)->Modified = FF_TRUE;
						}
					}
				}
			}
		}
	}
	FF_ReleaseSemaphore(pIoman->pSemaphore);

	return FF_ERR_NONE;
}
Beispiel #6
0
void FF_unlockFAT(FF_IOMAN *pIoman) {
	FF_PendSemaphore(pIoman->pSemaphore);
	{
		pIoman->Locks &= ~FF_FAT_LOCK;
	}
	FF_ReleaseSemaphore(pIoman->pSemaphore);
}
Beispiel #7
0
/**
 *	@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;
}
Beispiel #8
0
/**
 *	@private
 *	@brief	Releases a buffer resource.
 *
 *	@param	pIoman	Pointer to an FF_IOMAN object.
 *	@param	pBuffer	Pointer to an FF_BUFFER object.
 *
 **/
void FF_ReleaseBuffer(FF_IOMAN *pIoman, FF_BUFFER *pBuffer) {
	// Protect description changes with a semaphore.
	FF_PendSemaphore(pIoman->pSemaphore);
	{
		if (pBuffer->NumHandles) {
			pBuffer->NumHandles--;
		} else {
			//printf ("FF_ReleaseBuffer: buffer not claimed\n");
		}
	}
	FF_ReleaseSemaphore(pIoman->pSemaphore);
}
Beispiel #9
0
signed int fnRead(unsigned char *buffer, unsigned long sector, unsigned short sectors, BLK_DEV_LINUX pDevice) {
	unsigned long long address;
	unsigned long	Read;

	address = (unsigned long long) sector * pDevice->BlockSize;

	FF_PendSemaphore(pDevice->AccessSem);
	{
		fseeko64(pDevice->pDevice, address, 0);
		Read = fread(buffer, pDevice->BlockSize, sectors, pDevice->pDevice);
	}
	FF_ReleaseSemaphore(pDevice->AccessSem);

	read_inc();

	return Read / pDevice->BlockSize;
}
Beispiel #10
0
/**
 *	@brief	Thread-Safe BlockDevice Write operation for Windows.
 *
 **/
signed int fnWrite(unsigned char *buffer, unsigned long sector, unsigned short sectors, HANDLE hDevice) {
	struct _DEV_INFO	*ptDevInfo = (struct _DEV_INFO *) hDevice;
	LARGE_INTEGER		address;
	DWORD				Written;

	address.QuadPart = (unsigned long long) sector * ptDevInfo->BlockSize;
	
	FF_PendSemaphore(ptDevInfo->AccessSem);
	{
		SetFilePointerEx(ptDevInfo->hDev, address, NULL, FILE_BEGIN);
		WriteFile(ptDevInfo->hDev, buffer, ptDevInfo->BlockSize * sectors, &Written, NULL);
	}
	FF_ReleaseSemaphore(ptDevInfo->AccessSem);

	write_inc();

	return Written / ptDevInfo->BlockSize;
}
Beispiel #11
0
signed int fnWrite(unsigned char *buffer, unsigned long sector, unsigned short sectors, BLK_DEV_LINUX pDevice) {
	unsigned long long address;
	unsigned long Written;

	address = (unsigned long long) sector * pDevice->BlockSize;

	FF_PendSemaphore(pDevice->AccessSem);
	{
		fseeko64(pDevice->pDevice, address, 0);
		Written = fwrite(buffer, pDevice->BlockSize, sectors, pDevice->pDevice);

	}
	FF_ReleaseSemaphore(pDevice->AccessSem);

	write_inc();

	return Written / pDevice->BlockSize;
}
Beispiel #12
0
signed int fnWrite(unsigned char *buffer, unsigned long sector, unsigned short sectors, HANDLE hDevice) {
	struct _DEV_INFO *ptDevInfo = (struct _DEV_INFO *) hDevice;
	LARGE_INTEGER address;
	DWORD	Written;
	//unsigned long retVal;

	address.QuadPart = (unsigned long long) sector * ptDevInfo->BlockSize;
	
	FF_PendSemaphore(ptDevInfo->AccessSem);
	{
		//_fseeki64(pParam, address, SEEK_SET);
		SetFilePointerEx(ptDevInfo->hDev, address, NULL, FILE_BEGIN);
		//retVal = fwrite(buffer, BLOCK_SIZE, sectors, pParam);
		WriteFile(ptDevInfo->hDev, buffer, ptDevInfo->BlockSize * sectors, &Written, NULL);
	}
	FF_ReleaseSemaphore(ptDevInfo->AccessSem);
	return Written;
}
Beispiel #13
0
static FF_T_SINT32 FF_WriteClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) {
	FF_T_UINT32 Sectors;
	FF_T_UINT32 SequentialClusters = 0;
	FF_T_UINT32 nItemLBA;
	FF_T_SINT32 RetVal;	

	while(Count != 0) {
		if((Count - 1) > 0) {
			SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1));
		}
		Sectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster;
		nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster);
		nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA);

		do {
			if(pFile->pIoman->pBlkDevice->fnWriteBlocks) {
#ifdef	FF_BLKDEV_USES_SEM
				FF_PendSemaphore(pFile->pIoman->pSemaphore);
#endif
				// Called from FF_Write, sem not claimed
				RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, Sectors, pFile->pIoman->pBlkDevice->pParam);
#ifdef	FF_BLKDEV_USES_SEM
				FF_ReleaseSemaphore(pFile->pIoman->pSemaphore);
#endif
				if(RetVal == FF_ERR_DRIVER_BUSY) {
					FF_Yield();
					FF_Sleep(FF_DRIVER_BUSY_SLEEP);
				}
			} else {
				RetVal = FF_ERR_DEVICE_DRIVER_FAILED;
			}
			
		}while(RetVal == FF_ERR_DRIVER_BUSY);
		
		Count -= (SequentialClusters + 1);
		pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1));
		pFile->CurrentCluster += (SequentialClusters + 1);
		buffer += Sectors * pFile->pIoman->BlkSize;
		SequentialClusters = 0;
	}

	return 0;
}
Beispiel #14
0
/**
 *	@public
 *	@brief	Unregister a Blockdevice, so that the IOMAN can be re-used for another device.
 *
 *	Any active partitions must be Unmounted first.
 *
 *	@param	pIoman	FF_IOMAN object.
 *
 *	@return	FF_ERR_NONE on success.
 **/
FF_ERROR FF_UnregisterBlkDevice(FF_IOMAN *pIoman) {

	FF_T_SINT8 RetVal = FF_ERR_NONE;

	if(!pIoman) {
		return FF_ERR_NULL_POINTER;
	}

	FF_PendSemaphore(pIoman->pSemaphore);
	{
		if(pIoman->pPartition->PartitionMounted == FF_FALSE) {
			pIoman->pBlkDevice->devBlkSize		= 0;
			pIoman->pBlkDevice->fnpReadBlocks	= NULL;
			pIoman->pBlkDevice->fnpWriteBlocks	= NULL;
			pIoman->pBlkDevice->pParam			= NULL;
		} else {
			RetVal = FF_ERR_IOMAN_PARTITION_MOUNTED;
		}
	}
	FF_ReleaseSemaphore(pIoman->pSemaphore);

	return RetVal;
}
Beispiel #15
0
FF_T_SINT32 FF_BlockRead(FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer) {
	FF_T_SINT32 slRetVal = 0;

	if(pIoman->pPartition->TotalSectors) {
		if((ulSectorLBA + ulNumSectors) > (pIoman->pPartition->TotalSectors + pIoman->pPartition->BeginLBA)) {
			return -(FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_BLOCKREAD);		
		}
	}
	
	if(pIoman->pBlkDevice->fnpReadBlocks) {	// Make sure we don't execute a NULL.
#ifdef	FF_BLKDEV_USES_SEM
		FF_PendSemaphore(pIoman->pBlkDevSemaphore);
#endif
		slRetVal = pIoman->pBlkDevice->fnpReadBlocks(pBuffer, ulSectorLBA, ulNumSectors, pIoman->pBlkDevice->pParam);
#ifdef	FF_BLKDEV_USES_SEM
		FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore);
#endif
		if(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY) {
			FF_Sleep(FF_DRIVER_BUSY_SLEEP);
		}
	} while(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY);

	return slRetVal;
}
Beispiel #16
0
/**
 *	@private
 *	@brief	Releases a buffer resource.
 *
 *	@param	pIoman	Pointer to an FF_IOMAN object.
 *	@param	pBuffer	Pointer to an FF_BUFFER object.
 *
 **/
FF_ERROR FF_ReleaseBuffer(FF_IOMAN *pIoman, FF_BUFFER *pBuffer) {
	FF_ERROR Error = FF_ERR_NONE;
	
	// Protect description changes with a semaphore.
	FF_PendSemaphore(pIoman->pSemaphore);
	{
		if (pBuffer->NumHandles) {
			pBuffer->NumHandles--;
		} else {
			//printf ("FF_ReleaseBuffer: buffer not claimed\n");
		}
#ifdef FF_CACHE_WRITE_THROUGH
		if(pBuffer->Modified == FF_TRUE) {
			Error = FF_BlockWrite(pIoman, pBuffer->Sector, 1, pBuffer->pBuffer, FF_TRUE);
			if(!FF_isERR(Error)) {				// Ensure if an error occurs its still possible to write the block again.
				pBuffer->Modified = FF_FALSE;
			}
		}
#endif
	}
	FF_ReleaseSemaphore(pIoman->pSemaphore);

	return Error;
}
Beispiel #17
0
FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) {
	FF_BUFFER	*pBuffer;
	FF_BUFFER	*pBufLRU;
//	FF_BUFFER	*pBufLHITS = NULL;  // Wasn't use anymore?
	FF_BUFFER	*pBufMatch = NULL;
	FF_T_SINT32	RetVal;
	FF_T_INT    LoopCount = FF_GETBUFFER_WAIT_TIME;

	FF_T_INT cacheSize = pIoman->CacheSize;
	if (cacheSize <= 0) {
		return NULL;
	}

	while(!pBufMatch) {
		if (!--LoopCount) {
			//
			// *pError = FF_ERR_IOMAN_GETBUFFER_TIMEOUT;
			//
			return NULL;
		}
		FF_PendSemaphore(pIoman->pSemaphore);
		{

			for(pBuffer = pIoman->pBuffers; pBuffer < pIoman->pBuffers + cacheSize; pBuffer++) {
				if(pBuffer->Sector == Sector && pBuffer->Valid) {
					pBufMatch = pBuffer;
					break;	// Don't look further if you found a perfect match
				}
			}

			if(pBufMatch) {
				// A Match was found process!
				if(Mode == FF_MODE_READ && pBufMatch->Mode == FF_MODE_READ) {
					pBufMatch->NumHandles += 1;
					pBufMatch->Persistance += 1;
					break;
				}

				if(pBufMatch->NumHandles == 0) {
					pBufMatch->Mode = (Mode & FF_MODE_RD_WR);
					if((Mode & FF_MODE_WRITE) != 0) {	// This buffer has no attached handles.
						pBufMatch->Modified = FF_TRUE;
					}
					pBufMatch->NumHandles = 1;
					pBufMatch->Persistance += 1;
					break;
				}

				pBufMatch = NULL;	// Sector is already in use, keep yielding until its available!

			} else {
				pBufLRU   = NULL;	// So put them to NULL here

				for(pBuffer = pIoman->pBuffers; pBuffer < pIoman->pBuffers + cacheSize; pBuffer++) {
					if(pBuffer->NumHandles)
						continue;  // Occupied
					pBuffer->LRU += 1;

					if(!pBufLRU) {
						pBufLRU = pBuffer;
					}

					if(pBuffer->LRU > pBufLRU->LRU ||
					   (pBuffer->LRU == pBufLRU->LRU && pBuffer->Persistance > pBufLRU->Persistance)) {
						pBufLRU = pBuffer;
					}

				}
				// Choose a suitable buffer!
				if(pBufLRU) {
					// Process the suitable candidate.
					if(pBufLRU->Modified == FF_TRUE) {
						// Along with the FF_TRUE parameter to indicate semapahore has been claimed

						RetVal = FF_BlockWrite(pIoman, pBufLRU->Sector, 1, pBufLRU->pBuffer, FF_TRUE);
						if (RetVal < 0) {
							pBufMatch = NULL;
							break;
						}
					}
					if (Mode == FF_MODE_WR_ONLY) {
						memset (pBufLRU->pBuffer, '\0', pIoman->BlkSize);
					} else {
						RetVal = FF_BlockRead(pIoman, Sector, 1, pBufLRU->pBuffer, FF_TRUE);
						if (RetVal < 0) {
							pBufMatch = NULL;
							break;
						}
					}
					pBufLRU->Mode = (Mode & FF_MODE_RD_WR);
					pBufLRU->Persistance = 1;
					pBufLRU->LRU = 0;
					pBufLRU->NumHandles = 1;
					pBufLRU->Sector = Sector;

					pBufLRU->Modified = (Mode & FF_MODE_WRITE) != 0;

					pBufLRU->Valid = FF_TRUE;
					pBufMatch = pBufLRU;
					break;
				}

			}
		}
		FF_ReleaseSemaphore(pIoman->pSemaphore);
		// Better to go asleep to give low-priority task a chance to release buffer(s)
		FF_Sleep (FF_GETBUFFER_SLEEP_TIME);
	}	// while(!pBufMatch)
	FF_ReleaseSemaphore(pIoman->pSemaphore);

	return pBufMatch;	// Return the Matched Buffer!
}
Beispiel #18
0
FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) {
	FF_BUFFER	*pBuffer;
	FF_BUFFER	*pBufLRU	= NULL;
	FF_BUFFER	*pBufLHITS	= NULL;
	FF_BUFFER	*pBufMatch	= NULL;

	FF_T_UINT32	i;

	while(!pBufMatch) {
		FF_PendSemaphore(pIoman->pSemaphore);
		{
			pBuffer = pIoman->pBuffers;
			// HT if a perfect match has priority, find that first
			for(i = 0; i < pIoman->CacheSize; i++, pBuffer++) {
				pBuffer = (pIoman->pBuffers + i);
				if(pBuffer->Sector == Sector && pBuffer->Valid == FF_TRUE) {
					pBufMatch = pBuffer;
					break;	// Why look further if you found a perfect match?
				}
			}

			if(pBufMatch) {
				// A Match was found process!
				if(Mode == FF_MODE_READ && pBufMatch->Mode == FF_MODE_READ) {
					pBufMatch->NumHandles += 1;
					pBufMatch->Persistance += 1;
					FF_ReleaseSemaphore(pIoman->pSemaphore);
					return pBufMatch;
				}

				if(pBufMatch->Mode == FF_MODE_WRITE && pBufMatch->NumHandles == 0) {	// This buffer has no attached handles.
					pBufMatch->Mode = Mode;
					pBufMatch->NumHandles = 1;
					pBufMatch->Persistance += 1;
					FF_ReleaseSemaphore(pIoman->pSemaphore);
					return pBufMatch;
				}

				if(pBufMatch->Mode == FF_MODE_READ && Mode == FF_MODE_WRITE && pBufMatch->NumHandles == 0) {
					pBufMatch->Mode = Mode;
					pBufMatch->Modified = FF_TRUE;
					pBufMatch->NumHandles = 1;
					pBufMatch->Persistance += 1;
					FF_ReleaseSemaphore(pIoman->pSemaphore);
					return pBufMatch;
				}

				pBufMatch = NULL;	// Sector is already in use, keep yielding until its available!

			} else {
				pBuffer = pIoman->pBuffers;
				for(i = 0; i < pIoman->CacheSize; i++, pBuffer++) {
					if(pBuffer->NumHandles == 0) {
						pBuffer->LRU += 1;

						if(!pBufLRU) {
							pBufLRU = pBuffer;
						}
						if(!pBufLHITS) {
							pBufLHITS = pBuffer;
						}

						if(pBuffer->LRU >= pBufLRU->LRU) {
							if(pBuffer->LRU == pBufLRU->LRU) {
								if(pBuffer->Persistance > pBufLRU->Persistance) {
									pBufLRU = pBuffer;
								}
							} else {
								pBufLRU = pBuffer;
							}
						}

						if(pBuffer->Persistance < pBufLHITS->Persistance) {
							pBufLHITS = pBuffer;
						}
					}
				}

				if(pBufLRU) {
					// Process the suitable candidate.
					if(pBufLRU->Modified == FF_TRUE) {
						FF_BlockWrite(pIoman, pBufLRU->Sector, 1, pBufLRU->pBuffer);
					}
					pBufLRU->Mode = Mode;
					pBufLRU->Persistance = 1;
					pBufLRU->LRU = 0;
					pBufLRU->NumHandles = 1;
					pBufLRU->Sector = Sector;

					if(Mode == FF_MODE_WRITE) {
						pBufLRU->Modified = FF_TRUE;
					} else {
						pBufLRU->Modified = FF_FALSE;
					}

					FF_BlockRead(pIoman, Sector, 1, pBufLRU->pBuffer);
					pBufLRU->Valid = FF_TRUE;
					FF_ReleaseSemaphore(pIoman->pSemaphore);
					return pBufLRU;
				}

			}
		}
		FF_ReleaseSemaphore(pIoman->pSemaphore);
		FF_Yield();	// Better to go asleep to give low-priority task a chance to release buffer(s)
	}

	return pBufMatch;	// Return the Matched Buffer!
}
Beispiel #19
0
/**
 *	@public
 *	@brief	Equivalent to fread()
 *
 *	@param	pFile		FF_FILE object that was created by FF_Open().
 *	@param	ElementSize	The size of an element to read.
 *	@param	Count		The number of elements to read.
 *	@param	buffer		A pointer to a buffer of adequate size to be filled with the requested data.
 *
 *	@return Number of bytes read.
 *
 **/
FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer) {
	FF_T_UINT32 nBytes = ElementSize * Count;
	FF_T_UINT32	nBytesRead = 0;
	FF_T_UINT32 nBytesToRead;
	FF_IOMAN	*pIoman;
	FF_BUFFER	*pBuffer;
	FF_T_UINT32 nRelBlockPos;
	FF_T_UINT32	nItemLBA;
	FF_T_SINT32	RetVal = 0;
	FF_T_UINT16	sSectors;
	FF_T_UINT32 nRelClusterPos;
	FF_T_UINT32 nBytesPerCluster;
	FF_T_UINT32	nClusterDiff;

	if(!pFile) {
		return FF_ERR_NULL_POINTER;
	}

	if(!(pFile->Mode & FF_MODE_READ)) {
		return FF_ERR_FILE_NOT_OPENED_IN_READ_MODE;
	}

	pIoman = pFile->pIoman;

	if(pFile->FilePointer == pFile->Filesize) {
		return 0;
	}

	if((pFile->FilePointer + nBytes) > pFile->Filesize) {
		nBytes = pFile->Filesize - pFile->FilePointer;
	}
	
	nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
	if(nClusterDiff) {
		if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
			pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
			pFile->CurrentCluster += nClusterDiff;
		}
	}

	nRelBlockPos = FF_getMinorBlockEntry(pIoman, pFile->FilePointer, 1); // Get the position within a block.
	
	nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
	nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);

	if((nRelBlockPos + nBytes) < pIoman->BlkSize) {	// Bytes to read are within a block and less than a block size.
		pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ);
		{
			memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytes);
		}
		FF_ReleaseBuffer(pIoman, pBuffer);

		pFile->FilePointer += nBytes;
		
		return nBytes;		// Return the number of bytes read.

	} else {

		//---------- Read (memcpy) to a Sector Boundary
		if(nRelBlockPos != 0) {	// Not on a sector boundary, at this point the LBA is known.
			nBytesToRead = pIoman->BlkSize - nRelBlockPos;
			pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ);
			{
				// Here we copy to the sector boudary.
				memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytesToRead);
			}
			FF_ReleaseBuffer(pIoman, pBuffer);

			nBytes				-= nBytesToRead;
			nBytesRead			+= nBytesToRead;
			pFile->FilePointer	+= nBytesToRead;
			buffer				+= nBytesToRead;
			
		}

		//---------- Read to a Cluster Boundary
		
		nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1);
		nBytesPerCluster = (pIoman->pPartition->SectorsPerCluster * pIoman->BlkSize);
		if(nRelClusterPos != 0 && nBytes >= nBytesPerCluster) { // Need to get to cluster boundary
			
			nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
			if(nClusterDiff) {
				if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
					pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
					pFile->CurrentCluster += nClusterDiff;
				}
			}
		
			nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
			nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);

			sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize));
			
			do {
				if(pIoman->pBlkDevice->fnReadBlocks) {
#ifdef	FF_BLKDEV_USES_SEM
					FF_PendSemaphore(pFile->pIoman->pSemaphore);
#endif
					RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam);
#ifdef	FF_BLKDEV_USES_SEM
					FF_ReleaseSemaphore(pFile->pIoman->pSemaphore);
#endif
				}
				if(RetVal == FF_ERR_DRIVER_BUSY) {
					FF_Yield();
					FF_Sleep(FF_DRIVER_BUSY_SLEEP);
				}
			}while(RetVal == FF_ERR_DRIVER_BUSY);
			
			nBytesToRead		 = sSectors * pIoman->BlkSize;
			nBytes				-= nBytesToRead;
			buffer				+= nBytesToRead;
			nBytesRead			+= nBytesToRead;
			pFile->FilePointer	+= nBytesToRead;

		}

		//---------- Read Clusters
		if(nBytes >= nBytesPerCluster) {
			//----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check.
			nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
			if(nClusterDiff) {
				if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
					pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
					pFile->CurrentCluster += nClusterDiff;
				}
			}
			//----- End of Contributor fix.

			FF_ReadClusters(pFile, (nBytes / nBytesPerCluster), buffer);
			nBytesToRead = (nBytesPerCluster *  (nBytes / nBytesPerCluster));

			pFile->FilePointer	+= nBytesToRead;

			nBytes			-= nBytesToRead;
			buffer			+= nBytesToRead;
			nBytesRead		+= nBytesToRead;
		}

		//---------- Read Remaining Blocks
		if(nBytes >= pIoman->BlkSize) {
			sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize);
			
			nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
			if(nClusterDiff) {
				if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
					pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
					pFile->CurrentCluster += nClusterDiff;
				}
			}
			
			nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
			nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
			
			do {
				if(pIoman->pBlkDevice->fnReadBlocks) {
#ifdef	FF_BLKDEV_USES_SEM
					FF_PendSemaphore(pFile->pIoman->pSemaphore);
#endif
					RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam);
#ifdef	FF_BLKDEV_USES_SEM
					FF_ReleaseSemaphore(pFile->pIoman->pSemaphore);
#endif
				}
				if(RetVal == FF_ERR_DRIVER_BUSY) {
					FF_Yield();
					FF_Sleep(FF_DRIVER_BUSY_SLEEP);
				}
			}while(RetVal == FF_ERR_DRIVER_BUSY);
			
			nBytesToRead = sSectors * pIoman->BlkSize;
			pFile->FilePointer	+= nBytesToRead;
			nBytes				-= nBytesToRead;
			buffer				+= nBytesToRead;
			nBytesRead			+= nBytesToRead;
		}

		//---------- Read (memcpy) Remaining Bytes
		if(nBytes > 0) {
			
			nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
			if(nClusterDiff) {
				if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
					pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
					pFile->CurrentCluster += nClusterDiff;
				}
			}
			
			nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
			nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
			pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ);
			{
				memcpy(buffer, pBuffer->pBuffer, nBytes);
			}
			FF_ReleaseBuffer(pIoman, pBuffer);

			nBytesToRead = nBytes;
			pFile->FilePointer	+= nBytesToRead;
			nBytes				-= nBytesToRead;
			buffer				+= nBytesToRead;
			nBytesRead			+= nBytesToRead;

		}
	}

	return nBytesRead;
}
Beispiel #20
0
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;
}
Beispiel #21
0
/**
 *	@public
 *	@brief	Opens a File for Access
 *
 *	@param	pIoman		FF_IOMAN object that was created by FF_CreateIOMAN().
 *	@param	path		Path to the File or object.
 *	@param	Mode		Access Mode required. Modes are a little complicated, the function FF_GetModeBits()
 *	@param	Mode		will convert a stdio Mode string into the equivalent Mode bits for this parameter.
 *	@param	pError		Pointer to a signed byte for error checking. Can be NULL if not required.
 *	@param	pError		To be checked when a NULL pointer is returned.
 *
 *	@return	NULL pointer on Error, in which case pError should be checked for more information.
 *	@return	pError can be:
 **/
FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError) {
	FF_FILE		*pFile;
	FF_FILE		*pFileChain;
	FF_DIRENT	Object;
	FF_T_UINT32 DirCluster, FileCluster;
	FF_T_UINT32	nBytesPerCluster;
	FF_T_INT8	filename[FF_MAX_FILENAME];

	FF_T_UINT16	i;

	if(pError) {
		*pError = 0;
	}
	
	if(!pIoman) {
		if(pError) {
			*pError = FF_ERR_NULL_POINTER;
		}
		return (FF_FILE *)NULL;
	}
	pFile = FF_MALLOC(sizeof(FF_FILE));
	if(!pFile) {
		if(pError) {
			*pError = FF_ERR_NOT_ENOUGH_MEMORY;
		}
		return (FF_FILE *)NULL;
	}

	// Get the Mode Bits.
	pFile->Mode = Mode;

	i = (FF_T_UINT16) strlen(path);

	while(i != 0) {
		if(path[i] == '\\' || path[i] == '/') {
			break;
		}
		i--;
	}

	strncpy(filename, (path + i + 1), FF_MAX_FILENAME);

	if(i == 0) {
		i = 1;
	}
	

	DirCluster = FF_FindDir(pIoman, path, i);

	if(DirCluster) {
		//RetVal = //FF_FindEntry(pIoman, DirCluster, filename, &Object, FF_TRUE);
		//if(RetVal >= 0) {
			//FileCluster = Object.ObjectCluster;//FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object);
		//} else {
		//	FileCluster = 0;
		//}

		FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object);

		if(!FileCluster) {	// If 0 was returned, it might be because the file has no allocated cluster
			if(strlen(filename) == strlen(Object.FileName)) {
				if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) strlen(filename)) == FF_TRUE) {
					// The file really was found!
					FileCluster = 1;
				} 
			}
		}

		if(!FileCluster) {
			if((pFile->Mode & FF_MODE_CREATE)) {
				FileCluster = FF_CreateFile(pIoman, DirCluster, filename, &Object);
				Object.CurrentItem += 1;
			}
		}
		
		if(FileCluster) {
			if(Object.Attrib == FF_FAT_ATTR_DIR) {
				if(!(pFile->Mode & FF_MODE_DIR)) {
					// Not the object, File Not Found!
					FF_FREE(pFile);
					if(pError) {
						*pError = FF_ERR_FILE_OBJECT_IS_A_DIR;
					}
					return (FF_FILE *) NULL;
				}
			}
			
			//---------- Ensure Read-Only files don't get opened for Writing.
			if((pFile->Mode & FF_MODE_WRITE) || (pFile->Mode & FF_MODE_APPEND)) {
				if((Object.Attrib & FF_FAT_ATTR_READONLY)) {
					FF_FREE(pFile);
					if(pError) {
						*pError = FF_ERR_FILE_IS_READ_ONLY;
					}
					return (FF_FILE *) NULL;
				}
			}
			pFile->pIoman				= pIoman;
			pFile->FilePointer			= 0;
			pFile->ObjectCluster		= Object.ObjectCluster;
			pFile->Filesize				= Object.Filesize;
			pFile->CurrentCluster		= 0;
			pFile->AddrCurrentCluster	= pFile->ObjectCluster;
			//pFile->Mode					= Mode;
			pFile->Next					= NULL;
			pFile->DirCluster			= DirCluster;
			pFile->DirEntry				= Object.CurrentItem - 1;
			nBytesPerCluster			= pFile->pIoman->pPartition->SectorsPerCluster / pIoman->BlkSize;
			pFile->iChainLength			= 0;
			pFile->iEndOfChain			= 0;
			pFile->FileDeleted			= FF_FALSE;

			// File Permission Processing
			// Only "w" and "w+" mode strings can erase a file's contents.
			// Any other combinations will not cause an erase.
			if((pFile->Mode & FF_MODE_TRUNCATE)) {
				pFile->Filesize = 0;
				pFile->FilePointer = 0;
			}

			/*
				Add pFile onto the end of our linked list of FF_FILE objects.
			*/
			FF_PendSemaphore(pIoman->pSemaphore);
			{
				if(!pIoman->FirstFile) {
					pIoman->FirstFile = pFile;
				} else {
					pFileChain = (FF_FILE *) pIoman->FirstFile;
					do {
						if(pFileChain->ObjectCluster == pFile->ObjectCluster) {
							// File is already open! DON'T ALLOW IT!
							FF_ReleaseSemaphore(pIoman->pSemaphore);
							FF_FREE(pFile);
							if(pError) {
								*pError = FF_ERR_FILE_ALREADY_OPEN;
							}
							return (FF_FILE *) NULL;
						}
						if(!pFileChain->Next) {
							pFileChain->Next = pFile;
							break;
						}
						pFileChain = (FF_FILE *) pFileChain->Next;
					}while(pFileChain != NULL);
				}
			}
			FF_ReleaseSemaphore(pIoman->pSemaphore);

			return pFile;
		}else {
			FF_FREE(pFile);
			if(pError) {
				*pError = FF_ERR_FILE_NOT_FOUND;
			}
			return (FF_FILE *) NULL;
		} 
	}
	if(pError) {
		*pError = FF_ERR_FILE_INVALID_PATH;
	}

	FF_FREE(pFile);

	return (FF_FILE *)NULL;
}
Beispiel #22
0
/**
 *	@public
 *	@brief	Writes data to a File.
 *
 *	@param	pFile			FILE Pointer.
 *	@param	ElementSize		Size of an Element of Data to be copied. (in bytes). 
 *	@param	Count			Number of Elements of Data to be copied. (ElementSize * Count must not exceed ((2^31)-1) bytes. (2GB). For best performance, multiples of 512 bytes or Cluster sizes are best.
 *	@param	buffer			Byte-wise buffer containing the data to be written.
 *
 *	@return
 **/
FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer) {
	FF_T_UINT32 nBytes = ElementSize * Count;
	FF_T_UINT32	nBytesWritten = 0;
	FF_T_UINT32 nBytesToWrite;
	FF_IOMAN	*pIoman;
	FF_BUFFER	*pBuffer;
	FF_T_UINT32 nRelBlockPos;
	FF_T_UINT32	nItemLBA;
	FF_T_SINT32	RetVal = 0;
	FF_T_UINT16	sSectors;
	FF_T_UINT32 nRelClusterPos;
	FF_T_UINT32 nBytesPerCluster, nClusterDiff, nClusters;
	FF_ERROR	Error;

	if(!pFile) {
		return FF_ERR_NULL_POINTER;
	}

	if(!(pFile->Mode & FF_MODE_WRITE)) {
		return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE;
	}

	// Make sure a write is after the append point.
	if((pFile->Mode & FF_MODE_APPEND)) {
		if(pFile->FilePointer < pFile->Filesize) {
			FF_Seek(pFile, 0, FF_SEEK_END);
		}
	}

	pIoman = pFile->pIoman;

	nBytesPerCluster = (pIoman->pPartition->SectorsPerCluster * pIoman->BlkSize);

	// Extend File for atleast nBytes!
	// Handle file-space allocation
	Error = FF_ExtendFile(pFile, pFile->FilePointer + nBytes);

	if(Error) {
		return Error;	
	}

	nRelBlockPos = FF_getMinorBlockEntry(pIoman, pFile->FilePointer, 1); // Get the position within a block.
	
	nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
	if(nClusterDiff) {
		if(pFile->CurrentCluster != FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
			pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
			pFile->CurrentCluster += nClusterDiff;
		}
	}
	
	nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
	nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);

	if((nRelBlockPos + nBytes) < pIoman->BlkSize) {	// Bytes to read are within a block and less than a block size.
		pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE);
		{
			memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytes);
		}
		FF_ReleaseBuffer(pIoman, pBuffer);

		pFile->FilePointer += nBytes;
		nBytesWritten = nBytes;
		//return nBytes;		// Return the number of bytes read.

	} else {

		//---------- Write (memcpy) to a Sector Boundary
		if(nRelBlockPos != 0) {	// Not on a sector boundary, at this point the LBA is known.
			nBytesToWrite = pIoman->BlkSize - nRelBlockPos;
			pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE);
			{
				// Here we copy to the sector boudary.
				memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytesToWrite);
			}
			FF_ReleaseBuffer(pIoman, pBuffer);

			nBytes				-= nBytesToWrite;
			nBytesWritten		+= nBytesToWrite;
			pFile->FilePointer	+= nBytesToWrite;
			buffer				+= nBytesToWrite;
		}

		//---------- Write to a Cluster Boundary
		
		nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1);
		if(nRelClusterPos != 0 && nBytes >= nBytesPerCluster) { // Need to get to cluster boundary
			
			nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
			if(nClusterDiff) {
				if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
					pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
					pFile->CurrentCluster += nClusterDiff;
				}
			}
		
			nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
			nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);

			sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize));
			
			do {
				if(pIoman->pBlkDevice->fnWriteBlocks) {
#ifdef	FF_BLKDEV_USES_SEM
					FF_PendSemaphore(pFile->pIoman->pSemaphore);
#endif
					RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam);
#ifdef	FF_BLKDEV_USES_SEM
					FF_ReleaseSemaphore(pFile->pIoman->pSemaphore);
#endif
				}
				if(RetVal == FF_ERR_DRIVER_BUSY) {
					FF_Yield();
					FF_Sleep(FF_DRIVER_BUSY_SLEEP);
				}
			}while(RetVal == FF_ERR_DRIVER_BUSY);
			
			nBytesToWrite		 = sSectors * pIoman->BlkSize;
			nBytes				-= nBytesToWrite;
			buffer				+= nBytesToWrite;
			nBytesWritten		+= nBytesToWrite;
			pFile->FilePointer	+= nBytesToWrite;

		}

		//---------- Write Clusters
		if(nBytes >= nBytesPerCluster) {
			//----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check.
			nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
			if(nClusterDiff) {
				if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
					pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
					pFile->CurrentCluster += nClusterDiff;
				}
			}
			//----- End of Contributor fix.

			nClusters = (nBytes / nBytesPerCluster);
			
			FF_WriteClusters(pFile, nClusters, buffer);
			
			nBytesToWrite = (nBytesPerCluster *  nClusters);
			
			pFile->FilePointer	+= nBytesToWrite;

			nBytes				-= nBytesToWrite;
			buffer				+= nBytesToWrite;
			nBytesWritten		+= nBytesToWrite;
		}

		//---------- Write Remaining Blocks
		if(nBytes >= pIoman->BlkSize) {
			sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize);
			
			nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
			if(nClusterDiff) {
				if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
					pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
					pFile->CurrentCluster += nClusterDiff;
				}
			}			
			
			nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
			nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
			
			do {
				if(pIoman->pBlkDevice->fnWriteBlocks) {
#ifdef	FF_BLKDEV_USES_SEM
					FF_PendSemaphore(pFile->pIoman->pSemaphore);
#endif
					RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam);
#ifdef	FF_BLKDEV_USES_SEM
					FF_ReleaseSemaphore(pFile->pIoman->pSemaphore);
#endif
				}
				if(RetVal == FF_ERR_DRIVER_BUSY) {
					FF_Yield();
					FF_Sleep(FF_DRIVER_BUSY_SLEEP);
				}
			}while(RetVal == FF_ERR_DRIVER_BUSY);
			
			nBytesToWrite = sSectors * pIoman->BlkSize;
			pFile->FilePointer	+= nBytesToWrite;
			nBytes				-= nBytesToWrite;
			buffer				+= nBytesToWrite;
			nBytesWritten		+= nBytesToWrite;

		}

		//---------- Write (memcpy) Remaining Bytes
		if(nBytes > 0) {
			
			nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
			if(nClusterDiff) {
				if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
					pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
					pFile->CurrentCluster += nClusterDiff;
				}
			}
			
			nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
			nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
			pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE);
			{
				memcpy(pBuffer->pBuffer, buffer, nBytes);
			}
			FF_ReleaseBuffer(pIoman, pBuffer);

			nBytesToWrite = nBytes;
			pFile->FilePointer	+= nBytesToWrite;
			nBytes				-= nBytesToWrite;
			buffer				+= nBytesToWrite;
			nBytesWritten			+= nBytesToWrite;

		}
	}

	if(pFile->FilePointer > pFile->Filesize) {
		pFile->Filesize = pFile->FilePointer;
	}

	return nBytesWritten;
}
Beispiel #23
0
FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT8 Mode, FF_ERROR *pError) {
#else
FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError) {
#endif
	FF_FILE		*pFile;
	FF_FILE		*pFileChain;
	FF_DIRENT	Object;
	FF_T_UINT32 DirCluster, FileCluster;
	FF_T_UINT32	nBytesPerCluster;
#ifdef FF_UNICODE_SUPPORT
	FF_T_WCHAR	filename[FF_MAX_FILENAME];
#else
	FF_T_INT8	filename[FF_MAX_FILENAME];
#endif
	FF_ERROR	Error;

	FF_T_UINT16	i;

	if(pError) {
		*pError = 0;
	}
	
	if(!pIoman) {
		if(pError) {
			*pError = FF_ERR_NULL_POINTER;
		}
		return (FF_FILE *)NULL;
	}
	pFile = FF_MALLOC(sizeof(FF_FILE));
	if(!pFile) {
		if(pError) {
			*pError = FF_ERR_NOT_ENOUGH_MEMORY;
		}
		return (FF_FILE *)NULL;
	}

	// Get the Mode Bits.
	pFile->Mode = Mode;

#ifdef FF_UNICODE_SUPPORT
	i = (FF_T_UINT16) wcslen(path);
#else 
	i = (FF_T_UINT16) strlen(path);
#endif

	while(i != 0) {
		if(path[i] == '\\' || path[i] == '/') {
			break;
		}
		i--;
	}
#ifdef FF_UNICODE_SUPPORT
	wcsncpy(filename, (path + i + 1), FF_MAX_FILENAME);
#else
	strncpy(filename, (path + i + 1), FF_MAX_FILENAME);
#endif

	if(i == 0) {
		i = 1;
	}
	

	DirCluster = FF_FindDir(pIoman, path, i, &Error);
	if(Error) {
		if(pError) {
			*pError = Error;
		}
		FF_FREE(pFile);
		return (FF_FILE *) NULL;
	}

	if(DirCluster) {

		FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object, &Error);
		if(Error) {
			if(pError) {
				*pError = Error;	
			}
			FF_FREE(pFile);
			return (FF_FILE *) NULL;
		}

		if(!FileCluster) {	// If 0 was returned, it might be because the file has no allocated cluster
#ifdef FF_UNICODE_SUPPORT
			if(wcslen(filename) == wcslen(Object.FileName)) {
				if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) wcslen(filename)) == FF_TRUE) {
#else
			if(strlen(filename) == strlen(Object.FileName)) {
				if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) strlen(filename)) == FF_TRUE) {
#endif
					// The file really was found!
					FileCluster = 1;
				} 
			}
		}

		if(!FileCluster) {
			if((pFile->Mode & FF_MODE_CREATE)) {
				FileCluster = FF_CreateFile(pIoman, DirCluster, filename, &Object, &Error);
				if(Error) {
					if(pError) {
						*pError = Error;
					}
					FF_FREE(pFile);
					return (FF_FILE *) NULL;
				}
				Object.CurrentItem += 1;
			}
		}
		
		if(FileCluster) {
			if(Object.Attrib == FF_FAT_ATTR_DIR) {
				if(!(pFile->Mode & FF_MODE_DIR)) {
					// Not the object, File Not Found!
					FF_FREE(pFile);
					if(pError) {
						*pError = FF_ERR_FILE_OBJECT_IS_A_DIR;
					}
					return (FF_FILE *) NULL;
				}
			}
			
			//---------- Ensure Read-Only files don't get opened for Writing.
			if((pFile->Mode & FF_MODE_WRITE) || (pFile->Mode & FF_MODE_APPEND)) {
				if((Object.Attrib & FF_FAT_ATTR_READONLY)) {
					FF_FREE(pFile);
					if(pError) {
						*pError = FF_ERR_FILE_IS_READ_ONLY;
					}
					return (FF_FILE *) NULL;
				}
			}
			pFile->pIoman				= pIoman;
			pFile->FilePointer			= 0;
			pFile->ObjectCluster		= Object.ObjectCluster;
			pFile->Filesize				= Object.Filesize;
			pFile->CurrentCluster		= 0;
			pFile->AddrCurrentCluster	= pFile->ObjectCluster;
			//pFile->Mode					= Mode;
			pFile->Next					= NULL;
			pFile->DirCluster			= DirCluster;
			pFile->DirEntry				= Object.CurrentItem - 1;
			nBytesPerCluster			= pFile->pIoman->pPartition->SectorsPerCluster / pIoman->BlkSize;
			pFile->iChainLength			= 0;
			pFile->iEndOfChain			= 0;
			pFile->FileDeleted			= FF_FALSE;

			// File Permission Processing
			// Only "w" and "w+" mode strings can erase a file's contents.
			// Any other combinations will not cause an erase.
			if((pFile->Mode & FF_MODE_TRUNCATE)) {
				pFile->Filesize = 0;
				pFile->FilePointer = 0;
			}

			/*
				Add pFile onto the end of our linked list of FF_FILE objects.
			*/
			FF_PendSemaphore(pIoman->pSemaphore);
			{
				if(!pIoman->FirstFile) {
					pIoman->FirstFile = pFile;
				} else {
					pFileChain = (FF_FILE *) pIoman->FirstFile;
					do {
						if(pFileChain->ObjectCluster == pFile->ObjectCluster) {
							// File is already open! DON'T ALLOW IT!
							FF_ReleaseSemaphore(pIoman->pSemaphore);
							FF_FREE(pFile);
							if(pError) {
								*pError = FF_ERR_FILE_ALREADY_OPEN;
							}
							return (FF_FILE *) NULL;
						}
						if(!pFileChain->Next) {
							pFileChain->Next = pFile;
							break;
						}
						pFileChain = (FF_FILE *) pFileChain->Next;
					}while(pFileChain != NULL);
				}
			}
			FF_ReleaseSemaphore(pIoman->pSemaphore);

			return pFile;
		}else {
			FF_FREE(pFile);
			if(pError) {
				*pError = FF_ERR_FILE_NOT_FOUND;
			}
			return (FF_FILE *) NULL;
		} 
	}
	if(pError) {
		*pError = FF_ERR_FILE_INVALID_PATH;
	}

	FF_FREE(pFile);

	return (FF_FILE *)NULL;
}


/**
 *	@public
 *	@brief	Tests if a Directory contains any other files or folders.
 *
 *	@param	pIoman	FF_IOMAN object returned from the FF_CreateIOMAN() function.
 *
 **/
#ifdef FF_UNICODE_SUPPORT
FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_WCHAR *Path) {
#else
FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_INT8 *Path) {
#endif
	
	FF_DIRENT	MyDir;
	FF_ERROR	RetVal = FF_ERR_NONE;
	FF_T_UINT8	i = 0;

	if(!pIoman) {
		return FF_FALSE;
	}
	
	RetVal = FF_FindFirst(pIoman, &MyDir, Path);
	while(RetVal == 0) {
		i++;
		RetVal = FF_FindNext(pIoman, &MyDir);
		if(i > 2) {
			return FF_FALSE;
		}
	}

	return FF_TRUE;
}

#ifdef FF_UNICODE_SUPPORT
FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_WCHAR *path) {
#else
FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) {
#endif
	FF_FILE 			*pFile;
	FF_ERROR 			Error = FF_ERR_NONE;
	FF_T_UINT8 			EntryBuffer[32];
	FF_FETCH_CONTEXT	FetchContext;
	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);
			{
				Error = FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0);	// 0 to delete the entire chain!
			}
			FF_unlockFAT(pIoman);

			if(Error) {
				FF_unlockDIR(pIoman);
				FF_Close(pFile);
				return Error;				
			}

			// Initialise the dirent Fetch Context object for faster removal of dirents.

			Error = FF_InitEntryFetch(pIoman, pFile->DirCluster, &FetchContext);
			if(Error) {
				FF_unlockDIR(pIoman);
				FF_Close(pFile);
				return Error;
			}
			
			// Edit the Directory Entry! (So it appears as deleted);
			Error = FF_RmLFNs(pIoman, pFile->DirEntry, &FetchContext);
			if(Error) {
				FF_CleanupEntryFetch(pIoman, &FetchContext);
				FF_unlockDIR(pIoman);
				FF_Close(pFile);
				return Error;
			}
			Error = FF_FetchEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer);
			if(Error) {
				FF_CleanupEntryFetch(pIoman, &FetchContext);
				FF_unlockDIR(pIoman);
				FF_Close(pFile);
				return Error;
			}
			EntryBuffer[0] = 0xE5;
			Error = FF_PushEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer);
			if(Error) {
				FF_CleanupEntryFetch(pIoman, &FetchContext);
				FF_unlockDIR(pIoman);
				FF_Close(pFile);
				return Error;
			}
#ifdef FF_PATH_CACHE
			FF_PendSemaphore(pIoman->pSemaphore);	// Thread safety on shared object!
			{
				for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) {
#ifdef FF_UNICODE_SUPPORT
					if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)wcslen(path))) {
#else
					if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)strlen(path))) {
#endif
						pIoman->pPartition->PathCache[i].Path[0] = '\0';
						pIoman->pPartition->PathCache[i].DirCluster = 0;
						FF_ReleaseSemaphore(pIoman->pSemaphore);
					}
				}
			}
			FF_ReleaseSemaphore(pIoman->pSemaphore);
#endif
			
			Error = FF_IncreaseFreeClusters(pIoman, pFile->iChainLength);
			if(Error) {
				FF_CleanupEntryFetch(pIoman, &FetchContext);
				FF_unlockDIR(pIoman);
				FF_Close(pFile);
				return Error;
			}

			FF_CleanupEntryFetch(pIoman, &FetchContext);

			Error = FF_FlushCache(pIoman);
			if(Error) {
				FF_unlockDIR(pIoman);
				FF_Close(pFile);
				return Error;
			}
		} else {
			RetVal = FF_ERR_DIR_NOT_EMPTY;
		}
	}
	FF_unlockDIR(pIoman);
	Error = FF_Close(pFile); // Free the file pointer resources

	if(Error) {
		return Error;
	}

	// File is now lost!
	return RetVal;
}