PageRenderTime 216ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/MicroFrameworkPK_v4_1/DeviceCode/Drivers/FS/FAT/FAT_FileHandle.cpp

https://bitbucket.org/pmfsampaio/netmf-lpc
C++ | 454 lines | 310 code | 116 blank | 28 comment | 77 complexity | 0040e8251017b572e06c5afc51ddde74 MD5 | raw file
  1. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4. #include "tinyhal.h"
  5. #include "FAT_FS.h"
  6. #include "FAT_FS_Utility.h"
  7. #include "TinyCLR_Interop.h"
  8. //--//
  9. FAT_FileHandle* FAT_FileHandle::Open( FAT_LogicDisk* logicDisk, FAT_FILE* fileInfo, UINT32 clusIndex )
  10. {
  11. FAT_FileHandle* fileHandle = (FAT_FileHandle*)FAT_MemoryManager::AllocateHandle();
  12. if(!fileHandle) return NULL;
  13. fileHandle->m_logicDisk = logicDisk;
  14. fileHandle->m_clusIndex = clusIndex;
  15. fileHandle->m_sectIndex = logicDisk->ClusToSect( clusIndex );
  16. fileHandle->m_dataIndex = 0;
  17. fileHandle->m_position = 0;
  18. fileHandle->m_readWriteState = ReadWriteState__NONE;
  19. memcpy( &fileHandle->m_file, fileInfo, sizeof(FAT_FILE) );
  20. return fileHandle;
  21. }
  22. HRESULT FAT_FileHandle::Close()
  23. {
  24. FAT_Directory* dirEntry = m_file.GetDirectoryEntry();
  25. if (dirEntry && m_readWriteState != ReadWriteState__NONE)
  26. {
  27. UINT16 date, time;
  28. BOOL markedForWrite = FALSE;
  29. FAT_Utility::GetCurrentFATTime( &date, &time, NULL );
  30. if(dirEntry->Get_DIR_LstAccDate() != date)
  31. {
  32. m_file.MarkDirectoryEntryForWrite();
  33. markedForWrite = TRUE;
  34. dirEntry->Set_DIR_LstAccDate( date );
  35. }
  36. if((m_readWriteState & ReadWriteState__WRITE) == ReadWriteState__WRITE)
  37. {
  38. if(!markedForWrite) m_file.MarkDirectoryEntryForWrite();
  39. dirEntry->Set_DIR_WrtDate ( date );
  40. dirEntry->Set_DIR_WrtTime ( time );
  41. }
  42. }
  43. Flush();
  44. FAT_MemoryManager::FreeHandle( this );
  45. return S_OK;
  46. }
  47. HRESULT FAT_FileHandle::ReadWriteSeekHelper( int type, BYTE* buffer, int size, int* bytesDone )
  48. {
  49. TINYCLR_HEADER();
  50. BYTE* sector;
  51. BYTE getNextSectFlag = (type == Helper_Write) ? FAT_LogicDisk::GetNextSect__CREATE : FAT_LogicDisk::GetNextSect__NONE;
  52. int done = 0;
  53. UINT32 sectorSize = m_logicDisk->m_bytesPerSector;
  54. while(size > 0)
  55. {
  56. if(m_dataIndex == sectorSize) // if we are at the end of a sector, page in the next sector
  57. {
  58. TINYCLR_CHECK_HRESULT(m_logicDisk->GetNextSect( &m_clusIndex, &m_sectIndex, getNextSectFlag ));
  59. m_dataIndex = 0;
  60. }
  61. //get data size can be read in current sector
  62. size_t count = sectorSize - m_dataIndex;
  63. // Adjust if we only need a portion of it
  64. if(size < count) count = size;
  65. if(type != Helper_Seek)
  66. {
  67. sector = m_logicDisk->SectorCache.GetSector( m_sectIndex, (type == Helper_Write) ? TRUE : FALSE );
  68. if(!sector) TINYCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
  69. if(type == Helper_Read)
  70. {
  71. memcpy( buffer, &(sector[m_dataIndex]), count );
  72. }
  73. else // type == Helper_Write
  74. {
  75. if(buffer)
  76. {
  77. memcpy( &(sector[m_dataIndex]), buffer, count );
  78. }
  79. else
  80. {
  81. memset( &(sector[m_dataIndex]), 0, count );
  82. }
  83. }
  84. // adjust counters
  85. if(buffer) buffer += count;
  86. /********/ done += count;
  87. }
  88. // adjust counters
  89. m_dataIndex += count;
  90. m_position += count;
  91. size -= count;
  92. }
  93. if (bytesDone) *bytesDone = done;
  94. TINYCLR_NOCLEANUP();
  95. }
  96. HRESULT FAT_FileHandle::Read( BYTE* buffer, int size, int* bytesRead )
  97. {
  98. TINYCLR_HEADER();
  99. FAT_Directory* dirEntry;
  100. int limit;
  101. UINT32 dirFileSize;
  102. if(!buffer || size < 0 || !bytesRead)
  103. {
  104. TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
  105. }
  106. dirEntry = m_file.GetDirectoryEntry();
  107. if(!dirEntry) TINYCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
  108. // If there's another handle that's modifying the filesize, make sure m_position is valid
  109. dirFileSize = dirEntry->Get_DIR_FileSize();
  110. if(m_position > dirFileSize )
  111. {
  112. m_position = dirFileSize ;
  113. }
  114. limit = dirFileSize - m_position;
  115. if(limit == 0)
  116. {
  117. // returns -1 to signify the end of the file
  118. *bytesRead = -1;
  119. TINYCLR_SET_AND_LEAVE(S_OK);
  120. }
  121. //if size to read is larger than limit, set it to limit
  122. if(size > limit)
  123. {
  124. size = limit;
  125. }
  126. // set the cluster information if it wasn't previously available
  127. if(m_clusIndex == 0)
  128. {
  129. m_position = 0;
  130. m_clusIndex = dirEntry->GetFstClus();
  131. m_sectIndex = m_logicDisk->ClusToSect( m_clusIndex );
  132. m_dataIndex = 0;
  133. }
  134. TINYCLR_CHECK_HRESULT(ReadWriteSeekHelper( Helper_Read, buffer, size, bytesRead ));
  135. m_readWriteState |= ReadWriteState__READ;
  136. UINT16 date,time;
  137. UINT8 timeTenth;
  138. FAT_Utility::GetCurrentFATTime( &date, &time, &timeTenth );
  139. dirEntry->Set_DIR_LstAccDate(date);
  140. TINYCLR_NOCLEANUP();
  141. }
  142. HRESULT FAT_FileHandle::Write( BYTE* buffer, int size, int* bytesWritten )
  143. {
  144. TINYCLR_HEADER();
  145. FAT_Directory* dirEntry;
  146. if(size < 0) TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
  147. dirEntry = m_file.GetDirectoryEntry();
  148. if(!dirEntry) TINYCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
  149. //haven't allocate any cluster for this file
  150. if(dirEntry->GetFstClus() == 0)
  151. {
  152. UINT32 nextFreeClus = m_logicDisk->GetNextFreeClus( FALSE );
  153. if(nextFreeClus == CLUST_ERROR) TINYCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
  154. // GetNextFreeClus() might invalidate dirEntry
  155. dirEntry = m_file.GetDirectoryEntry( TRUE );
  156. if(!dirEntry) TINYCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
  157. dirEntry->SetFstClus( nextFreeClus );
  158. //update FAT table
  159. m_logicDisk->WriteFAT( nextFreeClus, CLUST_EOF );
  160. m_position = 0;
  161. m_clusIndex = nextFreeClus;
  162. m_sectIndex = m_logicDisk->ClusToSect( m_clusIndex );
  163. m_dataIndex = 0;
  164. }
  165. else if(m_clusIndex == 0) // set the cluster information if it wasn't previously available
  166. {
  167. m_position = 0;
  168. m_clusIndex = dirEntry->GetFstClus();
  169. m_sectIndex = m_logicDisk->ClusToSect( m_clusIndex );
  170. m_dataIndex = 0;
  171. }
  172. TINYCLR_CHECK_HRESULT(ReadWriteSeekHelper( Helper_Write, buffer, size, bytesWritten ));
  173. // Need to refresh directory entry, as the sector may be paged out by ReadWriteSeekHelper()
  174. dirEntry = m_file.GetDirectoryEntry();
  175. if(!dirEntry) TINYCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
  176. //if file is resized
  177. if(dirEntry->Get_DIR_FileSize() < m_position)
  178. {
  179. m_file.MarkDirectoryEntryForWrite();
  180. dirEntry->Set_DIR_FileSize((UINT32)m_position);
  181. }
  182. //set file write flag
  183. m_readWriteState |= ReadWriteState__WRITE;
  184. UINT16 date,time;
  185. UINT8 timeTenth;
  186. FAT_Utility::GetCurrentFATTime( &date, &time, &timeTenth );
  187. dirEntry->Set_DIR_WrtDate ( date );
  188. dirEntry->Set_DIR_WrtTime ( time );
  189. dirEntry->Set_DIR_LstAccDate(date);
  190. TINYCLR_NOCLEANUP();
  191. }
  192. HRESULT FAT_FileHandle::Flush()
  193. {
  194. m_logicDisk->SectorCache.FlushAll();
  195. return S_OK;
  196. }
  197. HRESULT FAT_FileHandle::Seek( INT64 offset, UINT32 origin, INT64* position )
  198. {
  199. TINYCLR_HEADER();
  200. FAT_Directory* dirEntry = m_file.GetDirectoryEntry();
  201. UINT32 dirFileSize = dirEntry->Get_DIR_FileSize();
  202. if(!dirEntry) TINYCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
  203. // If there's another handle that's modifying the filesize, make sure m_position is valid
  204. if(m_position > dirFileSize)
  205. {
  206. m_position = dirFileSize;
  207. }
  208. INT64 newPosition;
  209. switch(origin)
  210. {
  211. case SEEKORIGIN_BEGIN:
  212. newPosition = offset;
  213. break;
  214. case SEEKORIGIN_CURRENT:
  215. newPosition = m_position + offset;
  216. break;
  217. case SEEKORIGIN_END:
  218. newPosition = dirFileSize + offset;
  219. break;
  220. default:
  221. TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
  222. }
  223. //if position exceeds the file size, extends the file
  224. if(newPosition > dirFileSize)
  225. {
  226. TINYCLR_CHECK_HRESULT(SetLength( newPosition ));
  227. }
  228. else if(newPosition < 0) //if position < 0, return ERROR
  229. {
  230. TINYCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
  231. }
  232. // Get the offset relative to the current position
  233. offset = newPosition - m_position;
  234. // If we are going backwards, we have to start from the beginning
  235. if(offset < 0)
  236. {
  237. if (m_dataIndex >= (-1 * offset)) // Unless we're still staying in the same cluster
  238. {
  239. m_dataIndex += offset; // offset is < 0
  240. m_position += offset; // offset is < 0
  241. if(position) *position = m_position;
  242. TINYCLR_SET_AND_LEAVE(S_OK);
  243. }
  244. m_clusIndex = dirEntry->GetFstClus();
  245. m_sectIndex = m_logicDisk->ClusToSect( m_clusIndex );
  246. m_dataIndex = 0;
  247. m_position = 0;
  248. offset = newPosition;
  249. }
  250. TINYCLR_CHECK_HRESULT(ReadWriteSeekHelper( Helper_Seek, NULL, offset, NULL ));
  251. if(position) *position = m_position;
  252. TINYCLR_NOCLEANUP();
  253. }
  254. HRESULT FAT_FileHandle::GetLength( INT64* length )
  255. {
  256. if (!length)
  257. {
  258. return CLR_E_INVALID_PARAMETER;
  259. }
  260. FAT_Directory* dirEntry = m_file.GetDirectoryEntry();
  261. if(!dirEntry) return CLR_E_FILE_IO;
  262. *length = dirEntry->Get_DIR_FileSize();
  263. return S_OK;
  264. }
  265. HRESULT FAT_FileHandle::SetLength( INT64 length )
  266. {
  267. TINYCLR_HEADER();
  268. FAT_Directory* dirEntry;
  269. UINT32 length32;
  270. UINT32 startClus;
  271. UINT32 dirFileSize;
  272. if(length < 0 || length > 0xFFFFFFFF )
  273. {
  274. TINYCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE);
  275. }
  276. dirEntry = m_file.GetDirectoryEntry();
  277. if(!dirEntry) TINYCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
  278. length32 = (UINT32)length;
  279. startClus = dirEntry->GetFstClus();
  280. dirFileSize = dirEntry->Get_DIR_FileSize();
  281. if((length32 == dirFileSize) ||
  282. (length32 == 0 && startClus == 0))
  283. {
  284. TINYCLR_SET_AND_LEAVE(S_OK);
  285. }
  286. // Shrinking
  287. if(length32 <= dirFileSize)
  288. {
  289. UINT32 clusterSize = m_logicDisk->m_bytesPerSector * m_logicDisk->m_sectorsPerCluster;
  290. UINT32 oldClusCount = (dirFileSize + clusterSize - 1) / clusterSize;
  291. UINT32 newClusCount = (length32 + clusterSize - 1) / clusterSize;
  292. UINT32 clus = startClus;
  293. UINT32 clusNum = 0;
  294. //--//
  295. while(clusNum++ < oldClusCount)
  296. {
  297. //write cluster end flag
  298. if(clusNum == newClusCount)
  299. {
  300. clus = m_logicDisk->WriteFAT( clus, CLUST_EOF );
  301. }
  302. else if(clusNum > newClusCount) //free next cluster
  303. {
  304. clus = m_logicDisk->WriteFAT( clus, CLUST_NONE );
  305. }
  306. //check data cluster legal
  307. if(m_logicDisk->GetClusType( clus ) != CLUSTYPE_DATA)
  308. break;
  309. }
  310. if(length <= m_position)
  311. {
  312. TINYCLR_CHECK_HRESULT(Seek( length, SEEKORIGIN_BEGIN, NULL ));
  313. }
  314. // Update the Directory entry, (need to reload in case WriteFAT page out the sector)
  315. dirEntry = m_file.GetDirectoryEntry( TRUE );
  316. if (!dirEntry) TINYCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
  317. dirEntry->Set_DIR_FileSize((UINT32) length32 );
  318. if(length32 == 0)
  319. {
  320. dirEntry->SetFstClus( 0 );
  321. m_logicDisk->WriteFAT( startClus, CLUST_NONE );
  322. }
  323. }
  324. else //growing
  325. {
  326. //return fail if there isn't enough space left
  327. if(length32 - dirFileSize > m_logicDisk->GetDiskFreeSize())
  328. {
  329. TINYCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
  330. }
  331. INT64 oldPosition = m_position;
  332. INT64 endPosition;
  333. TINYCLR_CHECK_HRESULT(Seek( 0, SEEKORIGIN_END, &endPosition ));
  334. TINYCLR_CHECK_HRESULT(Write( NULL, length - endPosition, NULL ));
  335. TINYCLR_CHECK_HRESULT(Seek( oldPosition, SEEKORIGIN_BEGIN, NULL ));
  336. }
  337. TINYCLR_NOCLEANUP();
  338. }