Esempio n. 1
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;
}
Esempio n. 2
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;
}
Esempio n. 3
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;
}
Esempio n. 4
0
static FF_ERROR FF_WriteClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) {
	FF_T_UINT32 ulSectors;
	FF_T_UINT32 SequentialClusters = 0;
	FF_T_UINT32 nItemLBA;
	FF_T_SINT32 slRetVal;
	FF_ERROR	Error;

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

		slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, ulSectors, buffer);

		if(slRetVal < 0) {
			return slRetVal;
		}
		
		Count -= (SequentialClusters + 1);
		pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1), &Error);
		if(Error) {
			return Error;
		}
		pFile->CurrentCluster += (SequentialClusters + 1);
		buffer += ulSectors * pFile->pIoman->BlkSize;
		SequentialClusters = 0;
	}

	return 0;
}
Esempio n. 5
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!
}
Esempio n. 6
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!
}
Esempio n. 7
0
FF_ERROR FF_FormatPartition(FF_IOMAN *pIoman, FF_T_UINT32 ulPartitionNumber, FF_T_UINT32 ulClusterSize) {

	FF_BUFFER *pBuffer;
  	FF_T_SINT8	scPartitionCount;
	FF_T_UINT32 maxClusters, f16MaxClusters, f32MaxClusters;
	FF_T_UINT32 fatSize = 32; // Default to a fat32 format.

	FF_PARTITION_ENTRY partitionGeom;

	FF_T_UINT32 ulBPRLba; ///< The LBA of the boot partition record.

	FF_T_UINT32 fat32Size, fat16Size, newFat32Size, newFat16Size, finalFatSize;
	FF_T_UINT32 sectorsPerCluster = ulClusterSize / pIoman->BlkSize;

	FF_T_UINT32 ulReservedSectors, ulTotalSectors;

	FF_T_UINT32 ul32DataSectors, ul16DataSectors;
	FF_T_UINT32 i;

	FF_T_UINT32 ulClusterBeginLBA;

	FF_ERROR	Error = FF_ERR_NONE;

	// Get Partition Metrics, and pass on to FF_Format() function

	pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_READ);
	{
		if(!pBuffer) {
			return FF_ERR_DEVICE_DRIVER_FAILED | FF_FORMATPARTITION;
		}


		scPartitionCount = FF_PartitionCount(pBuffer->pBuffer);

		if(!scPartitionCount) {
			// Get Partition Geom from volume boot record.
			ulBPRLba = 0;
			partitionGeom.ulStartLBA = FF_getShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS); // Get offset to start of where we can actually put the FAT table.
			ulReservedSectors = partitionGeom.ulStartLBA;
			partitionGeom.ulLength = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS);

			if(partitionGeom.ulLength == 0) { // 32-bit entry was used.
				partitionGeom.ulLength = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS);
			}

			ulTotalSectors = partitionGeom.ulLength;

			partitionGeom.ulLength -= partitionGeom.ulStartLBA; // Remove the reserved sectors from the count.

		} else {
			// Get partition Geom from the partition table entry.

		}

		// Calculate the max possiblenumber of clusters based on clustersize.
		maxClusters = partitionGeom.ulLength / sectorsPerCluster;

		// Determine the size of a FAT table required to support this.
		fat32Size = (maxClusters * 4) / pIoman->BlkSize; // Potential size in sectors of a fat32 table.
		if((maxClusters * 4) % pIoman->BlkSize) {
			fat32Size++;
		}
		fat32Size *= 2;	// Officially there are 2 copies of the FAT.

		fat16Size = (maxClusters * 2) / pIoman->BlkSize; // Potential size in bytes of a fat16 table.
		if((maxClusters * 2) % pIoman->BlkSize) {
			fat16Size++;
		}
		fat16Size *= 2;

		// A real number of sectors to be available is therefore ~~
		ul16DataSectors = partitionGeom.ulLength - fat16Size;
		ul32DataSectors = partitionGeom.ulLength - fat32Size;

		f16MaxClusters = ul16DataSectors / sectorsPerCluster;
		f32MaxClusters = ul32DataSectors / sectorsPerCluster;

		newFat16Size = (f16MaxClusters * 2) / pIoman->BlkSize;
		if((f16MaxClusters * 2) % pIoman->BlkSize) {
			newFat16Size++;
		}

		newFat32Size = (f32MaxClusters * 4) / pIoman->BlkSize;
		if((f32MaxClusters * 4) % pIoman->BlkSize) {
			newFat32Size++;
		}

		// Now determine if this should be fat16/32 format?

		if(f16MaxClusters < 65525) {
			fatSize = 16;
			finalFatSize = newFat16Size;
		} else {
			fatSize = 32;
			finalFatSize = newFat32Size;
		}

		FF_ReleaseBuffer(pIoman, pBuffer);
		for(i = 0; i < finalFatSize*2; i++) { // Ensure the FAT table is clear.
			if(i == 0) {
				pBuffer = FF_GetBuffer(pIoman, partitionGeom.ulStartLBA, FF_MODE_WR_ONLY);
				if(!pBuffer) {
					return FF_ERR_DEVICE_DRIVER_FAILED;
				}

				memset(pBuffer->pBuffer, 0, pIoman->BlkSize);
			} else {
				FF_BlockWrite(pIoman, partitionGeom.ulStartLBA+i, 1, pBuffer->pBuffer, FF_FALSE);
			}
		}

		switch(fatSize) {
		case 16: {
			FF_putShort(pBuffer->pBuffer, 0, 0xFFF8); // First FAT entry.
			FF_putShort(pBuffer->pBuffer, 2, 0xFFFF); // RESERVED alloc.
			break;
		}

		case 32: {
			FF_putLong(pBuffer->pBuffer, 0, 0x0FFFFFF8); // FAT32 FAT sig.
			FF_putLong(pBuffer->pBuffer, 4, 0xFFFFFFFF); // RESERVED alloc.
			FF_putLong(pBuffer->pBuffer, 8, 0x0FFFFFFF); // Root dir allocation.
			break;
		}

		default:
			break;
		}

		FF_ReleaseBuffer(pIoman, pBuffer);


		// Clear and initialise the root dir.
		ulClusterBeginLBA = partitionGeom.ulStartLBA + (finalFatSize*2);

		for(i = 0; i < sectorsPerCluster; i++) {
			if(i == 0) {
				pBuffer = FF_GetBuffer(pIoman, ulClusterBeginLBA, FF_MODE_WR_ONLY);
				memset(pBuffer->pBuffer, 0, pIoman->BlkSize);
			} else  {
				FF_BlockWrite(pIoman, ulClusterBeginLBA+i, 1, pBuffer->pBuffer, FF_FALSE);
			}

		}

		FF_ReleaseBuffer(pIoman, pBuffer);

		// Correctly modify the second FAT item again.
		pBuffer = FF_GetBuffer(pIoman, partitionGeom.ulStartLBA + finalFatSize, FF_MODE_WRITE);
		{
			switch(fatSize) {
			case 16: {
				FF_putShort(pBuffer->pBuffer, 0, 0xFFF8);
				FF_putShort(pBuffer->pBuffer, 2, 0xFFFF);
				break;
			}
			   
			case 32:
				FF_putLong(pBuffer->pBuffer, 0, 0x0FFFFFF8);
				FF_putLong(pBuffer->pBuffer, 4, 0xFFFFFFFF);
				FF_putLong(pBuffer->pBuffer, 8, 0x0FFFFFFF); // Root dir allocation.
			}
		}
		FF_ReleaseBuffer(pIoman, pBuffer);


		// Modify the fields in the VBR/PBR for correct mounting.
		pBuffer = FF_GetBuffer(pIoman, ulBPRLba, FF_MODE_WRITE); 		// Modify the FAT descriptions.
		{

			// -- First section Common vars to Fat12/16 and 32.
			memset(pBuffer->pBuffer, 0, pIoman->BlkSize); 				// Clear the boot record.

			FF_putChar(pBuffer->pBuffer, 0, 0xEB);						// Place the Jump to bootstrap x86 instruction.
			FF_putChar(pBuffer->pBuffer, 1, 0x3C);						// Even though we won't populate the bootstrap code.
			FF_putChar(pBuffer->pBuffer, 2, 0x90);						// Some devices look for this as a signature.

			memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+3), "FULLFAT2", 8); // Place the FullFAT OEM code.

			FF_putShort(pBuffer->pBuffer, 11, pIoman->BlkSize);
			FF_putChar(pBuffer->pBuffer, 13, (FF_T_UINT8) sectorsPerCluster);

			FF_putShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS, (FF_T_UINT16)partitionGeom.ulStartLBA); 	// Number of reserved sectors. (1 for fat12/16, 32 for f32).
			FF_putShort(pBuffer->pBuffer, FF_FAT_NUMBER_OF_FATS, 2); 	// Always 2 copies.


			//FF_putShort(pBuffer->pBuffer, 19, 0);						// Number of sectors in partition if size < 32mb.

			FF_putChar(pBuffer->pBuffer, 21, 0xF8);             		// Media type -- HDD.
		   

			FF_putShort(pBuffer->pBuffer, 510, 0xAA55);					// MBR sig.
			FF_putLong(pBuffer->pBuffer, 32, partitionGeom.ulLength+partitionGeom.ulStartLBA); // Total sectors of this partition.

			if(fatSize == 32) {
				FF_putShort(pBuffer->pBuffer, 36, (FF_T_UINT16)finalFatSize);		// Number of sectors per fat. 
				FF_putShort(pBuffer->pBuffer, 44, 2);					// Root dir cluster (2).
				FF_putShort(pBuffer->pBuffer, 48, 1);					// FSINFO sector at LBA1.
				FF_putShort(pBuffer->pBuffer, 50, 6);					// 0 for no backup boot sector.
				FF_putChar(pBuffer->pBuffer, 66, 0x29);					// Indicate extended signature is present.
				memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+71), "FullFAT2-V", 10); // Volume name.
				memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+81), "FAT32   ", 8);

				// Put backup boot sector.
				FF_BlockWrite(pIoman, 6, 1, pBuffer->pBuffer, FF_FALSE);
			} else {
				FF_putChar(pBuffer->pBuffer, 38, 0x28);					// Signal this contains an extended signature.
				memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+43), "FullFAT2-V", 10); // Volume name.
				memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+54), "FAT16   ", 8);
				FF_putShort(pBuffer->pBuffer, FF_FAT_16_SECTORS_PER_FAT, (FF_T_UINT16) finalFatSize);
				FF_putShort(pBuffer->pBuffer, 17, 512);				 		// Number of Dir entries. (FAT32 0).
				//FF_putShort(pBuffer->pBuffer, FF_FAT_ROOT_ENTRY_COUNT, 
			}
		}
	}
	FF_ReleaseBuffer(pIoman, pBuffer);

	if(fatSize == 32) {
		// Finally if FAT32, create an FSINFO sector.
		pBuffer = FF_GetBuffer(pIoman, 1, FF_MODE_WRITE);
		{
			memset(pBuffer->pBuffer, 0, pIoman->BlkSize);
			FF_putLong(pBuffer->pBuffer, 0, 0x41615252);	// FSINFO sect magic number.
			FF_putLong(pBuffer->pBuffer, 484, 0x61417272);	// FSINFO second sig.
			// Calculate total sectors, -1 for the root dir allocation. (Free sectors count).
			FF_putLong(pBuffer->pBuffer, 488, ((ulTotalSectors - (ulReservedSectors + (2*finalFatSize))) / sectorsPerCluster)-1);
			FF_putLong(pBuffer->pBuffer, 492, 2);			// Hint for next free cluster.
			FF_putShort(pBuffer->pBuffer, 510, 0xAA55);
		}
		FF_ReleaseBuffer(pIoman, pBuffer);
	}

	FF_FlushCache(pIoman);

	return Error;
}
Esempio n. 8
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	slRetVal = 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, &Error);
			if(Error) {
				return Error;
			}
			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);
		{
			if(!pBuffer) {
				return FF_ERR_DEVICE_DRIVER_FAILED;
			}
			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);
			{
				if(!pBuffer) {
					return FF_ERR_DEVICE_DRIVER_FAILED;
				}
				// 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, &Error);
					if(Error) {
						return Error;
					}
					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));

			slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, sSectors, buffer);
			if(slRetVal < 0) {
				return slRetVal;
			}
			
			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, &Error);
					if(Error) {
						return Error;
					}
					pFile->CurrentCluster += nClusterDiff;
				}
			}
			//----- End of Contributor fix.

			nClusters = (nBytes / nBytesPerCluster);
			
			slRetVal = FF_WriteClusters(pFile, nClusters, buffer);
			if(slRetVal < 0) {
				return slRetVal;
			}
			
			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, &Error);
					if(Error) {
						return Error;
					}
					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);
			
			slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, sSectors, buffer);
			if(slRetVal < 0) {
				return slRetVal;
			}
			
			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, &Error);
					if(Error) {
						return Error;
					}
					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);
			{
				if(!pBuffer) {
					return FF_ERR_DEVICE_DRIVER_FAILED;
				}
				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;
}