Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2041 lines
83 KiB

  1. /*!!*/
  2. /*
  3. * $Log: V:/Flite/archives/TrueFFS5/Src/FATLITE.C_V $
  4. *
  5. * Rev 1.10 Jan 17 2002 23:00:28 oris
  6. * Removed SINGLE_BUFFER ifdef.
  7. * Changed debug print added \r.
  8. * Removed warnings.
  9. *
  10. * Rev 1.9 Nov 16 2001 00:26:46 oris
  11. * Removed warnings.
  12. *
  13. * Rev 1.8 Nov 08 2001 10:45:28 oris
  14. * Removed warnings.
  15. *
  16. * Rev 1.7 May 16 2001 21:17:30 oris
  17. * Added the FL_ prefix to the following defines: ON, OFF
  18. * Change "data" named variables to flData to avoid name clashes.
  19. *
  20. * Rev 1.6 Apr 18 2001 09:31:02 oris
  21. * added new line at the end of the file.
  22. *
  23. * Rev 1.5 Apr 16 2001 10:42:16 vadimk
  24. * Emty file bug was fixed ( we should not allocate cluster for an empty file )
  25. *
  26. * Rev 1.4 Apr 09 2001 15:07:10 oris
  27. * End with an empty line.
  28. *
  29. * Rev 1.3 Apr 03 2001 14:42:02 oris
  30. * Bug fix - 64 sectors in directory return flInvalidFatChain.
  31. *
  32. * Rev 1.2 Apr 01 2001 08:02:46 oris
  33. * copywrite notice.
  34. *
  35. * Rev 1.1 Feb 12 2001 12:16:42 oris
  36. * Changed mutexs for TrueFFS 5.0
  37. *
  38. * Rev 1.0 Feb 04 2001 11:02:28 oris
  39. * Initial revision.
  40. *
  41. */
  42. /***********************************************************************************/
  43. /* M-Systems Confidential */
  44. /* Copyright (C) M-Systems Flash Disk Pioneers Ltd. 1995-2001 */
  45. /* All Rights Reserved */
  46. /***********************************************************************************/
  47. /* NOTICE OF M-SYSTEMS OEM */
  48. /* SOFTWARE LICENSE AGREEMENT */
  49. /* */
  50. /* THE USE OF THIS SOFTWARE IS GOVERNED BY A SEPARATE LICENSE */
  51. /* AGREEMENT BETWEEN THE OEM AND M-SYSTEMS. REFER TO THAT AGREEMENT */
  52. /* FOR THE SPECIFIC TERMS AND CONDITIONS OF USE, */
  53. /* OR CONTACT M-SYSTEMS FOR LICENSE ASSISTANCE: */
  54. /* E-MAIL = [email protected] */
  55. /***********************************************************************************/
  56. #include "bddefs.h"
  57. #include "blockdev.h"
  58. #include "dosformt.h"
  59. #if defined(FILES) && FILES>0
  60. File fileTable[FILES]; /* the file table */
  61. #define directory ((DirectoryEntry *) vol.volBuffer.flData)
  62. FLStatus closeFile(File *file); /* forward */
  63. FLStatus flushBuffer(Volume vol); /* forward */
  64. /*----------------------------------------------------------------------*/
  65. /* d i s m o u n t V o l u m e */
  66. /* */
  67. /* Closing all files. */
  68. /* */
  69. /* Parameters: */
  70. /* vol : Pointer identifying drive */
  71. /* */
  72. /* Returns: */
  73. /* FLStatus : 0 on success, otherwise failed */
  74. /*----------------------------------------------------------------------*/
  75. FLStatus dismountFS(Volume vol,FLStatus status)
  76. {
  77. int i;
  78. #ifndef FL_READ_ONLY
  79. if (status == flOK)
  80. checkStatus(flushBuffer(&vol));
  81. #endif
  82. /* Close or discard all files and make them available */
  83. for (i = 0; i < FILES; i++)
  84. if (fileTable[i].fileVol == &vol)
  85. if (vol.flags & VOLUME_MOUNTED)
  86. closeFile(&fileTable[i]);
  87. else
  88. fileTable[i].flags = 0;
  89. vol.volBuffer.sectorNo = UNASSIGNED_SECTOR; /* Current sector no. (none) */
  90. vol.volBuffer.dirty = vol.volBuffer.checkPoint = FALSE;
  91. return flOK;
  92. }
  93. #ifndef FL_READ_ONLY
  94. /*----------------------------------------------------------------------*/
  95. /* f l u s h B u f f e r */
  96. /* */
  97. /* Writes the buffer contents if it is dirty. */
  98. /* */
  99. /* If this is a FAT sector, all FAT copies are written. */
  100. /* */
  101. /* Parameters: */
  102. /* vol : Pointer identifying drive */
  103. /* */
  104. /* Returns: */
  105. /* FLStatus : 0 on success, otherwise failed */
  106. /*----------------------------------------------------------------------*/
  107. FLStatus flushBuffer(Volume vol)
  108. {
  109. if (vol.volBuffer.dirty) {
  110. FLStatus status;
  111. unsigned i;
  112. Volume *bufferOwner = &vol;
  113. status = (*bufferOwner).tl.writeSector((*bufferOwner).tl.rec, vol.volBuffer.sectorNo,
  114. vol.volBuffer.flData);
  115. if (status == flOK) {
  116. if (vol.volBuffer.sectorNo >= (*bufferOwner).firstFATSectorNo &&
  117. vol.volBuffer.sectorNo < (*bufferOwner).secondFATSectorNo)
  118. for (i = 1; i < (*bufferOwner).numberOfFATS; i++)
  119. checkStatus((*bufferOwner).tl.writeSector((*bufferOwner).tl.rec,
  120. vol.volBuffer.sectorNo + i * (*bufferOwner).sectorsPerFAT,
  121. vol.volBuffer.flData));
  122. }
  123. else
  124. vol.volBuffer.sectorNo = UNASSIGNED_SECTOR;
  125. vol.volBuffer.dirty = vol.volBuffer.checkPoint = FALSE;
  126. return status;
  127. }
  128. else
  129. return flOK;
  130. }
  131. /*----------------------------------------------------------------------*/
  132. /* u p d a t e S e c t o r */
  133. /* */
  134. /* Prepares a sector for update in the buffer */
  135. /* */
  136. /* Parameters: */
  137. /* vol : Pointer identifying drive */
  138. /* sectorNo : Sector no. to read */
  139. /* read : Whether to initialize buffer by reading, or */
  140. /* clearing */
  141. /* */
  142. /* Returns: */
  143. /* FLStatus : 0 on success, otherwise failed */
  144. /*----------------------------------------------------------------------*/
  145. static FLStatus updateSector(Volume vol, SectorNo sectorNo, FLBoolean read)
  146. {
  147. if (sectorNo != vol.volBuffer.sectorNo || &vol != vol.volBuffer.owner) {
  148. const void FAR0 *mappedSector;
  149. checkStatus(flushBuffer(&vol));
  150. vol.volBuffer.sectorNo = sectorNo;
  151. vol.volBuffer.owner = &vol;
  152. if (read) {
  153. mappedSector = vol.tl.mapSector(vol.tl.rec,sectorNo,NULL);
  154. if (mappedSector) {
  155. if(mappedSector==dataErrorToken)
  156. return flDataError;
  157. tffscpy(vol.volBuffer.flData,mappedSector,SECTOR_SIZE);
  158. }
  159. else
  160. return flSectorNotFound;
  161. }
  162. else
  163. tffsset(vol.volBuffer.flData,0,SECTOR_SIZE);
  164. }
  165. vol.volBuffer.dirty = TRUE;
  166. return flOK;
  167. }
  168. #endif /* FL_READ_ONLY */
  169. /*----------------------------------------------------------------------*/
  170. /* f i r s t S e c t o r O f C l u s t e r */
  171. /* */
  172. /* Get sector no. corresponding to cluster no. */
  173. /* */
  174. /* Parameters: */
  175. /* vol : Pointer identifying drive */
  176. /* cluster : Cluster no. */
  177. /* */
  178. /* Returns: */
  179. /* first sector no. of cluster */
  180. /*----------------------------------------------------------------------*/
  181. static SectorNo firstSectorOfCluster(Volume vol, unsigned cluster)
  182. {
  183. return (SectorNo) (cluster - 2) * vol.sectorsPerCluster +
  184. vol.firstDataSectorNo;
  185. }
  186. /*----------------------------------------------------------------------*/
  187. /* g e t D i r E n t r y */
  188. /* */
  189. /* Get a read-only copy of a directory entry. */
  190. /* */
  191. /* Parameters: */
  192. /* vol : Pointer identifying drive */
  193. /* file : File belonging to directory entry */
  194. /* */
  195. /* Returns: */
  196. /* dirEntry : Pointer to directory entry */
  197. /*----------------------------------------------------------------------*/
  198. static const DirectoryEntry FAR0 *getDirEntry(File *file)
  199. {
  200. return (DirectoryEntry FAR0 *) findSector(file->fileVol,file->directorySector) +
  201. file->directoryIndex;
  202. }
  203. #ifndef FL_READ_ONLY
  204. /*----------------------------------------------------------------------*/
  205. /* g e t D i r E n t r y F o r U p d a t e */
  206. /* */
  207. /* Read a directory sector into the sector buffer and point to an */
  208. /* entry, with the intention of modifying it. */
  209. /* The buffer will be flushed on operation exit. */
  210. /* */
  211. /* Parameters: */
  212. /* vol : Pointer identifying drive */
  213. /* file : File belonging to directory entry */
  214. /* */
  215. /* Returns: */
  216. /* FLStatus : 0 on success, otherwise failed */
  217. /* dirEntry : Pointer to directory entry in buffer */
  218. /*----------------------------------------------------------------------*/
  219. static FLStatus getDirEntryForUpdate(File *file, DirectoryEntry * *dirEntry)
  220. {
  221. Volume vol = file->fileVol;
  222. checkStatus(updateSector(file->fileVol,file->directorySector,TRUE));
  223. *dirEntry = directory + file->directoryIndex;
  224. vol.volBuffer.checkPoint = TRUE;
  225. return flOK;
  226. }
  227. #endif /* FL_READ_ONLY */
  228. /*----------------------------------------------------------------------*/
  229. /* s e t C u r r e n t D a t e T i m e */
  230. /* */
  231. /* Set current time/date in directory entry */
  232. /* */
  233. /* Parameters: */
  234. /* dirEntry : Pointer to directory entry */
  235. /* */
  236. /*----------------------------------------------------------------------*/
  237. static void setCurrentDateTime(DirectoryEntry *dirEntry)
  238. {
  239. toLE2(dirEntry->updateTime,flCurrentTime());
  240. toLE2(dirEntry->updateDate,flCurrentDate());
  241. }
  242. /*----------------------------------------------------------------------*/
  243. /* g e t F A T e n t r y */
  244. /* */
  245. /* Get an entry from the FAT. The 1st FAT copy is used. */
  246. /* */
  247. /* Parameters: */
  248. /* vol : Pointer identifying drive */
  249. /* cluster : Cluster no. of enrty. */
  250. /* */
  251. /* Returns: */
  252. /* Value of FAT entry. */
  253. /*----------------------------------------------------------------------*/
  254. static FLStatus getFATentry(Volume vol, unsigned* entry)
  255. {
  256. unsigned cluster = *entry;
  257. LEushort FAR0 *fat16Sector;
  258. unsigned fatSectorNo = vol.firstFATSectorNo;
  259. #ifdef FAT_12BIT
  260. if (vol.flags & VOLUME_12BIT_FAT)
  261. fatSectorNo += (cluster * 3) >> (SECTOR_SIZE_BITS + 1);
  262. else
  263. #endif
  264. fatSectorNo += cluster >> (SECTOR_SIZE_BITS - 1);
  265. #ifndef FL_READ_ONLY
  266. if (!vol.volBuffer.dirty) {
  267. /* If the buffer is free, use it to store this FAT sector */
  268. checkStatus(updateSector(&vol,fatSectorNo,TRUE));
  269. vol.volBuffer.dirty = FALSE;
  270. }
  271. #endif /* FL_READ_ONLY */
  272. fat16Sector = (LEushort FAR0 *) findSector(&vol,fatSectorNo);
  273. if(fat16Sector==NULL)
  274. return flSectorNotFound;
  275. if(fat16Sector==dataErrorToken)
  276. return flDataError;
  277. #ifdef FAT_12BIT
  278. if (vol.flags & VOLUME_12BIT_FAT) {
  279. unsigned char FAR0 *fat12Sector = (unsigned char FAR0 *) fat16Sector;
  280. unsigned halfByteOffset = (cluster * 3) & (SECTOR_SIZE * 2 - 1);
  281. unsigned char firstByte = fat12Sector[halfByteOffset / 2];
  282. halfByteOffset += 2;
  283. if (halfByteOffset >= SECTOR_SIZE * 2) {
  284. /* Entry continues on the next sector. What a mess */
  285. halfByteOffset -= SECTOR_SIZE * 2;
  286. fat12Sector = (unsigned char FAR0 *) findSector(&vol,fatSectorNo + 1);
  287. if(fat12Sector==NULL)
  288. return flSectorNotFound;
  289. if(fat12Sector==dataErrorToken)
  290. return flDataError;
  291. }
  292. if (halfByteOffset & 1)
  293. *entry = ((firstByte & 0xf0) >> 4) + (fat12Sector[halfByteOffset / 2] << 4);
  294. else
  295. *entry = firstByte + ((fat12Sector[halfByteOffset / 2] & 0xf) << 8);
  296. if (*entry == 0xfff) /* in 12-bit fat, 0xfff marks the last cluster */
  297. *entry = FAT_LAST_CLUSTER; /* return 0xffff instead */
  298. return flOK;
  299. }
  300. else {
  301. #endif
  302. *entry = LE2(fat16Sector[cluster & (SECTOR_SIZE / 2 - 1)]);
  303. return flOK;
  304. #ifdef FAT_12BIT
  305. }
  306. #endif
  307. }
  308. #ifndef FL_READ_ONLY
  309. /*----------------------------------------------------------------------*/
  310. /* s e t F A T e n t r y */
  311. /* */
  312. /* Writes a new value to a given FAT cluster entry. */
  313. /* */
  314. /* Parameters: */
  315. /* vol : Pointer identifying drive */
  316. /* cluster : Cluster no. of enrty. */
  317. /* entry : New value of FAT entry. */
  318. /* */
  319. /* Returns: */
  320. /* FLStatus : 0 on success, otherwise failed */
  321. /*----------------------------------------------------------------------*/
  322. static FLStatus setFATentry(Volume vol, unsigned cluster, unsigned entry)
  323. {
  324. LEushort *fat16Sector;
  325. unsigned fatSectorNo = vol.firstFATSectorNo;
  326. #ifdef FAT_12BIT
  327. if (vol.flags & VOLUME_12BIT_FAT)
  328. fatSectorNo += (cluster * 3) >> (SECTOR_SIZE_BITS + 1);
  329. else
  330. #endif
  331. fatSectorNo += cluster >> (SECTOR_SIZE_BITS - 1);
  332. checkStatus(updateSector(&vol,fatSectorNo,TRUE));
  333. fat16Sector = (LEushort *) vol.volBuffer.flData;
  334. #ifdef FAT_12BIT
  335. if (vol.flags & VOLUME_12BIT_FAT) {
  336. unsigned char *fat12Sector = (unsigned char *) vol.volBuffer.flData;
  337. unsigned halfByteOffset = (cluster * 3) & (SECTOR_SIZE * 2 - 1);
  338. if (halfByteOffset & 1) {
  339. fat12Sector[halfByteOffset / 2] &= 0xf;
  340. fat12Sector[halfByteOffset / 2] |= (entry & 0xf) << 4;
  341. }
  342. else
  343. fat12Sector[halfByteOffset / 2] = entry;
  344. halfByteOffset += 2;
  345. if (halfByteOffset >= SECTOR_SIZE * 2) {
  346. /* Entry continues on the next sector. What a mess */
  347. halfByteOffset -= SECTOR_SIZE * 2;
  348. fatSectorNo++;
  349. checkStatus(updateSector(&vol,fatSectorNo,TRUE));
  350. }
  351. if (halfByteOffset & 1)
  352. fat12Sector[halfByteOffset / 2] = entry >> 4;
  353. else {
  354. fat12Sector[halfByteOffset / 2] &= 0xf0;
  355. fat12Sector[halfByteOffset / 2] |= (entry & 0x0f00) >> 8;
  356. }
  357. }
  358. else
  359. #endif
  360. toLE2(fat16Sector[cluster & (SECTOR_SIZE / 2 - 1)],entry);
  361. return flOK;
  362. }
  363. /*----------------------------------------------------------------------*/
  364. /* a l l o c a t e C l u s t e r */
  365. /* */
  366. /* Allocates a new cluster for a file and adds it to a FAT chain or */
  367. /* marks it in a directory entry. */
  368. /* */
  369. /* Parameters: */
  370. /* vol : Pointer identifying drive */
  371. /* file : File to extend. It should be positioned at */
  372. /* end-of-file. */
  373. /* */
  374. /* Returns: */
  375. /* FLStatus : 0 on success, otherwise failed */
  376. /*----------------------------------------------------------------------*/
  377. static FLStatus allocateCluster(File *file)
  378. {
  379. Volume vol = file->fileVol;
  380. unsigned originalRover;
  381. unsigned fatEntry;
  382. if (file->flags & FILE_READ_ONLY)
  383. return flNoWriteAccess;
  384. /* Look for a free cluster. Start at the allocation rover */
  385. originalRover = vol.allocationRover;
  386. do {
  387. vol.allocationRover++;
  388. if (vol.allocationRover > vol.maxCluster)
  389. vol.allocationRover = 2; /* wraparound to start of volume */
  390. if (vol.allocationRover == originalRover)
  391. return flNoSpaceInVolume;
  392. fatEntry = vol.allocationRover;
  393. checkStatus(getFATentry(&vol,&fatEntry));
  394. } while ( fatEntry!= FAT_FREE);
  395. /* Found a free cluster. Mark it as an end of chain */
  396. checkStatus(setFATentry(&vol,vol.allocationRover,FAT_LAST_CLUSTER));
  397. /* Mark previous cluster or directory to point to it */
  398. if (file->currentCluster == 0) {
  399. DirectoryEntry *dirEntry;
  400. checkStatus(getDirEntryForUpdate(file,&dirEntry));
  401. toLE2(dirEntry->startingCluster,vol.allocationRover);
  402. setCurrentDateTime(dirEntry);
  403. }
  404. else
  405. checkStatus(setFATentry(&vol,file->currentCluster,vol.allocationRover));
  406. /* Set our new current cluster */
  407. file->currentCluster = vol.allocationRover;
  408. return flOK;
  409. }
  410. #endif /* FL_READ_ONLY */
  411. /*----------------------------------------------------------------------*/
  412. /* g e t S e c t o r A n d O f f s e t */
  413. /* */
  414. /* Based on the current position of a file, gets a sector number and */
  415. /* offset in the sector that marks the file's current position. */
  416. /* If the position is at the end-of-file, and the file is opened for */
  417. /* write, this routine will extend the file by allocating a new cluster.*/
  418. /* */
  419. /* Parameters: */
  420. /* vol : Pointer identifying drive */
  421. /* */
  422. /* Returns: */
  423. /* FLStatus : 0 on success, otherwise failed */
  424. /*----------------------------------------------------------------------*/
  425. static FLStatus getSectorAndOffset(File *file,
  426. SectorNo *sectorNo,
  427. unsigned *offsetInSector)
  428. {
  429. Volume vol = file->fileVol;
  430. unsigned offsetInCluster =
  431. (unsigned) file->currentPosition & (vol.bytesPerCluster - 1);
  432. if (file->flags & FILE_IS_ROOT_DIR) {
  433. if (file->currentPosition >= file->fileSize)
  434. return flRootDirectoryFull;
  435. }
  436. if (offsetInCluster == 0) { /* This cluster is finished. Get next */
  437. if (!(file->flags & FILE_IS_ROOT_DIR)) {
  438. if (((file->currentPosition >= file->fileSize) && (file->currentPosition>0))||((file->fileSize==0)&&!(file->flags & FILE_IS_DIRECTORY))) {
  439. #ifndef FL_READ_ONLY
  440. checkStatus(allocateCluster(file));
  441. #else
  442. return flSectorNotFound;
  443. #endif
  444. }
  445. else {
  446. unsigned nextCluster;
  447. if (file->currentCluster == 0) {
  448. const DirectoryEntry FAR0 *dirEntry;
  449. dirEntry = getDirEntry(file);
  450. if(dirEntry==NULL)
  451. return flSectorNotFound;
  452. if(dirEntry==dataErrorToken)
  453. return flDataError;
  454. nextCluster = LE2(dirEntry->startingCluster);
  455. }
  456. else {
  457. nextCluster = file->currentCluster;
  458. checkStatus(getFATentry(&vol,&nextCluster));
  459. }
  460. if (nextCluster < 2 || nextCluster > vol.maxCluster)
  461. /* We have a bad file size, or the FAT is bad */
  462. return flInvalidFATchain;
  463. file->currentCluster = nextCluster;
  464. }
  465. }
  466. }
  467. *offsetInSector = offsetInCluster & (SECTOR_SIZE - 1);
  468. if (file->flags & FILE_IS_ROOT_DIR)
  469. *sectorNo = vol.rootDirectorySectorNo +
  470. (SectorNo) (file->currentPosition >> SECTOR_SIZE_BITS);
  471. else
  472. *sectorNo = firstSectorOfCluster(&vol,file->currentCluster) +
  473. (SectorNo) (offsetInCluster >> SECTOR_SIZE_BITS);
  474. return flOK;
  475. }
  476. /*----------------------------------------------------------------------*/
  477. /* c l o s e F i l e */
  478. /* */
  479. /* Closes an open file, records file size and dates in directory and */
  480. /* releases file handle. */
  481. /* */
  482. /* Parameters: */
  483. /* vol : Pointer identifying drive */
  484. /* file : File to close. */
  485. /* */
  486. /* Returns: */
  487. /* FLStatus : 0 on success, otherwise failed */
  488. /*----------------------------------------------------------------------*/
  489. FLStatus closeFile(File *file)
  490. {
  491. #ifndef FL_READ_ONLY
  492. if ((file->flags & FILE_MODIFIED) && !(file->flags & FILE_IS_ROOT_DIR)) {
  493. DirectoryEntry *dirEntry;
  494. checkStatus(getDirEntryForUpdate(file,&dirEntry));
  495. dirEntry->attributes |= ATTR_ARCHIVE;
  496. if (!(file->flags & FILE_IS_DIRECTORY))
  497. toLE4(dirEntry->fileSize,file->fileSize);
  498. setCurrentDateTime(dirEntry);
  499. }
  500. #endif
  501. file->flags = 0; /* no longer open */
  502. return flOK;
  503. }
  504. #ifndef FL_READ_ONLY
  505. #ifdef SUB_DIRECTORY
  506. /*----------------------------------------------------------------------*/
  507. /* e x t e n d D i r e c t o r y */
  508. /* */
  509. /* Extends a directory, writing empty entries and the mandatory '.' and */
  510. /* '..' entries. */
  511. /* */
  512. /* Parameters: */
  513. /* vol : Pointer identifying drive */
  514. /* file : Directory file to extend. On entry, */
  515. /* currentPosition == fileSize. On exit, fileSize*/
  516. /* is updated. */
  517. /* ownerDir : Cluster no. of owner directory */
  518. /* */
  519. /* Returns: */
  520. /* FLStatus : 0 on success, otherwise failed */
  521. /*----------------------------------------------------------------------*/
  522. static FLStatus extendDirectory(File *file, unsigned ownerDir)
  523. {
  524. Volume vol = file->fileVol;
  525. unsigned i;
  526. SectorNo sectorOfDir;
  527. unsigned offsetInSector;
  528. /* Assuming the current position is at the end-of-file, this will */
  529. /* extend the directory. */
  530. checkStatus(getSectorAndOffset(file,&sectorOfDir,&offsetInSector));
  531. for (i = 0; i < vol.sectorsPerCluster; i++) {
  532. /* Write binary zeroes to indicate never-used entries */
  533. checkStatus(updateSector(&vol,sectorOfDir + i,FALSE));
  534. vol.volBuffer.checkPoint = TRUE;
  535. if (file->currentPosition == 0 && i == 0) {
  536. /* Add the mandatory . and .. entries */
  537. tffscpy(directory[0].name,". ",sizeof directory[0].name);
  538. directory[0].attributes = ATTR_ARCHIVE | ATTR_DIRECTORY;
  539. toLE2(directory[0].startingCluster,file->currentCluster);
  540. toLE4(directory[0].fileSize,0);
  541. setCurrentDateTime(&directory[0]);
  542. tffscpy(&directory[1],&directory[0],sizeof directory[0]);
  543. directory[1].name[1] = '.'; /* change . to .. */
  544. toLE2(directory[1].startingCluster,ownerDir);
  545. }
  546. file->fileSize += SECTOR_SIZE;
  547. }
  548. /* Update the parent directory by closing the file */
  549. file->flags |= FILE_MODIFIED;
  550. return closeFile(file);
  551. }
  552. #endif /* SUB_DIRECTORY */
  553. #endif /* FL_READ_ONLY */
  554. /*----------------------------------------------------------------------*/
  555. /* f i n d D i r E n t r y */
  556. /* */
  557. /* Finds a directory entry by path-name, or finds an available directory*/
  558. /* entry if the file does not exist. */
  559. /* Most fields necessary for opening a file are set by this routine. */
  560. /* */
  561. /* Parameters: */
  562. /* vol : Pointer identifying drive */
  563. /* path : path to find */
  564. /* file : File in which to record directory information.*/
  565. /* Specific fields on entry: */
  566. /* flags: if FILE_MUST_OPEN = 1, directory */
  567. /* will be extended if necessary. */
  568. /* on exit: */
  569. /* flags: FILE_IS_DIRECTORY and */
  570. /* FILE_IS_ROOT_DIR set if true. */
  571. /* fileSize: Set for non-directory files. */
  572. /* currentCluster: Set to 0 (unknown) */
  573. /* ownerDirCluster: Set to 1st cluster of */
  574. /* owning directory. */
  575. /* directorySector: Sector of directory. If 0 */
  576. /* entry not found and directory full*/
  577. /* directoryEntry: Entry # in directory sector */
  578. /* currentPosition: not set by this routine. */
  579. /* */
  580. /* Returns: */
  581. /* FLStatus : 0 on success and file found */
  582. /* flFileNotFound on success and file not found */
  583. /* otherwise failed. */
  584. /*----------------------------------------------------------------------*/
  585. static FLStatus findDirEntry(Volume vol, FLSimplePath FAR1 *path, File *file)
  586. {
  587. File scanFile; /* Internal file of search */
  588. unsigned dirBackPointer = 0; /* 1st cluster of previous directory */
  589. FLStatus status = flOK; /* root directory exists */
  590. file->flags |= (FILE_IS_ROOT_DIR | FILE_IS_DIRECTORY);
  591. file->fileSize = (long) (vol.sectorsInRootDirectory) << SECTOR_SIZE_BITS;
  592. file->fileVol = &vol;
  593. #ifdef SUB_DIRECTORY
  594. for (; path->name[0]; path++) /* while we have another path segment */
  595. #else
  596. if (path->name[0]) /* search the root directory */
  597. #endif
  598. {
  599. status = flFileNotFound; /* not yet */
  600. if (!(file->flags & FILE_IS_DIRECTORY))
  601. return flPathNotFound; /* if we don't have a directory,
  602. we have no business here */
  603. scanFile = *file; /* the previous file found becomes the scan file */
  604. scanFile.currentPosition = 0;
  605. file->directorySector = 0; /* indicate no entry found yet */
  606. file->flags &= ~(FILE_IS_ROOT_DIR | FILE_IS_DIRECTORY | FILE_READ_ONLY);
  607. file->ownerDirCluster = dirBackPointer;
  608. file->fileSize = 0;
  609. file->currentCluster = 0;
  610. /* Scan directory */
  611. while (scanFile.currentPosition < scanFile.fileSize) {
  612. int i;
  613. DirectoryEntry FAR0 *dirEntry;
  614. SectorNo sectorOfDir;
  615. unsigned offsetInSector;
  616. FLStatus readStatus = getSectorAndOffset(&scanFile,&sectorOfDir,&offsetInSector);
  617. if (readStatus == flInvalidFATchain) {
  618. scanFile.fileSize = scanFile.currentPosition; /* now we know */
  619. break; /* we ran into the end of the directory file */
  620. }
  621. else if (readStatus != flOK)
  622. return readStatus;
  623. dirEntry = (DirectoryEntry FAR0 *) findSector(&vol,sectorOfDir);
  624. if (dirEntry == NULL)
  625. return flSectorNotFound;
  626. if(dirEntry==dataErrorToken)
  627. return flDataError;
  628. scanFile.currentPosition += SECTOR_SIZE;
  629. for (i = 0; i < DIRECTORY_ENTRIES_PER_SECTOR; i++, dirEntry++) {
  630. if (tffscmp(path,dirEntry->name,sizeof dirEntry->name) == 0 &&
  631. !(dirEntry->attributes & ATTR_VOL_LABEL)) {
  632. /* Found a match */
  633. file->directorySector = sectorOfDir;
  634. file->directoryIndex = i;
  635. file->fileSize = LE4(dirEntry->fileSize);
  636. if (dirEntry->attributes & ATTR_DIRECTORY) {
  637. file->flags |= FILE_IS_DIRECTORY;
  638. file->fileSize = 0x7fffffffl;
  639. /* Infinite. Directories don't have a recorded size */
  640. }
  641. if (dirEntry->attributes & ATTR_READ_ONLY)
  642. file->flags |= FILE_READ_ONLY;
  643. dirBackPointer = LE2(dirEntry->startingCluster);
  644. status = flOK;
  645. goto endOfPathSegment;
  646. }
  647. else if (dirEntry->name[0] == NEVER_USED_DIR_ENTRY ||
  648. dirEntry->name[0] == DELETED_DIR_ENTRY) {
  649. /* Found a free entry. Remember it in case we don't find a match */
  650. if (file->directorySector == 0) {
  651. file->directorySector = sectorOfDir;
  652. file->directoryIndex = i;
  653. }
  654. if (dirEntry->name[0] == NEVER_USED_DIR_ENTRY) /* end of dir */
  655. goto endOfPathSegment;
  656. }
  657. }
  658. }
  659. endOfPathSegment:
  660. ;
  661. }
  662. #ifndef FL_READ_ONLY
  663. if (status == flFileNotFound && (file->flags & FILE_MUST_OPEN) &&
  664. file->directorySector == 0) {
  665. /* We did not find a place in the directory for this new entry. The */
  666. /* directory should be extended. 'scanFile' refers to the directory */
  667. /* to extend, and the current pointer is at its end */
  668. #ifdef SUB_DIRECTORY
  669. checkStatus(extendDirectory(&scanFile,(unsigned) file->ownerDirCluster));
  670. file->directorySector = firstSectorOfCluster(&vol,scanFile.currentCluster);
  671. file->directoryIndex = 0; /* Has to be. This is a new cluster */
  672. #else
  673. status = flRootDirectoryFull;
  674. #endif
  675. }
  676. #endif /* FL_READ_ONLY */
  677. return status;
  678. }
  679. /*----------------------------------------------------------------------*/
  680. /* */
  681. /* r e a d M u l t i S e c t o r */
  682. /* */
  683. /* Checks if file was written on consequent sectors. */
  684. /* Parameters: */
  685. /* file : File to check */
  686. /* stillToRead : Number of bytes to read. If the read extends */
  687. /* beyond the end-of-file, the read is truncated */
  688. /* at the end-of-file. */
  689. /* Returns: */
  690. /* FLStatus : 0 on success, otherwise failed */
  691. /* sectors : Number of consequent sectors */
  692. /* */
  693. /*----------------------------------------------------------------------*/
  694. static FLStatus readMultiSector(Volume vol,File *file,
  695. unsigned long stillToRead,
  696. SectorNo* sectors)
  697. {
  698. SectorNo sectorCount = 1;
  699. unsigned offsetInCluster = (unsigned)((file->currentPosition & (vol.bytesPerCluster - 1))+512);
  700. while(stillToRead>=((sectorCount+1)<<SECTOR_SIZE_BITS)){
  701. if(offsetInCluster>=vol.bytesPerCluster) {
  702. unsigned nextCluster;
  703. nextCluster = file->currentCluster;
  704. checkStatus(getFATentry(&vol,&nextCluster));
  705. if (nextCluster < 2 || nextCluster > vol.maxCluster)
  706. /* We have a bad file size, or the FAT is bad */
  707. return flInvalidFATchain;
  708. if(nextCluster!=file->currentCluster+1)
  709. break;
  710. file->currentCluster = nextCluster;
  711. offsetInCluster = 0;
  712. }
  713. offsetInCluster+=SECTOR_SIZE;
  714. sectorCount++;
  715. }
  716. *sectors = sectorCount;
  717. return flOK;
  718. }
  719. /*----------------------------------------------------------------------*/
  720. /* r e a d F i l e */
  721. /* */
  722. /* Reads from the current position in the file to the user-buffer. */
  723. /* Parameters: */
  724. /* file : File to read. */
  725. /* ioreq->irData : Address of user buffer */
  726. /* ioreq->irLength : Number of bytes to read. If the read extends */
  727. /* beyond the end-of-file, the read is truncated */
  728. /* at the end-of-file. */
  729. /* */
  730. /* Returns: */
  731. /* FLStatus : 0 on success, otherwise failed */
  732. /* ioreq->irLength : Actual number of bytes read */
  733. /*----------------------------------------------------------------------*/
  734. FLStatus readFile(File *file,IOreq FAR2 *ioreq)
  735. {
  736. Volume vol = file->fileVol;
  737. unsigned char FAR1 *userData = (unsigned char FAR1 *) ioreq->irData; /* user buffer address */
  738. unsigned long stillToRead = ioreq->irLength;
  739. unsigned long remainingInFile = file->fileSize - file->currentPosition;
  740. ioreq->irLength = 0; /* read so far */
  741. /* Should we return an end of file status ? */
  742. if (stillToRead > remainingInFile)
  743. stillToRead = (unsigned) remainingInFile;
  744. while (stillToRead > 0) {
  745. SectorNo sectorToRead;
  746. unsigned offsetInSector;
  747. unsigned long readThisTime;
  748. const char FAR0 *sector;
  749. checkStatus(getSectorAndOffset(file,&sectorToRead,&offsetInSector));
  750. if (stillToRead < SECTOR_SIZE || offsetInSector > 0 || vol.tl.readSectors==NULL) {
  751. sector = (const char FAR0 *) findSector(&vol,sectorToRead);
  752. if(sector==NULL)
  753. {
  754. DEBUG_PRINT(("readFile : sector was not found\r\n"));
  755. return flSectorNotFound;
  756. }
  757. if(sector==dataErrorToken)
  758. return flDataError;
  759. readThisTime = SECTOR_SIZE - offsetInSector;
  760. if (readThisTime > stillToRead)
  761. readThisTime = (unsigned) stillToRead;
  762. if (sector)
  763. tffscpy(userData,sector + offsetInSector,(unsigned short)readThisTime);
  764. else
  765. return flSectorNotFound; /* Sector does not exist */
  766. }
  767. else {
  768. SectorNo sectorCount;
  769. checkStatus(readMultiSector(&vol,file,stillToRead,&sectorCount));
  770. checkStatus(vol.tl.readSectors(vol.tl.rec,sectorToRead,userData,sectorCount));
  771. readThisTime = (sectorCount<<SECTOR_SIZE_BITS);
  772. }
  773. stillToRead -= readThisTime;
  774. ioreq->irLength += readThisTime;
  775. userData = (unsigned char FAR1 *)flAddLongToFarPointer(userData,readThisTime);
  776. file->currentPosition += readThisTime;
  777. }
  778. return flOK;
  779. }
  780. /*----------------------------------------------------------------------*/
  781. /* f l F i n d N e x t F i l e */
  782. /* */
  783. /* See the description of 'flFindFirstFile'. */
  784. /* */
  785. /* Parameters: */
  786. /* irHandle : File handle returned by flFindFirstFile. */
  787. /* irData : Address of user buffer to receive a */
  788. /* DirectoryEntry structure */
  789. /* */
  790. /* Returns: */
  791. /* FLStatus : 0 on success, otherwise failed */
  792. /*----------------------------------------------------------------------*/
  793. FLStatus findNextFile(File *file, IOreq FAR2 *ioreq)
  794. {
  795. DirectoryEntry FAR1 *irDirEntry = (DirectoryEntry FAR1 *) ioreq->irData;
  796. FLStatus status;
  797. /* Do we have a directory ? */
  798. if (!(file->flags & FILE_IS_DIRECTORY))
  799. return flNotADirectory;
  800. ioreq->irLength = DIRECTORY_ENTRY_SIZE;
  801. do {
  802. /*checkStatus(readFile(file,ioreq));*/
  803. /*Vadim: add treatment for a full cluster sub-directory */
  804. status=readFile(file,ioreq);
  805. if ((ioreq->irLength != DIRECTORY_ENTRY_SIZE) ||
  806. (irDirEntry->name[0] == NEVER_USED_DIR_ENTRY)||
  807. (!(file->flags&FILE_IS_ROOT_DIR)&&(status==flInvalidFATchain)))
  808. {
  809. checkStatus(closeFile(file));
  810. return flNoMoreFiles;
  811. }
  812. else
  813. {
  814. if(status!=flOK)
  815. return status;
  816. }
  817. } while (irDirEntry->name[0] == DELETED_DIR_ENTRY ||
  818. (irDirEntry->attributes & ATTR_VOL_LABEL));
  819. return flOK;
  820. }
  821. #ifndef FL_READ_ONLY
  822. /*----------------------------------------------------------------------*/
  823. /* d e l e t e F i l e */
  824. /* */
  825. /* Deletes a file or directory. */
  826. /* */
  827. /* Parameters: */
  828. /* ioreq->irPath : path of file to delete */
  829. /* isDirectory : 0 = delete file, other = delete directory */
  830. /* */
  831. /* Returns: */
  832. /* FLStatus : 0 on success, otherwise failed */
  833. /*----------------------------------------------------------------------*/
  834. FLStatus deleteFile(Volume vol, IOreq FAR2 *ioreq, FLBoolean isDirectory)
  835. {
  836. File file; /* Our private file */
  837. DirectoryEntry *dirEntry;
  838. file.flags = 0;
  839. checkStatus(findDirEntry(&vol,ioreq->irPath,&file));
  840. if (file.flags & FILE_READ_ONLY)
  841. return flNoWriteAccess;
  842. if (isDirectory) {
  843. DirectoryEntry fileFindInfo;
  844. ioreq->irData = &fileFindInfo;
  845. if (!(file.flags & FILE_IS_DIRECTORY))
  846. return flNotADirectory;
  847. /* Verify that directory is empty */
  848. file.currentPosition = 0;
  849. for (;;) {
  850. FLStatus status = findNextFile(&file,ioreq);
  851. if (status == flNoMoreFiles)
  852. break;
  853. if (status != flOK)
  854. return status;
  855. if (!((fileFindInfo.attributes & ATTR_DIRECTORY) &&
  856. (tffscmp(fileFindInfo.name,". ",sizeof fileFindInfo.name) == 0 ||
  857. tffscmp(fileFindInfo.name,".. ",sizeof fileFindInfo.name) == 0)))
  858. return flDirectoryNotEmpty;
  859. }
  860. }
  861. else {
  862. /* Did we find a directory ? */
  863. if (file.flags & FILE_IS_DIRECTORY)
  864. return flFileIsADirectory;
  865. }
  866. /* Mark directory entry deleted */
  867. checkStatus(getDirEntryForUpdate(&file,&dirEntry));
  868. dirEntry->name[0] = DELETED_DIR_ENTRY;
  869. /* Delete FAT entries */
  870. file.currentPosition = 0;
  871. file.currentCluster = LE2(dirEntry->startingCluster);
  872. while (file.currentPosition < file.fileSize) {
  873. unsigned nextCluster;
  874. if (file.currentCluster < 2 || file.currentCluster > vol.maxCluster)
  875. /* We have a bad file size, or the FAT is bad */
  876. return isDirectory ? flOK : flInvalidFATchain;
  877. nextCluster = file.currentCluster;
  878. checkStatus(getFATentry(&vol,&nextCluster));
  879. /* mark FAT free */
  880. checkStatus(setFATentry(&vol,file.currentCluster,FAT_FREE));
  881. vol.volBuffer.checkPoint = TRUE;
  882. /* mark sectors free */
  883. checkStatus(vol.tl.deleteSector(vol.tl.rec,
  884. firstSectorOfCluster(&vol,file.currentCluster),
  885. vol.sectorsPerCluster));
  886. file.currentPosition += vol.bytesPerCluster;
  887. file.currentCluster = nextCluster;
  888. }
  889. if (file.currentCluster > 1 && file.currentCluster <= vol.maxCluster) {
  890. checkStatus(setFATentry(&vol,file.currentCluster,FAT_FREE));
  891. vol.volBuffer.checkPoint = TRUE;
  892. /* mark sectors free */
  893. checkStatus(vol.tl.deleteSector(vol.tl.rec,
  894. firstSectorOfCluster(&vol,file.currentCluster),
  895. vol.sectorsPerCluster));
  896. }
  897. return flOK;
  898. }
  899. /*----------------------------------------------------------------------*/
  900. /* s e t N a m e I n D i r E n t r y */
  901. /* */
  902. /* Sets the file name in a directory entry from a path name */
  903. /* */
  904. /* Parameters: */
  905. /* dirEntry : directory entry */
  906. /* path : path the last segment of which is the name */
  907. /* */
  908. /*----------------------------------------------------------------------*/
  909. static void setNameInDirEntry(DirectoryEntry *dirEntry, FLSimplePath FAR1 *path)
  910. {
  911. FLSimplePath FAR1 *lastSegment;
  912. for (lastSegment = path; /* Find null terminator */
  913. lastSegment->name[0];
  914. lastSegment++);
  915. tffscpy(dirEntry->name,--lastSegment,sizeof dirEntry->name);
  916. }
  917. #endif /* FL_READ_ONLY */
  918. /*----------------------------------------------------------------------*/
  919. /* o p e n F i l e */
  920. /* */
  921. /* Opens an existing file or creates a new file. Creates a file handle */
  922. /* for further file processing. */
  923. /* */
  924. /* Parameters: */
  925. /* ioreq->irFlags : Access and action options, defined below */
  926. /* ioreq->irPath : path of file to open */
  927. /* */
  928. /* Returns: */
  929. /* FLStatus : 0 on success, otherwise failed */
  930. /* ioreq->irHandle : New file handle for open file */
  931. /* */
  932. /*----------------------------------------------------------------------*/
  933. FLStatus openFile(Volume vol, IOreq FAR2 *ioreq)
  934. {
  935. int i;
  936. FLStatus status;
  937. /* Look for an available file */
  938. File *file = fileTable;
  939. for (i = 0; i < FILES && (file->flags & FILE_IS_OPEN); i++, file++);
  940. if (i >= FILES)
  941. return flTooManyOpenFiles;
  942. file->fileVol = &vol;
  943. ioreq->irHandle = i; /* return file handle */
  944. #ifndef FL_READ_ONLY
  945. /* Delete file if exists and required */
  946. if (ioreq->irFlags & ACCESS_CREATE) {
  947. FLStatus status = deleteFile(&vol,ioreq,FALSE);
  948. if (status != flOK && status != flFileNotFound)
  949. return status;
  950. }
  951. /* Find the path */
  952. if (ioreq->irFlags & ACCESS_CREATE)
  953. file->flags |= FILE_MUST_OPEN;
  954. #endif /* FL_READ_ONLY */
  955. status = findDirEntry(file->fileVol,ioreq->irPath,file);
  956. if (status != flOK &&
  957. (status != flFileNotFound || !(ioreq->irFlags & ACCESS_CREATE)))
  958. return status;
  959. /* Did we find a directory ? */
  960. if (file->flags & FILE_IS_DIRECTORY)
  961. return flFileIsADirectory;
  962. #ifndef FL_READ_ONLY
  963. /* Create file if required */
  964. if (ioreq->irFlags & ACCESS_CREATE) {
  965. DirectoryEntry *dirEntry;
  966. /* Look for a free cluster. Start at the allocation rover */
  967. checkStatus(getDirEntryForUpdate(file,&dirEntry));
  968. setNameInDirEntry(dirEntry,ioreq->irPath);
  969. dirEntry->attributes = ATTR_ARCHIVE;
  970. toLE2(dirEntry->startingCluster,0);
  971. toLE4(dirEntry->fileSize,0);
  972. setCurrentDateTime(dirEntry);
  973. }
  974. #endif /* FL_READ_ONLY */
  975. if (!(ioreq->irFlags & ACCESS_READ_WRITE))
  976. file->flags |= FILE_READ_ONLY;
  977. file->currentPosition = 0; /* located at file beginning */
  978. file->flags |= FILE_IS_OPEN; /* this file now officially open */
  979. return flOK;
  980. }
  981. #ifndef FL_READ_ONLY
  982. /*----------------------------------------------------------------------*/
  983. /* */
  984. /* w r i t e M u l t i S e c t o r */
  985. /* */
  986. /* Checks the possibility of writing file on consequent sectors. */
  987. /* Parameters: */
  988. /* file : File to check */
  989. /* stillToWrite : Number of bytes to read. If the read extends */
  990. /* beyond the end-of-file, the read is truncated */
  991. /* at the end-of-file. */
  992. /* Returns: */
  993. /* FLStatu : 0 on success, otherwise failed */
  994. /* sectors : Number of consequent sectors */
  995. /* */
  996. /*----------------------------------------------------------------------*/
  997. static FLStatus writeMultiSector(Volume vol,File *file,
  998. unsigned long stillToWrite,
  999. SectorNo* sectors)
  1000. {
  1001. SectorNo sectorCount = 1;
  1002. unsigned offsetInCluster = (unsigned)((file->currentPosition & (vol.bytesPerCluster - 1))+512);
  1003. while(stillToWrite>=((sectorCount+1)<<SECTOR_SIZE_BITS)){
  1004. if(offsetInCluster>=vol.bytesPerCluster) {
  1005. if ((long)(file->currentPosition+(sectorCount<<SECTOR_SIZE_BITS))>= file->fileSize) {
  1006. if(file->currentCluster <= vol.maxCluster) {
  1007. unsigned fatEntry;
  1008. if(file->currentCluster+1>vol.maxCluster)
  1009. break;/*There is not free consequent cluster*/
  1010. fatEntry = file->currentCluster+1;
  1011. checkStatus(getFATentry(&vol,&fatEntry));
  1012. if(fatEntry==FAT_FREE) {
  1013. /* Found a free cluster. Mark it as an end of chain */
  1014. checkStatus(setFATentry(&vol,file->currentCluster+1,FAT_LAST_CLUSTER));
  1015. /* Mark previous cluster or directory to point to it */
  1016. checkStatus(setFATentry(&vol,file->currentCluster,file->currentCluster+1));
  1017. /* Set our new current cluster */
  1018. file->currentCluster = file->currentCluster+1;
  1019. offsetInCluster = 0;
  1020. }
  1021. else /*There is not free consequent cluster*/
  1022. break;
  1023. }
  1024. else
  1025. return flInvalidFATchain;
  1026. }
  1027. else { /* We did not passed end of file*/
  1028. unsigned nextCluster = file->currentCluster;
  1029. checkStatus(getFATentry(&vol,&nextCluster));
  1030. if (nextCluster < 2 || nextCluster > vol.maxCluster)
  1031. /* We have a bad file size, or the FAT is bad */
  1032. return flInvalidFATchain;
  1033. if(nextCluster!=file->currentCluster+1)
  1034. break;
  1035. file->currentCluster = nextCluster;
  1036. offsetInCluster = 0;
  1037. }
  1038. }
  1039. offsetInCluster+=SECTOR_SIZE;
  1040. sectorCount++;
  1041. }
  1042. *sectors = sectorCount;
  1043. return flOK;
  1044. }
  1045. /*----------------------------------------------------------------------*/
  1046. /* w r i t e F i l e */
  1047. /* */
  1048. /* Writes from the current position in the file from the user-buffer. */
  1049. /* */
  1050. /* Parameters: */
  1051. /* file : File to write. */
  1052. /* ioreq->irData : Address of user buffer */
  1053. /* ioreq->irLength : Number of bytes to write. */
  1054. /* */
  1055. /* Returns: */
  1056. /* FLStatus : 0 on success, otherwise failed */
  1057. /* ioreq->irLength : Actual number of bytes written */
  1058. /*----------------------------------------------------------------------*/
  1059. FLStatus writeFile(File *file, IOreq FAR2 *ioreq)
  1060. {
  1061. Volume vol = file->fileVol;
  1062. char FAR1 *userData = (char FAR1 *) ioreq->irData; /* user buffer address */
  1063. unsigned long stillToWrite = ioreq->irLength;
  1064. if (file->flags & FILE_READ_ONLY)
  1065. return flNoWriteAccess;
  1066. file->flags |= FILE_MODIFIED;
  1067. ioreq->irLength = 0; /* written so far */
  1068. while (stillToWrite > 0) {
  1069. SectorNo sectorToWrite;
  1070. unsigned offsetInSector;
  1071. unsigned long writeThisTime;
  1072. checkStatus(getSectorAndOffset(file,&sectorToWrite,&offsetInSector));
  1073. if (stillToWrite < SECTOR_SIZE || offsetInSector > 0) {
  1074. unsigned short shortWrite;
  1075. /* Not on full sector boundary */
  1076. checkStatus(updateSector(&vol,sectorToWrite,
  1077. ((file->currentPosition < file->fileSize) || (offsetInSector > 0))));
  1078. #ifdef HIGH_SECURITY
  1079. if ((file->flags & FILE_IS_DIRECTORY)||(file->currentPosition < file->fileSize))
  1080. #else
  1081. if(file->flags & FILE_IS_DIRECTORY)
  1082. #endif
  1083. vol.volBuffer.checkPoint = TRUE;
  1084. writeThisTime = SECTOR_SIZE - offsetInSector;
  1085. if (writeThisTime > stillToWrite)
  1086. writeThisTime = stillToWrite;
  1087. shortWrite = (unsigned short)writeThisTime;
  1088. tffscpy(vol.volBuffer.flData + offsetInSector,userData,shortWrite);
  1089. }
  1090. else {
  1091. SectorNo sectorCount;
  1092. if(vol.tl.writeMultiSector!=NULL) {
  1093. checkStatus(writeMultiSector(&vol,file,stillToWrite,&sectorCount));
  1094. }
  1095. else
  1096. sectorCount = 1;
  1097. if (((sectorToWrite+sectorCount > vol.volBuffer.sectorNo) && (sectorToWrite <= vol.volBuffer.sectorNo)) &&
  1098. (&vol == vol.volBuffer.owner)) {
  1099. vol.volBuffer.sectorNo = UNASSIGNED_SECTOR; /* no longer valid */
  1100. vol.volBuffer.dirty = vol.volBuffer.checkPoint = FALSE;
  1101. }
  1102. if(vol.tl.writeMultiSector==NULL) {
  1103. checkStatus(vol.tl.writeSector(vol.tl.rec,sectorToWrite,userData));
  1104. }
  1105. else {
  1106. checkStatus(vol.tl.writeMultiSector(vol.tl.rec,sectorToWrite,userData,sectorCount));
  1107. }
  1108. writeThisTime = (sectorCount<<SECTOR_SIZE_BITS);
  1109. }
  1110. stillToWrite -= writeThisTime;
  1111. ioreq->irLength += writeThisTime;
  1112. userData = (char FAR1 *)flAddLongToFarPointer(userData,writeThisTime);
  1113. file->currentPosition += writeThisTime;
  1114. if (file->currentPosition > file->fileSize)
  1115. file->fileSize = file->currentPosition;
  1116. }
  1117. return flOK;
  1118. }
  1119. #endif /* FL_READ_ONLY */
  1120. /*----------------------------------------------------------------------*/
  1121. /* s e e k F i l e */
  1122. /* */
  1123. /* Sets the current position in the file, relative to file start, end */
  1124. /* or current position. */
  1125. /* Note: This function will not move the file pointer beyond the */
  1126. /* beginning or end of file, so the actual file position may be */
  1127. /* different from the required. The actual position is indicated on */
  1128. /* return. */
  1129. /* */
  1130. /* Parameters: */
  1131. /* file : File to set position. */
  1132. /* ioreq->irLength : Offset to set position. */
  1133. /* ioreq->irFlags : Method code */
  1134. /* SEEK_START: absolute offset from start of file */
  1135. /* SEEK_CURR: signed offset from current position */
  1136. /* SEEK_END: signed offset from end of file */
  1137. /* */
  1138. /* Returns: */
  1139. /* FLStatus : 0 on success, otherwise failed */
  1140. /* ioreq->irLength : Actual absolute offset from start of file */
  1141. /*----------------------------------------------------------------------*/
  1142. FLStatus seekFile(File *file, IOreq FAR2 *ioreq)
  1143. {
  1144. Volume vol = file->fileVol;
  1145. long int seekPosition = ioreq->irLength;
  1146. switch (ioreq->irFlags) {
  1147. case SEEK_START:
  1148. break;
  1149. case SEEK_CURR:
  1150. seekPosition += file->currentPosition;
  1151. break;
  1152. case SEEK_END:
  1153. seekPosition += file->fileSize;
  1154. break;
  1155. default:
  1156. return flBadParameter;
  1157. }
  1158. if (seekPosition < 0)
  1159. seekPosition = 0;
  1160. if (seekPosition > file->fileSize)
  1161. seekPosition = file->fileSize;
  1162. /* now set the position ... */
  1163. if (seekPosition < file->currentPosition) {
  1164. file->currentCluster = 0;
  1165. file->currentPosition = 0;
  1166. }
  1167. while (file->currentPosition < seekPosition) {
  1168. SectorNo sectorNo;
  1169. unsigned offsetInSector;
  1170. checkStatus(getSectorAndOffset(file,&sectorNo,&offsetInSector));
  1171. file->currentPosition += vol.bytesPerCluster;
  1172. file->currentPosition &= - (long) (vol.bytesPerCluster);
  1173. }
  1174. ioreq->irLength = file->currentPosition = seekPosition;
  1175. return flOK;
  1176. }
  1177. /*----------------------------------------------------------------------*/
  1178. /* f l F i n d F i l e */
  1179. /* */
  1180. /* Finds a file entry in a directory, optionally modifying the file */
  1181. /* time/date and/or attributes. */
  1182. /* Files may be found by handle no. provided they are open, or by name. */
  1183. /* Only the Hidden, System or Read-only attributes may be modified. */
  1184. /* Entries may be found for any existing file or directory other than */
  1185. /* the root. A DirectoryEntry structure describing the file is copied */
  1186. /* to a user buffer. */
  1187. /* */
  1188. /* The DirectoryEntry structure is defined in dosformt.h */
  1189. /* */
  1190. /* Parameters: */
  1191. /* irHandle : If by name: Drive number (0, 1, ...) */
  1192. /* else : Handle of open file */
  1193. /* irPath : If by name: Specifies a file or directory path*/
  1194. /* irFlags : Options flags */
  1195. /* FIND_BY_HANDLE: Find open file by handle. */
  1196. /* Default is access by path. */
  1197. /* SET_DATETIME: Update time/date from buffer */
  1198. /* SET_ATTRIBUTES: Update attributes from buffer */
  1199. /* irDirEntry : Address of user buffer to receive a */
  1200. /* DirectoryEntry structure */
  1201. /* */
  1202. /* Returns: */
  1203. /* irLength : Modified */
  1204. /* FLStatus : 0 on success, otherwise failed */
  1205. /*----------------------------------------------------------------------*/
  1206. FLStatus findFile(Volume vol, File *file, IOreq FAR2 *ioreq)
  1207. {
  1208. File tFile; /* temporary file for searches */
  1209. if (ioreq->irFlags & FIND_BY_HANDLE)
  1210. tFile = *file;
  1211. else {
  1212. tFile.flags = 0;
  1213. checkStatus(findDirEntry(&vol,ioreq->irPath,&tFile));
  1214. }
  1215. if (tFile.flags & FILE_IS_ROOT_DIR)
  1216. if (ioreq->irFlags & (SET_DATETIME | SET_ATTRIBUTES))
  1217. return flPathIsRootDirectory;
  1218. else {
  1219. DirectoryEntry FAR1 *irDirEntry = (DirectoryEntry FAR1 *) ioreq->irData;
  1220. tffsset(irDirEntry,0,sizeof(DirectoryEntry));
  1221. irDirEntry->attributes = ATTR_DIRECTORY;
  1222. return flOK;
  1223. }
  1224. #ifndef FL_READ_ONLY
  1225. if (ioreq->irFlags & (SET_DATETIME | SET_ATTRIBUTES)) {
  1226. DirectoryEntry FAR1 *irDirEntry = (DirectoryEntry FAR1 *) ioreq->irData;
  1227. DirectoryEntry *dirEntry;
  1228. checkStatus(getDirEntryForUpdate(&tFile,&dirEntry));
  1229. if (ioreq->irFlags & SET_DATETIME) {
  1230. COPY2(dirEntry->updateDate,irDirEntry->updateDate);
  1231. COPY2(dirEntry->updateTime,irDirEntry->updateTime);
  1232. }
  1233. if (ioreq->irFlags & SET_ATTRIBUTES) {
  1234. unsigned char attr;
  1235. attr = dirEntry->attributes & ATTR_DIRECTORY;
  1236. attr |= irDirEntry->attributes &
  1237. (ATTR_ARCHIVE | ATTR_HIDDEN | ATTR_READ_ONLY | ATTR_SYSTEM);
  1238. dirEntry->attributes = attr;
  1239. }
  1240. tffscpy(irDirEntry, dirEntry, sizeof(DirectoryEntry));
  1241. }
  1242. else
  1243. #endif /* FL_READ_ONLY */
  1244. {
  1245. const DirectoryEntry FAR0 *dirEntry;
  1246. dirEntry = getDirEntry(&tFile);
  1247. if(dirEntry==NULL)
  1248. return flSectorNotFound;
  1249. if(dirEntry==dataErrorToken)
  1250. return flDataError;
  1251. tffscpy(ioreq->irData,dirEntry,sizeof(DirectoryEntry));
  1252. if (ioreq->irFlags & FIND_BY_HANDLE)
  1253. toLE4(((DirectoryEntry FAR1 *) (ioreq->irData))->fileSize, tFile.fileSize);
  1254. }
  1255. return flOK;
  1256. }
  1257. /*----------------------------------------------------------------------*/
  1258. /* f l F i n d F i r s t F i l e */
  1259. /* */
  1260. /* Finds the first file entry in a directory. */
  1261. /* This function is used in combination with the flFindNextFile call, */
  1262. /* which returns the remaining file entries in a directory sequentially.*/
  1263. /* Entries are returned according to the unsorted directory order. */
  1264. /* flFindFirstFile creates a file handle, which is returned by it. Calls*/
  1265. /* to flFindNextFile will provide this file handle. When flFindNextFile */
  1266. /* returns 'noMoreEntries', the file handle is automatically closed. */
  1267. /* Alternatively the file handle can be closed by a 'closeFile' call */
  1268. /* before actually reaching the end of directory. */
  1269. /* A DirectoryEntry structure is copied to the user buffer describing */
  1270. /* each file found. This structure is defined in dosformt.h. */
  1271. /* */
  1272. /* Parameters: */
  1273. /* irHandle : Drive number (0, 1, ...) */
  1274. /* irPath : Specifies a directory path */
  1275. /* irData : Address of user buffer to receive a */
  1276. /* DirectoryEntry structure */
  1277. /* */
  1278. /* Returns: */
  1279. /* irHandle : File handle to use for subsequent operations. */
  1280. /* FLStatus : 0 on success, otherwise failed */
  1281. /*----------------------------------------------------------------------*/
  1282. FLStatus findFirstFile(Volume vol, IOreq FAR2 *ioreq)
  1283. {
  1284. int i;
  1285. /* Look for an available file */
  1286. File *file = fileTable;
  1287. for (i = 0; i < FILES && (file->flags & FILE_IS_OPEN); i++, file++);
  1288. if (i >= FILES)
  1289. return flTooManyOpenFiles;
  1290. file->fileVol = &vol;
  1291. ioreq->irHandle = i; /* return file handle */
  1292. /* Find the path */
  1293. checkStatus(findDirEntry(file->fileVol,ioreq->irPath,file));
  1294. file->currentPosition = 0; /* located at file beginning */
  1295. file->flags |= FILE_IS_OPEN | FILE_READ_ONLY; /* this file now officially open */
  1296. return findNextFile(file,ioreq);
  1297. }
  1298. /*----------------------------------------------------------------------*/
  1299. /* g e t D i s k I n f o */
  1300. /* */
  1301. /* Returns general allocation information. */
  1302. /* */
  1303. /* The bytes/sector, sector/cluster, total cluster and free cluster */
  1304. /* information are returned into a DiskInfo structure. */
  1305. /* */
  1306. /* Parameters: */
  1307. /* ioreq->irData : Address of DiskInfo structure */
  1308. /* */
  1309. /* Returns: */
  1310. /* FLStatus : 0 on success, otherwise failed */
  1311. /*----------------------------------------------------------------------*/
  1312. FLStatus getDiskInfo(Volume vol, IOreq FAR2 *ioreq)
  1313. {
  1314. unsigned i;
  1315. unsigned fatEntry;
  1316. DiskInfo FAR1 *diskInfo = (DiskInfo FAR1 *) ioreq->irData;
  1317. diskInfo->bytesPerSector = SECTOR_SIZE;
  1318. diskInfo->sectorsPerCluster = vol.sectorsPerCluster;
  1319. diskInfo->totalClusters = vol.maxCluster - 1;
  1320. diskInfo->freeClusters = 0; /* let's count them */
  1321. for (i = 2; i <= vol.maxCluster; i++) {
  1322. fatEntry = i;
  1323. checkStatus(getFATentry(&vol,&fatEntry));
  1324. if ( fatEntry== 0)
  1325. diskInfo->freeClusters++;
  1326. }
  1327. return flOK;
  1328. }
  1329. #ifndef FL_READ_ONLY
  1330. #ifdef RENAME_FILE
  1331. /*----------------------------------------------------------------------*/
  1332. /* r e n a m e F i l e */
  1333. /* */
  1334. /* Renames a file to another name. */
  1335. /* */
  1336. /* Parameters: */
  1337. /* ioreq->irPath : path of existing file */
  1338. /* ioreq->irData : path of new name. */
  1339. /* */
  1340. /* Returns: */
  1341. /* FLStatus : 0 on success, otherwise failed */
  1342. /*----------------------------------------------------------------------*/
  1343. FLStatus renameFile(Volume vol, IOreq FAR2 *ioreq)
  1344. {
  1345. File file, file2; /* temporary files for searches */
  1346. DirectoryEntry *dirEntry, *dirEntry2;
  1347. FLStatus status;
  1348. FLSimplePath FAR1 *irPath2 = (FLSimplePath FAR1 *) ioreq->irData;
  1349. file.flags = 0;
  1350. checkStatus(findDirEntry(&vol,ioreq->irPath,&file));
  1351. file2.flags = FILE_MUST_OPEN;
  1352. status = findDirEntry(file.fileVol,irPath2,&file2);
  1353. if (status != flFileNotFound)
  1354. return status == flOK ? flFileAlreadyExists : status;
  1355. #ifndef VFAT_COMPATIBILITY
  1356. if (file.ownerDirCluster == file2.ownerDirCluster) { /* Same directory */
  1357. /* Change name in directory entry */
  1358. checkStatus(getDirEntryForUpdate(&file,&dirEntry));
  1359. setNameInDirEntry(dirEntry,irPath2);
  1360. }
  1361. else
  1362. #endif
  1363. { /* not same directory */
  1364. /* Write new directory entry */
  1365. const DirectoryEntry FAR0 *dir;
  1366. checkStatus(getDirEntryForUpdate(&file2,&dirEntry2));
  1367. dir = getDirEntry(&file);
  1368. if(dir==NULL)
  1369. return flSectorNotFound;
  1370. if(dir==dataErrorToken)
  1371. return flDataError;
  1372. *dirEntry2 = *dir;
  1373. setNameInDirEntry(dirEntry2,irPath2);
  1374. /* Delete original entry */
  1375. checkStatus(getDirEntryForUpdate(&file,&dirEntry));
  1376. dirEntry->name[0] = DELETED_DIR_ENTRY;
  1377. }
  1378. return flOK;
  1379. }
  1380. #endif /* RENAME_FILE */
  1381. #endif /* FL_READ_ONLY */
  1382. #ifndef FL_READ_ONLY
  1383. #ifdef SUB_DIRECTORY
  1384. /*----------------------------------------------------------------------*/
  1385. /* m a k e D i r */
  1386. /* */
  1387. /* Creates a new directory. */
  1388. /* */
  1389. /* Parameters: */
  1390. /* ioreq->irPath : path of new directory. */
  1391. /* */
  1392. /* Returns: */
  1393. /* FLStatus : 0 on success, otherwise failed */
  1394. /*----------------------------------------------------------------------*/
  1395. FLStatus makeDir(Volume vol, IOreq FAR2 *ioreq)
  1396. {
  1397. File file; /* temporary file for searches */
  1398. unsigned dirBackPointer;
  1399. DirectoryEntry *dirEntry;
  1400. FLStatus status;
  1401. unsigned originalRover;
  1402. unsigned fatEntry;
  1403. file.flags = FILE_MUST_OPEN;
  1404. status = findDirEntry(&vol,ioreq->irPath,&file);
  1405. if (status != flFileNotFound)
  1406. return status == flOK ? flFileAlreadyExists : status;
  1407. /* Look for a free cluster. Start at the allocation rover */
  1408. originalRover = vol.allocationRover;
  1409. do {
  1410. vol.allocationRover++;
  1411. if (vol.allocationRover > vol.maxCluster)
  1412. vol.allocationRover = 2; /* wraparound to start of volume */
  1413. if (vol.allocationRover == originalRover)
  1414. return flNoSpaceInVolume;
  1415. fatEntry = vol.allocationRover;
  1416. checkStatus(getFATentry(&vol,&fatEntry));
  1417. } while ( fatEntry!= FAT_FREE);
  1418. /* Found a free cluster. Mark it as an end of chain */
  1419. checkStatus(setFATentry(&vol,vol.allocationRover,FAT_LAST_CLUSTER));
  1420. /* Create the directory entry for the new dir */
  1421. checkStatus(getDirEntryForUpdate(&file,&dirEntry));
  1422. setNameInDirEntry(dirEntry,ioreq->irPath);
  1423. dirEntry->attributes = ATTR_ARCHIVE | ATTR_DIRECTORY;
  1424. toLE2(dirEntry->startingCluster,vol.allocationRover);
  1425. toLE4(dirEntry->fileSize,0);
  1426. setCurrentDateTime(dirEntry);
  1427. /* Remember the back pointer to owning directory for the ".." entry */
  1428. dirBackPointer = (unsigned) file.ownerDirCluster;
  1429. file.flags |= FILE_IS_DIRECTORY;
  1430. file.currentPosition = 0;
  1431. file.fileSize = 0;
  1432. return extendDirectory(&file,dirBackPointer);
  1433. }
  1434. #endif /* SUB_DIRECTORY */
  1435. #ifdef SPLIT_JOIN_FILE
  1436. /*------------------------------------------------------------------------*/
  1437. /* j o i n F i l e */
  1438. /* */
  1439. /* joins two files. If the end of the first file is on a cluster */
  1440. /* boundary, the files will be joined there. Otherwise, the data in */
  1441. /* the second file from the beginning until the offset that is equal to */
  1442. /* the offset in cluster of the end of the first file will be lost. The */
  1443. /* rest of the second file will be joined to the first file at the end of */
  1444. /* the first file. On exit, the first file is the expanded file and the */
  1445. /* second file is deleted. */
  1446. /* Note: The second file will be open by this function, it is advised to */
  1447. /* close it before calling this function in order to avoid */
  1448. /* inconsistencies. */
  1449. /* */
  1450. /* Parameters: */
  1451. /* file : file to join to. */
  1452. /* irPath : Path name of the file to be joined. */
  1453. /* */
  1454. /* Returns: */
  1455. /* FLStatus : 0 on success, otherwise failed. */
  1456. /* */
  1457. /*------------------------------------------------------------------------*/
  1458. FLStatus joinFile (File *file, IOreq FAR2 *ioreq)
  1459. {
  1460. Volume vol = file->fileVol;
  1461. File joinedFile;
  1462. DirectoryEntry *joinedDirEntry;
  1463. unsigned offsetInCluster = (unsigned)(file->fileSize % vol.bytesPerCluster);
  1464. if (file->flags & FILE_READ_ONLY)
  1465. return flNoWriteAccess;
  1466. if (file->flags & FILE_IS_DIRECTORY)
  1467. return flFileIsADirectory;
  1468. /* open the joined file. */
  1469. joinedFile.flags = 0;
  1470. checkStatus(findDirEntry(file->fileVol,ioreq->irPath,&joinedFile));
  1471. joinedFile.currentPosition = 0;
  1472. /* Check if the two files are the same file. */
  1473. if (file->directorySector == joinedFile.directorySector &&
  1474. file->directoryIndex == joinedFile.directoryIndex)
  1475. return flBadFileHandle;
  1476. file->flags |= FILE_MODIFIED;
  1477. if (joinedFile.fileSize > (long)offsetInCluster) { /* the joined file extends
  1478. beyond file's end of file.*/
  1479. unsigned lastCluster, nextCluster, firstCluster;
  1480. const DirectoryEntry FAR0 *dir;
  1481. dir = getDirEntry(&joinedFile);
  1482. if(dir==NULL)
  1483. return flSectorNotFound;
  1484. if(dir==dataErrorToken)
  1485. return flDataError;
  1486. /* get the first cluster of the joined file. */
  1487. firstCluster = LE2(dir->startingCluster);
  1488. if (file->fileSize) { /* the file is not empty.*/
  1489. /* find the last cluster of file by following the FAT chain.*/
  1490. if (file->currentCluster == 0) { /* start from the first cluster.*/
  1491. const DirectoryEntry FAR0 *dir;
  1492. dir = getDirEntry(file);
  1493. if(dir==NULL)
  1494. return flSectorNotFound;
  1495. if(dir==dataErrorToken)
  1496. return flDataError;
  1497. nextCluster = LE2(dir->startingCluster);
  1498. }
  1499. else /* start from the current cluster.*/
  1500. nextCluster = file->currentCluster;
  1501. /* follow the FAT chain.*/
  1502. while (nextCluster != FAT_LAST_CLUSTER) {
  1503. if (nextCluster < 2 || nextCluster > vol.maxCluster)
  1504. return flInvalidFATchain;
  1505. lastCluster = nextCluster;
  1506. checkStatus(getFATentry(&vol,&nextCluster));
  1507. }
  1508. }
  1509. else /* the file is empty. */
  1510. lastCluster = 0;
  1511. if (offsetInCluster) { /* join in the middle of a cluster.*/
  1512. SectorNo sectorNo, joinedSectorNo, tempSectorNo;
  1513. unsigned offset, joinedOffset, numOfSectors = 1, i;
  1514. const char FAR0 *startCopy;
  1515. unsigned fatEntry;
  1516. /* get the sector and offset of the end of the file.*/
  1517. file->currentPosition = file->fileSize;
  1518. file->currentCluster = lastCluster;
  1519. checkStatus(getSectorAndOffset(file, &sectorNo, &offset));
  1520. /* load the sector of the end of the file to the buffer.*/
  1521. checkStatus(updateSector(&vol, sectorNo, TRUE));
  1522. /* copy the second part of the first cluster of the joined file
  1523. to the end of the last cluster of the original file.*/
  1524. /* first set the current position of the joined file.*/
  1525. joinedFile.currentPosition = offsetInCluster;
  1526. joinedFile.currentCluster = firstCluster;
  1527. /* get the relevant sector in the joined file.*/
  1528. checkStatus(getSectorAndOffset(&joinedFile, &joinedSectorNo, &joinedOffset));
  1529. /* map sector and offset.*/
  1530. startCopy = (const char FAR0 *) findSector(&vol,joinedSectorNo) + joinedOffset;
  1531. if (startCopy == NULL)
  1532. return flSectorNotFound;
  1533. if(startCopy==dataErrorToken)
  1534. return flDataError;
  1535. /* copy.*/
  1536. tffscpy(vol.volBuffer.flData + offset, startCopy, SECTOR_SIZE - offset);
  1537. checkStatus(flushBuffer(&vol));
  1538. /* find how many sectors should still be copied (the number of sectors
  1539. until the end of the current cluster).*/
  1540. tempSectorNo = firstSectorOfCluster(&vol,lastCluster);
  1541. while(tempSectorNo != sectorNo) {
  1542. tempSectorNo++;
  1543. numOfSectors++;
  1544. }
  1545. /* copy the rest of the sectors in the current cluster.
  1546. this is done by loading a sector from the joined file to the buffer,
  1547. changing the sectoNo of the buffer to the relevant sector in file
  1548. and then flushing the buffer.*/
  1549. sectorNo++;
  1550. joinedSectorNo++;
  1551. for(i = 0; i < vol.sectorsPerCluster - numOfSectors; i++) {
  1552. checkStatus(updateSector(&vol,joinedSectorNo, TRUE));
  1553. vol.volBuffer.sectorNo = sectorNo;
  1554. checkStatus(flushBuffer(&vol));
  1555. sectorNo++;
  1556. joinedSectorNo++;
  1557. }
  1558. fatEntry = firstCluster;
  1559. checkStatus(getFATentry(&vol,&fatEntry));
  1560. /* adjust the FAT chain.*/
  1561. checkStatus(setFATentry(&vol,
  1562. lastCluster,
  1563. fatEntry));
  1564. /* mark the first cluster of the joined file as free */
  1565. checkStatus(setFATentry(&vol,firstCluster,FAT_FREE));
  1566. vol.volBuffer.checkPoint = TRUE;
  1567. /* mark sectors free */
  1568. checkStatus(vol.tl.deleteSector(vol.tl.rec,firstSectorOfCluster(&vol,firstCluster),
  1569. vol.sectorsPerCluster));
  1570. }
  1571. else { /* join on a cluster boundary.*/
  1572. if (lastCluster) { /* file is not empty. */
  1573. checkStatus(setFATentry(&vol,lastCluster, firstCluster));
  1574. }
  1575. else { /* file is empty.*/
  1576. DirectoryEntry *dirEntry;
  1577. checkStatus(getDirEntryForUpdate(file, &dirEntry));
  1578. toLE2(dirEntry->startingCluster, firstCluster);
  1579. setCurrentDateTime(dirEntry);
  1580. }
  1581. }
  1582. /*adjust the size of the expanded file.*/
  1583. file->fileSize += joinedFile.fileSize - offsetInCluster;
  1584. /* mark the directory entry of the joined file as deleted.*/
  1585. checkStatus(getDirEntryForUpdate(&joinedFile, &joinedDirEntry));
  1586. joinedDirEntry->name[0] = DELETED_DIR_ENTRY;
  1587. }
  1588. else /* the joined file is too small all is left to do is delete it */
  1589. checkStatus(deleteFile (&vol, ioreq, FALSE));
  1590. return flOK;
  1591. }
  1592. /*------------------------------------------------------------------------*/
  1593. /* s p l i t F i l e */
  1594. /* */
  1595. /* Splits the file into two files. The original file contains the first */
  1596. /* part, and a new file (which is created for that purpose) contains */
  1597. /* the second part. If the current position is on a cluster */
  1598. /* boundary, the file will be split at the current position. Otherwise, */
  1599. /* the cluster of the current position is duplicated, one copy is the */
  1600. /* first cluster of the new file, and the other is the last cluster of the*/
  1601. /* original file, which now ends at the current position. */
  1602. /* */
  1603. /* Parameters: */
  1604. /* file : file to split. */
  1605. /* irPath : Path name of the new file. */
  1606. /* */
  1607. /* Returns: */
  1608. /* irHandle : handle of the new file. */
  1609. /* FLStatus : 0 on success, otherwise failed. */
  1610. /* */
  1611. /*------------------------------------------------------------------------*/
  1612. FLStatus splitFile (File *file, IOreq FAR2 *ioreq)
  1613. {
  1614. Volume vol = file->fileVol;
  1615. File *newFile, dummyFile;
  1616. IOreq ioreq2;
  1617. FLStatus status;
  1618. unsigned fatEntry;
  1619. if (file->flags & FILE_READ_ONLY)
  1620. return flNoWriteAccess;
  1621. if (file->flags & FILE_IS_DIRECTORY)
  1622. return flFileIsADirectory;
  1623. /* check if the path of the new file already exists.*/
  1624. dummyFile.flags = 0;
  1625. status = findDirEntry(&vol,ioreq->irPath,&dummyFile);
  1626. if (status != flFileNotFound) {
  1627. if (status == flOK) /* there is a file with that path.*/
  1628. return flFileAlreadyExists;
  1629. else
  1630. return status;
  1631. }
  1632. /* open the new file.*/
  1633. ioreq2.irFlags = OPEN_FOR_WRITE;
  1634. ioreq2.irPath = ioreq->irPath;
  1635. checkStatus(openFile(&vol,&ioreq2));
  1636. newFile = fileTable + ioreq2.irHandle;
  1637. newFile->flags |= FILE_MODIFIED;
  1638. file->flags |= FILE_MODIFIED;
  1639. if (file->currentPosition % vol.bytesPerCluster) { /* not on a cluster boundary.*/
  1640. SectorNo sectorNo, newSectorNo, lastSector;
  1641. int i;
  1642. if((status = allocateCluster(newFile)) != flOK) {
  1643. newFile->flags = 0; /* close the new file */
  1644. return status;
  1645. }
  1646. sectorNo = firstSectorOfCluster(&vol,file->currentCluster);
  1647. newSectorNo = firstSectorOfCluster(&vol,newFile->currentCluster);
  1648. /* deal with split in a last not full cluster */
  1649. fatEntry = file->currentCluster;
  1650. checkStatus(getFATentry(&vol,&fatEntry));
  1651. if (fatEntry == FAT_LAST_CLUSTER)
  1652. lastSector = ((file->fileSize - 1) % vol.bytesPerCluster)/SECTOR_SIZE +
  1653. sectorNo;
  1654. else
  1655. lastSector = sectorNo + vol.sectorsPerCluster; /* out of the cluster */
  1656. /* copy the current cluster of the original file to the first cluster
  1657. of the new file, sector after sector.*/
  1658. for(i = 0; i < (int)vol.sectorsPerCluster; i++) {
  1659. if((status = updateSector(&vol,sectorNo, TRUE)) != flOK) {
  1660. newFile->flags = 0; /* close the new file */
  1661. return status;
  1662. }
  1663. vol.volBuffer.sectorNo = newSectorNo;
  1664. if((status = flushBuffer(&vol)) != flOK) {
  1665. newFile->flags = 0; /* close the new file */
  1666. return status;
  1667. }
  1668. sectorNo++;
  1669. newSectorNo++;
  1670. if(sectorNo > lastSector)
  1671. break;
  1672. }
  1673. fatEntry = file->currentCluster;
  1674. checkStatus(getFATentry(&vol,&fatEntry));
  1675. /* adjust the FAT chain of the new file.*/
  1676. if((status = setFATentry(&vol,newFile->currentCluster,
  1677. fatEntry)) != flOK) {
  1678. newFile->flags = 0; /* close the new file */
  1679. return status;
  1680. }
  1681. /* mark current cluster 0 (as current position).*/
  1682. newFile->currentCluster = 0;
  1683. }
  1684. else { /* on a cluster boundary.*/
  1685. DirectoryEntry *newDirEntry;
  1686. /* adjust the directory entry of the new file.*/
  1687. if((status = getDirEntryForUpdate(newFile,&newDirEntry)) != flOK) {
  1688. newFile->flags = 0; /* close the new file */
  1689. return status;
  1690. }
  1691. if (file->currentPosition) { /* split at the middle of the file.*/
  1692. fatEntry = file->currentCluster;
  1693. checkStatus(getFATentry(&vol,&fatEntry));
  1694. toLE2(newDirEntry->startingCluster, fatEntry);
  1695. setCurrentDateTime(newDirEntry);
  1696. }
  1697. else { /* split at the beginning of the file.*/
  1698. DirectoryEntry *dirEntry;
  1699. const DirectoryEntry FAR0 *dir;
  1700. dir = getDirEntry(file);
  1701. if(dir==NULL)
  1702. return flSectorNotFound;
  1703. if(dir==dataErrorToken)
  1704. return flDataError;
  1705. /* first cluster of file becomes the first cluster of the new file.*/
  1706. toLE2(newDirEntry->startingCluster,LE2(dir->startingCluster));
  1707. setCurrentDateTime(newDirEntry);
  1708. /* starting cluster of file becomes 0.*/
  1709. if((status = getDirEntryForUpdate(file, &dirEntry)) != flOK) {
  1710. newFile->flags = 0; /* close the new file */
  1711. return status;
  1712. }
  1713. toLE2(dirEntry->startingCluster, 0);
  1714. setCurrentDateTime(dirEntry);
  1715. }
  1716. }
  1717. /* adjust the size of the new file.*/
  1718. newFile->fileSize = file->fileSize - file->currentPosition +
  1719. (file->currentPosition % vol.bytesPerCluster);
  1720. /* adjust the chain and size of the original file.*/
  1721. if (file->currentPosition) /* we didn't split at the beginning.*/
  1722. if((status = setFATentry(&vol,file->currentCluster, FAT_LAST_CLUSTER)) != flOK) {
  1723. newFile->flags = 0; /* close the new file */
  1724. return status;
  1725. }
  1726. file->fileSize = file->currentPosition;
  1727. /* return to the user the handle of the new file.*/
  1728. ioreq->irHandle = ioreq2.irHandle;
  1729. return flOK;
  1730. }
  1731. #endif /* SPLIT_JOIN_FILE */
  1732. #endif /* FL_READ_ONLY */
  1733. /*----------------------------------------------------------------------*/
  1734. /* I n i t F S */
  1735. /* */
  1736. /* Initializes the FLite file system. */
  1737. /* */
  1738. /* Calling this function is optional. If it is not called, */
  1739. /* initialization will be done automatically on the first FLite call. */
  1740. /* This function is provided for those applications who want to */
  1741. /* explicitly initialize the system and get an initialization status. */
  1742. /* */
  1743. /* Calling flInit after initialization was done has no effect. */
  1744. /* */
  1745. /* Parameters: */
  1746. /* None */
  1747. /* */
  1748. /* Returns: */
  1749. /* FLStatus : 0 on success, otherwise failed */
  1750. /*----------------------------------------------------------------------*/
  1751. void initFS()
  1752. {
  1753. unsigned i;
  1754. unsigned volNo;
  1755. Volume vol = vols;
  1756. for (volNo = 0; volNo < VOLUMES; volNo++, pVol++) {
  1757. vol.volBuffer.dirty = FALSE;
  1758. vol.volBuffer.owner = NULL;
  1759. vol.volBuffer.sectorNo = UNASSIGNED_SECTOR; /* Current sector no. (none) */
  1760. vol.volBuffer.checkPoint = FALSE;
  1761. }
  1762. for (i = 0; i < FILES; i++)
  1763. fileTable[i].flags = 0;
  1764. }
  1765. #endif