Leaked source code of windows server 2003
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.

2397 lines
60 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. cvtarea.c
  5. Abstract:
  6. Creates file on a volume of specified size (bytes, kb, mb, gb, %free, %dis) at
  7. specified/random location contig/noncontig
  8. Author:
  9. Raja Sivagaminathan [sivaraja] 01/12/2000
  10. Revision History:
  11. --*/
  12. #include "CVTAREA.H"
  13. int _cdecl main(int argc, char *argv[])
  14. {
  15. FILE *file;
  16. // Global initializations
  17. gpHeadNode = NULL;
  18. gpFATNodeCount = 0;
  19. if (!ProcessCommandLine(argc, argv))
  20. {
  21. return 1;
  22. }
  23. //
  24. // check how file name is supplied
  25. //
  26. if (gsFileParam[1] != ':')
  27. {
  28. gcDrive = GetCurrentDrive();
  29. if (!gcDrive)
  30. {
  31. Mes("Unable to get current drive\n");
  32. return 1;
  33. }
  34. if (gsFileParam[0] != '\\')
  35. {
  36. strcpy(gsFileName, "\\");
  37. if (!GetCurrentDirectory(gcDrive, gsCurrentDir))
  38. {
  39. Mes("Unable to get current directory.\n");
  40. return 1;
  41. }
  42. if (gsCurrentDir[0] != 0) // may be root directory
  43. {
  44. strcat(gsFileName, gsCurrentDir);
  45. if (gsCurrentDir[strlen(gsCurrentDir) - 1] != '\\')
  46. {
  47. strcat(gsFileName, "\\");
  48. }
  49. }
  50. }
  51. else
  52. {
  53. // so that the next strcat works fine
  54. gsFileName[0] = 0;
  55. }
  56. strcat(gsFileName, gsFileParam);
  57. }
  58. else
  59. {
  60. gcDrive = gsFileParam[0];
  61. gcDrive = (BYTE) toupper((int) gcDrive);
  62. if (gcDrive < 'A' || gcDrive > 'Z')
  63. {
  64. Mes("Invalid drive name.\n");
  65. return 1;
  66. }
  67. if (gsFileParam[2] == '\\')
  68. {
  69. strcpy(gsFileName, gsFileParam+2);
  70. }
  71. else
  72. {
  73. strcpy(gsFileName, "\\");
  74. if (!GetCurrentDirectory(gcDrive, gsCurrentDir))
  75. {
  76. Mes("Unable to get current directory.\n");
  77. return 1;
  78. }
  79. if (gsCurrentDir[0] != 0) // may be root directory
  80. {
  81. strcat(gsFileName, gsCurrentDir);
  82. if (gsCurrentDir[strlen(gsCurrentDir) - 1] != '\\')
  83. {
  84. strcat(gsFileName, "\\");
  85. }
  86. }
  87. strcat(gsFileName, gsFileParam+2);
  88. }
  89. }
  90. if (gnDumpMode)
  91. {
  92. if (!LockVolume(gcDrive, READONLYLOCK))
  93. {
  94. Mes("Unable to lock volume\n");
  95. return 1;
  96. }
  97. if (!BuildDriveInfo(gcDrive, &gsDrvInfo))
  98. {
  99. return 1;
  100. }
  101. GetAllInfoOfFile(&gsDrvInfo, gsFileName, &gsFileLoc, &gsFileInfo);
  102. printf("Cluster allocation for %s\n\n", gsFileName);
  103. printf("Starting at:\tNumber of Clusters:\n\n");
  104. gnClusterFrom = gsFileLoc.StartCluster;
  105. gnClusterProgress = gnClusterFrom;
  106. gnClustersCounted = 0;
  107. while(1)
  108. {
  109. gnClusterProgressPrev = gnClusterProgress;
  110. gnClusterProgress = FindNextCluster(&gsDrvInfo, gnClusterProgress);
  111. gnClustersCounted++;
  112. //
  113. // contigous ?
  114. //
  115. if (gnClusterProgress != gnClusterProgressPrev+1)
  116. {
  117. printf("%lu\t\t%lu\n", gnClusterFrom, gnClustersCounted);
  118. gnClustersCounted = 0;
  119. gnClusterFrom = gnClusterProgress;
  120. }
  121. if (gnClusterProgress >= GetFATEOF(&gsDrvInfo) - 7)
  122. {
  123. printf("EndOfFile\n");
  124. break;
  125. }
  126. if (gnClusterProgress > gsDrvInfo.TotalClusters || gnClusterProgress < 2)
  127. {
  128. Mes("FATAL ERROR : FAT is corrupt.\n");
  129. break;
  130. }
  131. }
  132. //
  133. // All done, unlock volume
  134. //
  135. if (!UnlockVolume(gcDrive))
  136. {
  137. Mes("WARNING : Unable to unlock volume\n");
  138. //return 1;
  139. }
  140. }
  141. else
  142. {
  143. if (gnFreeSpaceDumpMode)
  144. {
  145. if (!LockVolume(gcDrive, READONLYLOCK))
  146. {
  147. Mes("Unable to lock volume\n");
  148. return 1;
  149. }
  150. if (!BuildDriveInfo(gcDrive, &gsDrvInfo))
  151. {
  152. return 1;
  153. }
  154. printf("Free Clusters on Drive %c:\n\n", gcDrive);
  155. gnClustersCounted = 0;
  156. //
  157. // locate first free cluster
  158. //
  159. gnClusterProgress = FindFreeCluster(&gsDrvInfo);
  160. if (!gnClusterProgress)
  161. {
  162. Mes("No free clusters found.\n");
  163. return 0;
  164. }
  165. printf("Starting at:\tNumber of Clusters:\n\n");
  166. for (;gnClusterProgress <= gsDrvInfo.TotalClusters; gnClusterProgress++)
  167. {
  168. if (FindNextCluster(&gsDrvInfo, gnClusterProgress) == 0)
  169. {
  170. // if this is 0 then gnClusterFrom needs to be updated
  171. if (gnClustersCounted == 0)
  172. {
  173. gnClusterFrom = gnClusterProgress;
  174. }
  175. gnClustersCounted++;
  176. }
  177. else
  178. {
  179. if (gnClustersCounted)
  180. {
  181. printf("%lu\t\t%lu\n", gnClusterFrom, gnClustersCounted);
  182. gnClustersCounted = 0;
  183. }
  184. }
  185. }
  186. //
  187. // do we still have something to print?
  188. //
  189. if (gnClustersCounted)
  190. {
  191. printf("%lu\t\t%lu\n", gnClusterFrom, gnClustersCounted);
  192. }
  193. //
  194. // All done, unlock volume
  195. //
  196. if (!UnlockVolume(gcDrive))
  197. {
  198. Mes("WARNING : Unable to unlock volume\n");
  199. //return 1;
  200. }
  201. }
  202. else
  203. {
  204. //
  205. // let DOS create a 0 length file
  206. //
  207. file = fopen(gsFileParam, "w+");
  208. if (!file)
  209. {
  210. Mes("Error creating file\n");
  211. return 1;
  212. }
  213. else
  214. {
  215. fclose(file);
  216. }
  217. if (!LockVolume(gcDrive, READWRITELOCK))
  218. {
  219. Mes("Unable to lock volume\n");
  220. return 1;
  221. }
  222. if (!BuildDriveInfo(gcDrive, &gsDrvInfo))
  223. {
  224. return 1;
  225. }
  226. GetAllInfoOfFile(&gsDrvInfo, gsFileName, &gsFileLoc, &gsFileInfo);
  227. if (gsFileLoc.Found != 1)
  228. {
  229. Mes("FATAL ERROR : Unable to locate created file\n");
  230. return 1;
  231. }
  232. //
  233. // Do all the operations requested in command line parameters
  234. //
  235. if (gbValidateFirstClusterParam)
  236. {
  237. gnFirstCluster = ConvertClusterUnit(&gsDrvInfo);
  238. if (!gnFirstCluster)
  239. {
  240. DisplayUsage();
  241. return 0;
  242. }
  243. }
  244. Mes("Computing cluster requirement...\n");
  245. gnClustersRequired = GetClustersRequired(&gsDrvInfo);
  246. printf("Clusters Required : %lu\n", gnClustersRequired);
  247. //
  248. // Check if the file size will exceed DWORD (4GB)
  249. //
  250. if ((FOURGB / (gsDrvInfo.BytesPerSector * gsDrvInfo.SectorsPerCluster)) < gnClustersRequired)
  251. {
  252. Mes("*** WARNING: Clusters required exceed FAT32 file system limit. ***\n");
  253. gnClustersRequired = FOURGB / (gsDrvInfo.BytesPerSector * gsDrvInfo.SectorsPerCluster);
  254. printf("%lu clusters (= 4GB) will be allocated.\n", gnClustersRequired);
  255. }
  256. //
  257. // if Contigous clusters required make sure they are available
  258. //
  259. if (gnContig)
  260. {
  261. Mes("Finding contigous clusters...\n");
  262. gnClusterStart = GetContigousStart(&gsDrvInfo, gnClustersRequired);
  263. if (gnClusterStart == 0)
  264. {
  265. Mes("Unable to find contigous clusters\n");
  266. return 0;
  267. }
  268. }
  269. else
  270. {
  271. gnClusterStart = gnFirstCluster;
  272. }
  273. if (gnStrictLocation && gnClusterStart != gnFirstCluster)
  274. {
  275. Mes("Unable to allocate clusters at/from the requested location\n");
  276. return 1;
  277. }
  278. //
  279. // Ready to allocate clusters and set file information
  280. //
  281. Mes("Allocating clusters...\n");
  282. gnAllocated = OccupyClusters(&gsDrvInfo, gnClusterStart, gnClustersRequired);
  283. printf("%lu clusters allocated.\n", gnAllocated);
  284. Mes("Committing FAT Sectors...\n");
  285. CcCommitFATSectors(&gsDrvInfo);
  286. //
  287. // Now set file information
  288. //
  289. Mes("Setting file information...\n");
  290. gsFileInfo.StartCluster = gnClusterStart;
  291. if (gnSizeUnit)
  292. {
  293. gsFileInfo.Size = gnAllocated * gsDrvInfo.SectorsPerCluster * gsDrvInfo.BytesPerSector;
  294. }
  295. else
  296. {
  297. if (gnAllocated != gnClustersRequired)
  298. {
  299. gsFileInfo.Size = gnAllocated * gsDrvInfo.SectorsPerCluster * gsDrvInfo.BytesPerSector;
  300. }
  301. else
  302. {
  303. gsFileInfo.Size = gnSize;
  304. }
  305. }
  306. if (!SetFileInfo(&gsDrvInfo, &gsFileLoc, &gsFileInfo))
  307. {
  308. Mes("FATAL ERROR : Error setting file information\n");
  309. return 1;
  310. }
  311. CcCommitFATSectors(&gsDrvInfo);
  312. //
  313. // All done, unlock volume
  314. //
  315. if (!UnlockVolume(gcDrive))
  316. {
  317. Mes("WARNING : Unable to unlock volume\n");
  318. //return 1;
  319. }
  320. // DeallocateLRUMRUList();
  321. // DeallocateFATCacheTree(gpHeadNode);
  322. DeallocateFATCacheList();
  323. Mes("File created successfully.\n");
  324. }
  325. }
  326. return 0;
  327. }
  328. UINT16 ProcessCommandLine(int argc, char *argv[])
  329. {
  330. UINT16 ti, tn;
  331. char sStr[50];
  332. if (argc < 3)
  333. {
  334. DisplayUsage();
  335. return 0;
  336. }
  337. //
  338. // Get FileName
  339. //
  340. strcpy(gsFileParam, argv[1]);
  341. tn = strlen(gsFileParam);
  342. //
  343. // Do simple validation
  344. //
  345. for (ti = 0; ti < tn; ti++)
  346. {
  347. if (gsFileParam[ti] == '*' || gsFileParam[ti] == '?')
  348. {
  349. DisplayUsage();
  350. return 0;
  351. }
  352. }
  353. gnDumpMode = 0;
  354. gnFreeSpaceDumpMode = 0;
  355. //
  356. // Get Size
  357. //
  358. strcpy(sStr, argv[2]);
  359. if (stricmp(sStr, "/info") == 0)
  360. {
  361. gnDumpMode = 1;
  362. //
  363. // dont accept anyother parameter if /info is entered
  364. //
  365. if (argc > 3)
  366. {
  367. DisplayUsage();
  368. return 0;
  369. }
  370. else
  371. {
  372. return 1;
  373. }
  374. }
  375. else
  376. {
  377. if (stricmp(sStr, "/freespace") == 0)
  378. {
  379. gnFreeSpaceDumpMode = 1;
  380. if (argc > 3)
  381. {
  382. DisplayUsage();
  383. return 0;
  384. }
  385. else
  386. {
  387. if (strlen(gsFileParam) > 2 ||
  388. toupper(gsFileParam[0]) < 'A' ||
  389. toupper(gsFileParam[0]) > 'Z' ||
  390. gsFileParam[1] != ':')
  391. {
  392. DisplayUsage();
  393. return 0;
  394. }
  395. return 1;
  396. }
  397. }
  398. }
  399. if (!PureNumber(sStr))
  400. {
  401. DisplayUsage();
  402. return 0;
  403. }
  404. gnSize = (UINT32) atol(sStr);
  405. if (gnSize == 0)
  406. {
  407. DisplayUsage();
  408. return 0;
  409. }
  410. gnContig = 0;
  411. gnStrictLocation = 0;
  412. gnSizeUnit = 0;
  413. gnClusterUnit = 0;
  414. gnFirstCluster = 0;
  415. gnClusterStart = 0;
  416. gbValidateFirstClusterParam = 0;
  417. for (ti = 3; ti < (UINT16) argc; ti++)
  418. {
  419. strcpy(sStr, argv[ti]);
  420. //
  421. // Check each argument if it qualifies and remember them in global variables
  422. //
  423. if (ti == 3)
  424. {
  425. if (stricmp(sStr, "KB") == 0)
  426. {
  427. gnSizeUnit = 1;
  428. continue;
  429. }
  430. else
  431. {
  432. if (stricmp(sStr, "MB") == 0)
  433. {
  434. gnSizeUnit = 2;
  435. continue;
  436. }
  437. else
  438. {
  439. if (stricmp(sStr, "GB") == 0)
  440. {
  441. gnSizeUnit = 3;
  442. continue;
  443. }
  444. else
  445. {
  446. if (stricmp(sStr, "%free") == 0)
  447. {
  448. gnSizeUnit = 4;
  449. continue;
  450. }
  451. else
  452. {
  453. if (stricmp(sStr, "%disk") == 0)
  454. {
  455. gnSizeUnit = 5;
  456. continue;
  457. }
  458. }
  459. }
  460. }
  461. }
  462. }
  463. if (stricmp(sStr, "/contig") == 0)
  464. {
  465. gnContig = 1;
  466. continue;
  467. }
  468. if (stricmp(sStr, "/firstcluster") == 0)
  469. {
  470. if ((UINT16) argc <= ti)
  471. {
  472. DisplayUsage();
  473. return 0;
  474. }
  475. else
  476. {
  477. // this parm must be a number
  478. strcpy(sStr, argv[ti+1]);
  479. if (!PureNumber(sStr))
  480. {
  481. DisplayUsage();
  482. return 0;
  483. }
  484. gnFirstCluster = atol(sStr);
  485. if (gnFirstCluster == 0)
  486. {
  487. DisplayUsage();
  488. return 0;
  489. }
  490. else
  491. {
  492. gbValidateFirstClusterParam = 1;
  493. //
  494. // look for optional unit
  495. //
  496. if ((UINT16) argc > ti + 1)
  497. {
  498. strcpy(sStr, argv[ti+2]);
  499. if (stricmp(sStr, "KB") == 0 ||
  500. stricmp(sStr, "MB") == 0 ||
  501. stricmp(sStr, "GB") == 0 ||
  502. stricmp(sStr, "/strictlocation") == 0)
  503. {
  504. if (stricmp(sStr, "KB") == 0)
  505. {
  506. gnClusterUnit = 1;
  507. }
  508. else
  509. {
  510. if (stricmp(sStr, "MB") == 0)
  511. {
  512. gnClusterUnit = 2;
  513. }
  514. else
  515. {
  516. if (stricmp(sStr, "GB") == 0)
  517. {
  518. Mes("gnClusterUnit is 3\n");
  519. gnClusterUnit = 3;
  520. }
  521. else
  522. {
  523. if (stricmp(sStr, "/strictlocation") == 0)
  524. {
  525. gnStrictLocation = 1;
  526. }
  527. }
  528. }
  529. }
  530. // if cluster unit AND /strictlocation specified
  531. if (!gnStrictLocation && (UINT16) argc > ti + 2)
  532. {
  533. strcpy(sStr, argv[ti+3]);
  534. if (stricmp(sStr, "/strictlocation") == 0)
  535. {
  536. gnStrictLocation = 1;
  537. ti+=3;
  538. continue;
  539. }
  540. }
  541. ti+=2;
  542. continue;
  543. }
  544. }
  545. ti++;
  546. continue;
  547. }
  548. }
  549. }
  550. // if it got here the command line is not recognized (junk parameter)
  551. DisplayUsage();
  552. return 0;
  553. }
  554. return 1;
  555. }
  556. UINT16 PureNumber(char *sNumStr)
  557. {
  558. UINT16 ti, tn;
  559. tn = strlen(sNumStr);
  560. for (ti = 0; ti < tn; ti++)
  561. {
  562. if (sNumStr[ti] < 48 || sNumStr[ti] > 57)
  563. {
  564. return 0;
  565. }
  566. }
  567. return 1;
  568. }
  569. void DisplayUsage(void)
  570. {
  571. Mes("Invalid parameters\n");
  572. Mes("USAGE:\n\n");
  573. Mes("CVTAREA <filename> <size> (<units>) (/contig) \n\t\t(/firstcluster <cluster> (clusunits) (/strictlocation))\n\n");
  574. Mes("\t<filename> - is a filename.\n");
  575. Mes("\t<size> - is a 32 bit integer.\n");
  576. Mes("\t<units> - is a modifier for <size> valid options are \n\t\tKB, MB, GB, ");
  577. putchar(37);
  578. // if we dont seperate this, stupid thing comes up with unrecognized escape sequence
  579. Mes("disk and ");
  580. putchar(37);
  581. // if we dont seperate this, stupid thing comes up with floating point error because of %f
  582. Mes("free\n");
  583. Mes("\t/contig - the file must be created contiguously on disk.\n");
  584. Mes("\t/firstcluster - the first cluster at which the file shall be located.\n\n\n");
  585. Mes("CVTAREA <filename> </info>\n\n");
  586. Mes("\t<filename> - is a filename.\n");
  587. Mes("\t/info - dumps cluster numbers allocated for a given file\n\n\n");
  588. Mes("CVTAREA <drivename> </freespace>\n\n");
  589. Mes("\tdrivename - is a drive letter followed by : example C:\n");
  590. Mes("\t/freespace - dumps free space chunks\n");
  591. }
  592. void Mes(char *pMessage)
  593. {
  594. printf(pMessage);
  595. }
  596. //
  597. // Sector related functions
  598. //
  599. UINT16 LockVolume(BYTE nDrive, BYTE nMode)
  600. {
  601. union _REGS inregs;
  602. union _REGS outregs;
  603. struct _SREGS segregs;
  604. // Lock volume
  605. outregs.x.cflag = 1;
  606. inregs.x.ax = 0x440d;
  607. inregs.h.bh = nMode;
  608. inregs.h.bl = nDrive - 64;
  609. inregs.h.ch = 8;
  610. inregs.h.cl = 0x4a;
  611. inregs.x.dx = 0;
  612. int86x(0x21, &inregs, &outregs, &segregs);
  613. if (outregs.x.cflag & 1)
  614. {
  615. return 0;
  616. }
  617. else
  618. {
  619. return 1;
  620. }
  621. }
  622. UINT16 UnlockVolume(BYTE nDrive)
  623. {
  624. union _REGS inregs;
  625. union _REGS outregs;
  626. struct _SREGS segregs;
  627. // Lock volume
  628. outregs.x.cflag = 1;
  629. inregs.x.ax = 0x440d;
  630. inregs.h.bl = nDrive - 64;
  631. inregs.h.ch = 8;
  632. inregs.h.cl = 0x6a;
  633. int86x(0x21, &inregs, &outregs, &segregs);
  634. if (outregs.x.cflag & 1)
  635. {
  636. return 0;
  637. }
  638. else
  639. {
  640. return 1;
  641. }
  642. }
  643. BYTE GetCurrentDrive(void)
  644. {
  645. union _REGS inregs;
  646. union _REGS outregs;
  647. inregs.h.ah = 0x19;
  648. int86(0x21, &inregs, &outregs);
  649. if (outregs.x.cflag & 1)
  650. {
  651. return 0;
  652. }
  653. return outregs.h.al + 65;
  654. }
  655. BYTE GetCurrentDirectory(BYTE nDrive, BYTE *pBuffer)
  656. {
  657. union _REGS inregs;
  658. union _REGS outregs;
  659. struct _SREGS segregs;
  660. outregs.x.cflag = 1;
  661. inregs.x.ax = 0x7147; // get current directory
  662. inregs.h.dl = nDrive - 64;
  663. segregs.ds = FP_SEG(pBuffer);
  664. inregs.x.si = FP_OFF(pBuffer);
  665. int86x(0x21, &inregs, &outregs, &segregs);
  666. if (outregs.x.cflag & 1)
  667. {
  668. // Try old method
  669. inregs.h.ah = 0x47;
  670. int86x(0x21, &inregs, &outregs, &segregs);
  671. if (outregs.x.cflag & 1)
  672. {
  673. return 0;
  674. }
  675. }
  676. return 1;
  677. }
  678. UINT16 ReadSector(BYTE nDrive, UINT32 nStartSector, UINT16 nCount, BYTE *pBuffer)
  679. {
  680. BYTE DriveNum;
  681. union _REGS inregs;
  682. union _REGS outregs;
  683. struct _SREGS segregs;
  684. ABSPACKET AbsPacket, *pAbs;
  685. // Try int 21h 7305 first
  686. pAbs = &AbsPacket;
  687. // A: = 1, B: = 2, .....
  688. DriveNum = nDrive - 65;
  689. Tx.e.evx = 0;
  690. Tx.e.evx = nStartSector;
  691. AbsPacket.SectorLow = Tx.x.vx;
  692. AbsPacket.SectorHigh = Tx.x.xvx;
  693. AbsPacket.SectorCount = nCount;
  694. AbsPacket.BufferOffset = FP_OFF(pBuffer);
  695. AbsPacket.BufferSegment = FP_SEG(pBuffer);
  696. segregs.ds = FP_SEG(pAbs);
  697. segregs.es = FP_SEG(pAbs);
  698. inregs.x.bx = FP_OFF(pAbs);
  699. inregs.x.cx = 0xffff;
  700. inregs.h.dl = nDrive-64;
  701. inregs.x.ax = 0x7305;
  702. //
  703. // Read mode SI = 0
  704. //
  705. inregs.x.si = 0;
  706. outregs.x.ax = 0;
  707. outregs.x.cflag = 0;
  708. int86x(0x21, &inregs, &outregs, &segregs);
  709. if (outregs.x.cflag & 0x1)
  710. {
  711. goto ErrorRead;
  712. }
  713. return 1;
  714. ErrorRead:
  715. return 0;
  716. }
  717. UINT16 WriteSector(BYTE nDrive, UINT32 nStartSector, UINT16 nCount, BYTE *pBuffer)
  718. {
  719. BYTE DriveNum;
  720. union _REGS inregs;
  721. union _REGS outregs;
  722. struct _SREGS segregs;
  723. ABSPACKET AbsPacket, *pAbs;
  724. // Try int 21h 7305 first
  725. pAbs = &AbsPacket;
  726. // A: = 1, B: = 2, .....
  727. DriveNum = nDrive - 65;
  728. Tx.e.evx = 0;
  729. Tx.e.evx = nStartSector;
  730. AbsPacket.SectorLow = Tx.x.vx;
  731. AbsPacket.SectorHigh = Tx.x.xvx;
  732. AbsPacket.SectorCount = nCount;
  733. AbsPacket.BufferOffset = FP_OFF(pBuffer);
  734. AbsPacket.BufferSegment = FP_SEG(pBuffer);
  735. segregs.ds = FP_SEG(pAbs);
  736. segregs.es = FP_SEG(pAbs);
  737. inregs.x.bx = FP_OFF(pAbs);
  738. inregs.x.cx = 0xffff;
  739. inregs.h.dl = nDrive-64;
  740. inregs.x.ax = 0x7305;
  741. //
  742. // Write mode SI != 0 (bit 1 set)
  743. //
  744. inregs.x.si = 1;
  745. outregs.x.ax = 0;
  746. outregs.x.cflag = 0;
  747. int86x(0x21, &inregs, &outregs, &segregs);
  748. if (outregs.x.cflag & 0x1)
  749. {
  750. goto ErrorWrite;
  751. }
  752. return 1;
  753. ErrorWrite:
  754. return 0;
  755. }
  756. //
  757. // Boot related functions
  758. //
  759. UINT16 BuildDriveInfo(BYTE Drive, BPBINFO *pDrvInfo)
  760. {
  761. BYTE *pSector;
  762. pSector = (BYTE *) malloc(1024);
  763. if (!pSector)
  764. {
  765. Mes("Memory allocation error\n");
  766. return 0;
  767. }
  768. //
  769. // Although FAT32 boot sector spans two sectors BPB is contained in the first sector
  770. // So we only read one sector
  771. //
  772. if (!ReadSector(Drive, 0, 1, pSector))
  773. {
  774. Mes("Unable to read boot sector\n");
  775. return 0;
  776. }
  777. if ((strncmp(pSector+54, "FAT16 ", 8) == 0) || strncmp(pSector+54, "FAT12 ", 8) == 0)
  778. {
  779. GetFATBPBInfo(pSector, pDrvInfo);
  780. }
  781. else
  782. {
  783. if (strncmp(pSector+82, "FAT32 ", 8) == 0)
  784. {
  785. GetFAT32BPBInfo(pSector, pDrvInfo);
  786. }
  787. else
  788. {
  789. Mes("Unsupported file system\n");
  790. return 0;
  791. }
  792. }
  793. free(pSector);
  794. if (!pDrvInfo->ReliableInfo)
  795. {
  796. Mes("Drive is either corrupted or unable to get BPB Info\n");
  797. }
  798. pDrvInfo->Drive = Drive;
  799. return 1;
  800. }
  801. UINT16 GetFATBPBInfo(BYTE *pBootSector, BPBINFO *pDrvInfo)
  802. {
  803. pDrvInfo->ReliableInfo = 0;
  804. if (pBootSector[510] != 0x55 || pBootSector[511] != 0xAA)
  805. {
  806. Mes("Invalid boot sector\n");
  807. return 0;
  808. }
  809. else
  810. {
  811. pDrvInfo->BytesPerSector = (pBootSector[0x0c] << 8) | pBootSector[0x0b];
  812. if (pDrvInfo->BytesPerSector == 0) // Just be safe
  813. {
  814. Mes("Invalid boot sector\n");
  815. return 0;
  816. }
  817. pDrvInfo->SectorsPerCluster = pBootSector[0x0d];
  818. if (pDrvInfo->SectorsPerCluster == 0) // Just be safe
  819. {
  820. Mes("Invalid boot sector\n");
  821. return 0;
  822. }
  823. pDrvInfo->ReservedBeforeFAT = (pBootSector[0x0f] << 8) | pBootSector[0x0e];
  824. pDrvInfo->FATCount = pBootSector[0x10];
  825. if (pDrvInfo->FATCount == 0) // Just be safe
  826. {
  827. Mes("Invalid boot sector\n");
  828. return 0;
  829. }
  830. pDrvInfo->MaxRootDirEntries = (pBootSector[0x12] << 8) | pBootSector[0x11];
  831. pDrvInfo->TotalSectors = (pBootSector[0x14] << 8) | pBootSector[0x13];
  832. pDrvInfo->MediaID = pBootSector[0x15];
  833. pDrvInfo->SectorsPerFAT = (pBootSector[0x17] << 8) | pBootSector[0x16];
  834. if (pDrvInfo->SectorsPerFAT == 0) // Just be safe
  835. {
  836. Mes("Invalid boot sector\n");
  837. return 0;
  838. }
  839. pDrvInfo->SectorsPerTrack = (pBootSector[0x19] << 8) | pBootSector[0x18];
  840. pDrvInfo->Heads = (pBootSector[0x1b] << 8) | pBootSector[0x1a];
  841. pDrvInfo->HiddenSectors = (pBootSector[0x1d] << 8) | pBootSector[0x1c];
  842. Rx.h.vl = pBootSector[0x20]; Rx.h.vh = pBootSector[0x21]; Rx.h.xvl = pBootSector[0x22];Rx.h.xvh = pBootSector[0x23];
  843. pDrvInfo->BigTotalSectors = Rx.e.evx;
  844. pDrvInfo->RootDirCluster = 0;
  845. //
  846. // The following informations are useful and are not directly from Boot sector
  847. //
  848. pDrvInfo->TotalRootDirSectors = ((pDrvInfo->MaxRootDirEntries * 32) / 512) + 1;
  849. if (((pDrvInfo->MaxRootDirEntries * 32) % 512) == 0)
  850. {
  851. pDrvInfo->TotalRootDirSectors--;
  852. }
  853. pDrvInfo->TotalSystemSectors = (UINT32)pDrvInfo->ReservedBeforeFAT + (UINT32)pDrvInfo->FATCount * (UINT32)pDrvInfo->SectorsPerFAT + (UINT32) pDrvInfo->TotalRootDirSectors;
  854. pDrvInfo->FirstRootDirSector = (UINT32)((UINT32)pDrvInfo->ReservedBeforeFAT + (UINT32)pDrvInfo->FATCount * (UINT32)pDrvInfo->SectorsPerFAT);
  855. //
  856. // If TotalSectors is zero then the actual total sectors value is in BigTotalSectors
  857. // and it means the drive is BIGDOS (> 32MB).
  858. //
  859. if (pDrvInfo->TotalSectors == 0)
  860. {
  861. pDrvInfo->TotalClusters = ((pDrvInfo->BigTotalSectors - pDrvInfo->TotalSystemSectors) / pDrvInfo->SectorsPerCluster) + 2 - 1; // +2 Because clusters starts from 2
  862. }
  863. else
  864. {
  865. pDrvInfo->TotalClusters = ((pDrvInfo->TotalSectors - pDrvInfo->TotalSystemSectors) / pDrvInfo->SectorsPerCluster) + 2 - 1; // +2 because clusters starts from 2
  866. }
  867. //
  868. // Determine the fat type
  869. //
  870. if (pDrvInfo->TotalClusters <= 4096)
  871. {
  872. pDrvInfo->FATType = 12;
  873. }
  874. else
  875. {
  876. pDrvInfo->FATType = 16;
  877. }
  878. }
  879. //
  880. // Validate all the info above
  881. //
  882. if (pDrvInfo->FATCount == 2 && pDrvInfo->SectorsPerFAT != 0 &&
  883. pDrvInfo->SectorsPerCluster != 0 && pDrvInfo->BytesPerSector == 512 &&
  884. (pDrvInfo->TotalSectors != 0 || pDrvInfo->BigTotalSectors != 0) &&
  885. pDrvInfo->ReservedBeforeFAT != 0)
  886. {
  887. pDrvInfo->ReliableInfo = 1;
  888. }
  889. return 1;
  890. }
  891. UINT16 GetFAT32BPBInfo(BYTE *pBootSector, BPBINFO *pDrvInfo)
  892. {
  893. pDrvInfo->ReliableInfo = 0;
  894. if (pBootSector[510] != 0x55 || pBootSector[511] != 0xAA)
  895. {
  896. Mes("Invalid boot sector\n");
  897. return 0;
  898. }
  899. else
  900. {
  901. //
  902. // Build the drive information now
  903. //
  904. pDrvInfo->BytesPerSector = (pBootSector[0x0c] << 8) | pBootSector[0x0b];
  905. pDrvInfo->SectorsPerCluster = pBootSector[0x0d];
  906. pDrvInfo->ReservedBeforeFAT = (pBootSector[0x0f] << 8) | pBootSector[0x0e];
  907. pDrvInfo->FATCount = pBootSector[0x10];
  908. pDrvInfo->MaxRootDirEntries = (pBootSector[0x12] << 8) | pBootSector[0x11];
  909. pDrvInfo->TotalSectors = 0;
  910. pDrvInfo->MediaID = pBootSector[0x15];
  911. pDrvInfo->SectorsPerTrack = (pBootSector[0x19] << 8) | pBootSector[0x18];
  912. pDrvInfo->Heads = (pBootSector[0x1b] << 8) | pBootSector[0x1a];
  913. Rx.h.vl = pBootSector[0x1c]; Rx.h.vh = pBootSector[0x1d]; Rx.h.xvl = pBootSector[0x1e];Rx.h.xvh = pBootSector[0x1f];
  914. pDrvInfo->HiddenSectors = Rx.e.evx;
  915. Rx.h.vl = pBootSector[0x20]; Rx.h.vh = pBootSector[0x21]; Rx.h.xvl = pBootSector[0x22];Rx.h.xvh = pBootSector[0x23];
  916. pDrvInfo->BigTotalSectors = Rx.e.evx;
  917. Rx.h.vl = pBootSector[0x24]; Rx.h.vh = pBootSector[0x25]; Rx.h.xvl = pBootSector[0x26];Rx.h.xvh = pBootSector[0x27];
  918. pDrvInfo->SectorsPerFAT = Rx.e.evx;
  919. Rx.h.vl = pBootSector[0x2c]; Rx.h.vh = pBootSector[0x2d]; Rx.h.xvl = pBootSector[0x2e];Rx.h.xvh = pBootSector[0x2f];
  920. pDrvInfo->RootDirCluster = Rx.e.evx;
  921. //
  922. // The following informations are useful and are not directly from the Boot sector
  923. //
  924. pDrvInfo->TotalSystemSectors = (UINT32)((UINT32)pDrvInfo->ReservedBeforeFAT + (UINT32)pDrvInfo->FATCount * (UINT32) pDrvInfo->SectorsPerFAT);
  925. pDrvInfo->FirstRootDirSector = (UINT32)((UINT32)pDrvInfo->TotalSystemSectors + (UINT32)(pDrvInfo->RootDirCluster - 2) * (UINT32)pDrvInfo->SectorsPerCluster + 1);
  926. pDrvInfo->TotalClusters = ((pDrvInfo->BigTotalSectors - pDrvInfo->TotalSystemSectors) / pDrvInfo->SectorsPerCluster) + 2 - 1; // +2 Because clusters starts from 2
  927. pDrvInfo->FATType = 32;
  928. //
  929. // Validate all the info above
  930. //
  931. if (pDrvInfo->FATCount == 2 && pDrvInfo->SectorsPerFAT != 0 &&
  932. pDrvInfo->SectorsPerCluster != 0 && pDrvInfo->BytesPerSector == 512 &&
  933. (pDrvInfo->TotalSectors != 0 || pDrvInfo->BigTotalSectors != 0) &&
  934. pDrvInfo->ReservedBeforeFAT != 0)
  935. {
  936. pDrvInfo->ReliableInfo = 1;
  937. }
  938. }
  939. return 1;
  940. }
  941. UINT16 AddNode(PNODE pNode)
  942. {
  943. if (!pNode)
  944. {
  945. return 1;
  946. }
  947. if (!gpHeadNode)
  948. {
  949. gpHeadNode = pNode;
  950. gpTailNode = pNode;
  951. pNode->Back = NULL;
  952. pNode->Next = NULL;
  953. }
  954. else
  955. {
  956. pNode->Next = gpHeadNode;
  957. pNode->Back = NULL;
  958. gpHeadNode->Back = pNode;
  959. gpHeadNode = pNode;
  960. }
  961. return 1;
  962. }
  963. PNODE FindNode(UINT32 nSector)
  964. {
  965. PNODE pNode;
  966. if (!gpHeadNode)
  967. {
  968. return NULL;
  969. }
  970. pNode = gpHeadNode;
  971. while (pNode)
  972. {
  973. if (pNode->Sector == nSector)
  974. {
  975. break;
  976. }
  977. pNode = pNode->Next;
  978. }
  979. return pNode;
  980. }
  981. PNODE RemoveNode(void)
  982. {
  983. // Removes last node
  984. PNODE pNode;
  985. if (!gpTailNode)
  986. {
  987. return NULL;
  988. }
  989. pNode = gpTailNode;
  990. gpTailNode = pNode->Back;
  991. pNode->Back = NULL;
  992. if (gpTailNode)
  993. {
  994. gpTailNode->Next = NULL;
  995. }
  996. return pNode;
  997. }
  998. void DeallocateFATCacheList(void)
  999. {
  1000. PNODE pNode;
  1001. while (gpHeadNode)
  1002. {
  1003. pNode = gpHeadNode;
  1004. gpHeadNode = gpHeadNode->Next;
  1005. free(pNode->Buffer);
  1006. free(pNode);
  1007. }
  1008. }
  1009. //
  1010. // Functions related to FAT caching
  1011. //
  1012. BYTE *CcReadFATSector(BPBINFO *pDrvInfo, UINT32 nFATSector)
  1013. {
  1014. // Locate nFATSector in the cache
  1015. PNODE pNode;
  1016. pNode = FindNode(nFATSector);
  1017. if (!pNode)
  1018. {
  1019. //
  1020. // If MAXCACHE reached use LRU MRU scheme
  1021. //
  1022. if (gpFATNodeCount < MAXCACHE)
  1023. {
  1024. pNode = malloc(sizeof(NODE)+5);
  1025. if (!pNode)
  1026. {
  1027. return NULL;
  1028. }
  1029. pNode->Buffer = malloc(512);
  1030. if (!pNode->Buffer)
  1031. {
  1032. return NULL;
  1033. }
  1034. ReadSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + nFATSector, 1, pNode->Buffer);
  1035. pNode->Sector = nFATSector;
  1036. pNode->Dirty = 0;
  1037. AddNode(pNode);
  1038. gpFATNodeCount++;
  1039. }
  1040. else
  1041. {
  1042. // RemoveLRUMakeMRU(gpLRU->Node);
  1043. // pNode = gpMRU->Node;
  1044. pNode = RemoveNode();
  1045. if (pNode->Dirty)
  1046. {
  1047. WriteSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + pNode->Sector, 1, pNode->Buffer);
  1048. WriteSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + pDrvInfo->SectorsPerFAT + pNode->Sector, 1, pNode->Buffer);
  1049. }
  1050. pNode->Sector = nFATSector;
  1051. ReadSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + nFATSector, 1, pNode->Buffer);
  1052. AddNode(pNode);
  1053. }
  1054. }
  1055. return pNode->Buffer;
  1056. }
  1057. UINT16 CcWriteFATSector(BPBINFO *pDrvInfo, UINT32 nFATSector)
  1058. {
  1059. PNODE pNode;
  1060. pNode = FindNode(nFATSector);
  1061. if (!pNode)
  1062. {
  1063. // must be found, because every FAT node we write must gone thru CcReadFATSector first
  1064. return 0;
  1065. }
  1066. else
  1067. {
  1068. pNode->Dirty = 1;
  1069. }
  1070. }
  1071. void CcCommitFATSectors(BPBINFO *pDrvInfo)
  1072. {
  1073. PNODE pNode;
  1074. if (!gpHeadNode)
  1075. {
  1076. return;
  1077. }
  1078. pNode = gpHeadNode;
  1079. while (pNode)
  1080. {
  1081. if (pNode->Dirty)
  1082. {
  1083. // 1st FAT copy
  1084. WriteSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + pNode->Sector, 1, pNode->Buffer);
  1085. // 2nd FAT copy
  1086. WriteSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + pDrvInfo->SectorsPerFAT + pNode->Sector, 1, pNode->Buffer);
  1087. pNode->Dirty = 0;
  1088. }
  1089. pNode = pNode->Next;
  1090. }
  1091. return;
  1092. }
  1093. //
  1094. // FAT related functions
  1095. //
  1096. UINT32 FindNextCluster(BPBINFO *pDrvInfo,UINT32 CurrentCluster)
  1097. {
  1098. UINT32 ToRead;
  1099. UINT32 SeekOffset;
  1100. BYTE JustAByte;
  1101. Rx.e.evx = 0;
  1102. switch (pDrvInfo->FATType)
  1103. {
  1104. case 12:
  1105. ToRead = (CurrentCluster*3/2)/512;
  1106. PettyFATSector = CcReadFATSector(pDrvInfo, ToRead);
  1107. //**ReadSector(DrvInfo->Drive, DrvInfo->ReservedBeforeFAT + ToRead, 1, (BYTE *) PettyFATSector);
  1108. //
  1109. // Go to that cluster location
  1110. //
  1111. SeekOffset = (CurrentCluster*3/2) % 512;
  1112. if ((CurrentCluster % 2) == 0) // if even
  1113. {
  1114. JustAByte = (BYTE) (PettyFATSector[SeekOffset+1] & 0x0f);
  1115. Rx.h.vl = PettyFATSector[SeekOffset]; Rx.h.vh = JustAByte;
  1116. }
  1117. else // if cluster number is odd the calculation is different
  1118. {
  1119. JustAByte = (BYTE) (PettyFATSector[SeekOffset] & 0xf0);
  1120. Rx.h.vl = JustAByte; Rx.h.vh = PettyFATSector[SeekOffset+1];
  1121. Rx.x.vx >>= 4;
  1122. }
  1123. Rx.h.xvl = 0; Rx.h.xvh = 0;
  1124. break;
  1125. case 16:
  1126. ToRead = CurrentCluster/256; // 256 cells in a 16 bit FAT sector
  1127. PettyFATSector = CcReadFATSector(pDrvInfo, ToRead);
  1128. //**ReadSector(DrvInfo->Drive, DrvInfo->ReservedBeforeFAT + ToRead, 1, (BYTE *)PettyFATSector);
  1129. //
  1130. // Go to that Cluster location
  1131. //
  1132. SeekOffset = (CurrentCluster - (ToRead * 256)) * 2;
  1133. Rx.h.vl = PettyFATSector[SeekOffset]; Rx.h.vh = PettyFATSector[SeekOffset+1];
  1134. Rx.h.xvl = 0; Rx.h.xvh = 0;
  1135. break;
  1136. case 32:
  1137. ToRead = CurrentCluster/128; // 128 cells in a 32 bit FAT sector
  1138. PettyFATSector = CcReadFATSector(pDrvInfo, ToRead);
  1139. //**ReadSector(DrvInfo->Drive, DrvInfo->ReservedBeforeFAT + ToRead, 1, (BYTE *)PettyFATSector);
  1140. //
  1141. // Go to that Cluster location
  1142. //
  1143. SeekOffset = (CurrentCluster - (ToRead * 128)) * 4;
  1144. Rx.h.vl = PettyFATSector[SeekOffset]; Rx.h.vh = PettyFATSector[SeekOffset+1];
  1145. Rx.h.xvl = PettyFATSector[SeekOffset+2]; Rx.h.xvh = PettyFATSector[SeekOffset+3];
  1146. break;
  1147. default:
  1148. Rx.e.evx = 0;
  1149. break;
  1150. }
  1151. return Rx.e.evx;
  1152. }
  1153. UINT16 UpdateFATLocation(BPBINFO *pDrvInfo, UINT32 CurrentCluster,UINT32 PointingValue)
  1154. {
  1155. UINT32 ToRead;
  1156. UINT32 SeekOffset;
  1157. if (CurrentCluster == 0 || CurrentCluster == 1 || CurrentCluster >= (GetFATEOF(pDrvInfo)-7))
  1158. {
  1159. return 0;
  1160. }
  1161. switch (pDrvInfo->FATType)
  1162. {
  1163. case 12:
  1164. ToRead = (CurrentCluster*3/2)/512;
  1165. PettyFATSector = CcReadFATSector(pDrvInfo, ToRead);
  1166. //**ReadSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + ToRead, 1, PettyFATSector);
  1167. //
  1168. // Go to that location
  1169. //
  1170. SeekOffset = (CurrentCluster*3/2) % 512;
  1171. if ((CurrentCluster % 2) == 0) // if even
  1172. {
  1173. Rx.e.evx = 0;
  1174. Rx.x.vx = (UINT16) PointingValue;
  1175. PettyFATSector[SeekOffset+1] = (BYTE) (PettyFATSector[SeekOffset+1] & 0xf0);
  1176. Rx.h.vh = (BYTE) (Rx.h.vh & 0x0f);
  1177. PettyFATSector[SeekOffset+1] = PettyFATSector[SeekOffset+1] | Rx.h.vh;
  1178. PettyFATSector[SeekOffset] = Rx.h.vl;
  1179. }
  1180. else // if cluster number is odd the calculation is different
  1181. {
  1182. Rx.e.evx = 0;
  1183. Rx.x.vx = (UINT16) PointingValue;
  1184. PettyFATSector[SeekOffset] = (BYTE)(PettyFATSector[SeekOffset] & 0x0f);
  1185. Rx.h.vl = (BYTE) (Rx.h.vl & 0xf0);
  1186. PettyFATSector[SeekOffset] = PettyFATSector[SeekOffset] | Rx.h.vl;
  1187. PettyFATSector[SeekOffset+1] = Rx.h.vh;
  1188. }
  1189. break;
  1190. case 16:
  1191. ToRead = CurrentCluster/256; // 256 cells in a 16 bit FAT sector
  1192. PettyFATSector = CcReadFATSector(pDrvInfo, ToRead);
  1193. //**ReadSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + ToRead, 1, PettyFATSector);
  1194. //
  1195. // Go to that location
  1196. //
  1197. SeekOffset = (CurrentCluster % 256) * 2;
  1198. Rx.e.evx = 0;
  1199. Rx.x.vx = (UINT16) PointingValue;
  1200. PettyFATSector[SeekOffset] = Rx.h.vl;PettyFATSector[SeekOffset+1] = Rx.h.vh;
  1201. break;
  1202. case 32:
  1203. ToRead = CurrentCluster/128; // 128 cells in a 32 bit FAT sector
  1204. PettyFATSector = CcReadFATSector(pDrvInfo, ToRead);
  1205. //**ReadSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + ToRead, 1, PettyFATSector);
  1206. //
  1207. // Go to that location
  1208. //
  1209. SeekOffset = (CurrentCluster % 128) * 4;
  1210. Rx.e.evx = 0;
  1211. Rx.e.evx = PointingValue;
  1212. PettyFATSector[SeekOffset] = Rx.h.vl; PettyFATSector[SeekOffset+1] = Rx.h.vh;
  1213. PettyFATSector[SeekOffset+2] = Rx.h.xvl; PettyFATSector[SeekOffset+3] = Rx.h.xvh;
  1214. break;
  1215. default:
  1216. return 0;
  1217. }
  1218. CcWriteFATSector(pDrvInfo, ToRead);
  1219. //**Update FAT 1st Copy
  1220. //WriteSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + ToRead, 1, PettyFATSector);
  1221. // Update FAT 2nd Copy
  1222. //**WriteSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + pDrvInfo->SectorsPerFAT + ToRead, 1, PettyFATSector);
  1223. return 1;
  1224. }
  1225. UINT32 FindFreeCluster(BPBINFO *pDrvInfo)
  1226. {
  1227. UINT32 ti, tj;
  1228. UINT32 FreeCluster;
  1229. UINT32 SeekOffset;
  1230. if (pDrvInfo->FATType == 12)
  1231. {
  1232. //
  1233. // Instead of messing up with FAT16 and FAT32's smooth operation use the slow method
  1234. //
  1235. for (ti = 2; ti <= pDrvInfo->TotalClusters; ti++)
  1236. {
  1237. //
  1238. // this just aint gonna slow down things on a huge 2MB FAT12 partition
  1239. //
  1240. if (FindNextCluster(pDrvInfo, ti) == 0)
  1241. {
  1242. LastClusterAllocated = ti;
  1243. return ti;
  1244. }
  1245. }
  1246. return 0;
  1247. }
  1248. else
  1249. {
  1250. // ** this part was developed before FAT caching was implemented... and the purpose was
  1251. // for better performance
  1252. // But with FAT caching it is even better or no difference at all, so this part is left alone.
  1253. //
  1254. // Start looking from Cluster 2
  1255. //
  1256. FreeCluster = 2;
  1257. for (ti = 1; ti <= pDrvInfo->SectorsPerFAT; ti++)
  1258. {
  1259. //**if (!ReadSector(pDrvInfo->Drive, pDrvInfo->ReservedBeforeFAT + ti-1, 1, PettyFATSector))
  1260. PettyFATSector = CcReadFATSector(pDrvInfo, ti-1);
  1261. if (!PettyFATSector)
  1262. {
  1263. return 0;
  1264. }
  1265. tj = 0;
  1266. while (tj < 512)
  1267. {
  1268. switch (pDrvInfo->FATType)
  1269. {
  1270. case 16:
  1271. SeekOffset = (FreeCluster * 2) % (UINT32) 512;
  1272. if (PettyFATSector[SeekOffset] == 0 && PettyFATSector[SeekOffset+1] == 0)
  1273. {
  1274. LastClusterAllocated = FreeCluster;
  1275. return FreeCluster;
  1276. }
  1277. tj += 2;
  1278. break;
  1279. case 32:
  1280. SeekOffset = (FreeCluster * 4) % (UINT32) 512;
  1281. if (PettyFATSector[SeekOffset] == 0 && PettyFATSector[SeekOffset+1] == 0
  1282. && PettyFATSector[SeekOffset+2] == 0 && PettyFATSector[SeekOffset+3] == 0)
  1283. {
  1284. LastClusterAllocated = FreeCluster;
  1285. return FreeCluster;
  1286. }
  1287. tj += 4;
  1288. break;
  1289. default:
  1290. return 0;
  1291. }
  1292. FreeCluster++;
  1293. if (FreeCluster > pDrvInfo->TotalClusters)
  1294. {
  1295. return 0;
  1296. }
  1297. }
  1298. }
  1299. return 0;
  1300. }
  1301. }
  1302. UINT32 QFindFreeCluster(BPBINFO *pDrvInfo)
  1303. {
  1304. // LastClusterAllocated is critical for this function to work fast.
  1305. // It starts from LastClusterAllocated+1 to find a free cluster and calls
  1306. // the regular FindFreeCluster if did not find a free cluster between
  1307. // LastClusterAllocated+1 and TotalClusters
  1308. UINT32 ti;
  1309. UINT32 FreeCluster;
  1310. FreeCluster = 0;
  1311. for (ti = LastClusterAllocated+1; ti <= pDrvInfo->TotalClusters; ti++)
  1312. {
  1313. if (FindNextCluster(pDrvInfo, ti) == 0)
  1314. {
  1315. LastClusterAllocated = ti;
  1316. return ti;
  1317. }
  1318. }
  1319. if (FreeCluster == 0)
  1320. {
  1321. FreeCluster = FindFreeCluster(pDrvInfo);
  1322. }
  1323. return FreeCluster;
  1324. }
  1325. UINT32 GetFATEOF(BPBINFO *pDrvInfo)
  1326. {
  1327. UINT32 FATEOF;
  1328. switch (pDrvInfo->FATType)
  1329. {
  1330. case 12:
  1331. FATEOF = 0x0fff;
  1332. break;
  1333. case 16:
  1334. FATEOF = 0xffff;
  1335. break;
  1336. case 32:
  1337. FATEOF = 0x0fffffff;
  1338. break;
  1339. }
  1340. return FATEOF;
  1341. }
  1342. UINT32 GetFreeClusters(BPBINFO *pDrvInfo)
  1343. {
  1344. UINT32 nCount;
  1345. UINT32 ti;
  1346. nCount = 0;
  1347. for (ti = 2; ti <= pDrvInfo->TotalClusters; ti++)
  1348. {
  1349. if (FindNextCluster(pDrvInfo, ti) == 0)
  1350. {
  1351. nCount++;
  1352. }
  1353. }
  1354. return nCount;
  1355. }
  1356. UINT32 ConvertClusterUnit(BPBINFO *pDrvInfo)
  1357. {
  1358. //
  1359. // one KB = 2 sectors, we use 2 to avoid get thru overflow as much as possible (although we have overflow check)
  1360. // when gnClusterUnit is not 0, it means a start location from the beginning of the disk BY SIZE.
  1361. // for example, if "/firstcluster 1 GB" is specified, it means start from a cluster after (skipping)
  1362. // 1 GB space from the beginning of the disk
  1363. //
  1364. UINT32 nFirstCluster;
  1365. nFirstCluster = gnFirstCluster;
  1366. switch (gnClusterUnit)
  1367. {
  1368. case 0:
  1369. // do nothing
  1370. break;
  1371. case 1: // Start Cluster unit specified in KB
  1372. if (nFirstCluster < 0x80000000) // overflow check
  1373. {
  1374. nFirstCluster = ((nFirstCluster * 2) / pDrvInfo->SectorsPerCluster) + 2;
  1375. }
  1376. else
  1377. {
  1378. nFirstCluster = 0;
  1379. }
  1380. break;
  1381. case 2: // Start Cluster unit specified in MB
  1382. if (nFirstCluster < 0x200000) // overflow check
  1383. {
  1384. nFirstCluster = ((nFirstCluster * 2 * 1024) / pDrvInfo->SectorsPerCluster) + 2;
  1385. }
  1386. else
  1387. {
  1388. nFirstCluster = 0;
  1389. }
  1390. break;
  1391. case 3: // Start Cluster unit specified in GB
  1392. if (nFirstCluster < 0x800) // overflow check
  1393. {
  1394. nFirstCluster = ((nFirstCluster * 2 * 1024 * 1024) / pDrvInfo->SectorsPerCluster) + 2;
  1395. }
  1396. else
  1397. {
  1398. nFirstCluster = 0;
  1399. }
  1400. break;
  1401. default:
  1402. // do nothing
  1403. break;
  1404. }
  1405. if ((nFirstCluster > pDrvInfo->TotalClusters) || (nFirstCluster < 2))
  1406. {
  1407. nFirstCluster = 0;
  1408. }
  1409. return nFirstCluster;
  1410. }
  1411. UINT32 GetClustersRequired(BPBINFO *pDrvInfo)
  1412. {
  1413. UINT32 nClustersRequired;
  1414. UINT32 nDriveClusterSize;
  1415. UINT32 tnSize;
  1416. nDriveClusterSize = (UINT32) pDrvInfo->SectorsPerCluster * (UINT32) pDrvInfo->BytesPerSector;
  1417. tnSize = gnSize;
  1418. //
  1419. // calcs looks vague, but we try to avoid as much overflow as possible
  1420. //
  1421. switch (gnSizeUnit)
  1422. {
  1423. case 0: //bytes
  1424. nClustersRequired = tnSize / nDriveClusterSize;
  1425. if (tnSize % nDriveClusterSize)
  1426. {
  1427. nClustersRequired++;
  1428. }
  1429. break;
  1430. case 1: //KB
  1431. if (nDriveClusterSize >= 1024)
  1432. {
  1433. nClustersRequired = tnSize / (nDriveClusterSize / 1024);
  1434. if (tnSize % (nDriveClusterSize / 1024))
  1435. {
  1436. nClustersRequired++;
  1437. }
  1438. }
  1439. else
  1440. {
  1441. // Here we go by sectors, still trying to avoid overflow
  1442. tnSize = tnSize * 2; // sectors
  1443. nClustersRequired = tnSize / pDrvInfo->SectorsPerCluster;
  1444. if (tnSize % pDrvInfo->SectorsPerCluster)
  1445. {
  1446. nClustersRequired++;
  1447. }
  1448. }
  1449. break;
  1450. case 2: // MB
  1451. if (nDriveClusterSize >= 1024)
  1452. {
  1453. tnSize = tnSize * 1024;
  1454. nClustersRequired = tnSize / (nDriveClusterSize / 1024);
  1455. if (tnSize % (nDriveClusterSize / 1024))
  1456. {
  1457. nClustersRequired++;
  1458. }
  1459. }
  1460. else
  1461. {
  1462. tnSize = tnSize * 2 * 1024; //sectors
  1463. nClustersRequired = tnSize / pDrvInfo->SectorsPerCluster;
  1464. if (tnSize % pDrvInfo->SectorsPerCluster)
  1465. {
  1466. nClustersRequired++;
  1467. }
  1468. }
  1469. break;
  1470. case 3: // GB
  1471. if (nDriveClusterSize >= 1024)
  1472. {
  1473. tnSize = tnSize * 1024 * 1024;
  1474. nClustersRequired = tnSize / (nDriveClusterSize / 1024);
  1475. if (tnSize % (nDriveClusterSize / 1024))
  1476. {
  1477. nClustersRequired++;
  1478. }
  1479. }
  1480. else
  1481. {
  1482. tnSize = tnSize * 2 * 1024 * 1024; //sectors
  1483. nClustersRequired = tnSize / pDrvInfo->SectorsPerCluster;
  1484. if (tnSize % pDrvInfo->SectorsPerCluster)
  1485. {
  1486. nClustersRequired++;
  1487. }
  1488. }
  1489. break;
  1490. case 4:
  1491. // based on percentage free
  1492. nClustersRequired = GetFreeClusters(pDrvInfo);
  1493. nClustersRequired = nClustersRequired / 100;
  1494. nClustersRequired = nClustersRequired * gnSize;
  1495. break;
  1496. case 5:
  1497. // based on percentage disk size
  1498. nClustersRequired = pDrvInfo->TotalClusters;
  1499. nClustersRequired = nClustersRequired / 100;
  1500. nClustersRequired = nClustersRequired * gnSize;
  1501. break;
  1502. }
  1503. return nClustersRequired;
  1504. }
  1505. UINT32 GetContigousStart(BPBINFO *pDrvInfo, UINT32 nClustersRequired)
  1506. {
  1507. UINT32 ti;
  1508. UINT32 nContigousStart;
  1509. if (gnFirstCluster == 0)
  1510. {
  1511. nContigousStart = 2;
  1512. }
  1513. else
  1514. {
  1515. nContigousStart = gnFirstCluster;
  1516. }
  1517. //
  1518. // -2 is adjustment value, because cluster value starts at 2
  1519. //
  1520. while ((nContigousStart-2+nClustersRequired) < pDrvInfo->TotalClusters)
  1521. {
  1522. for (ti = 0; ti < nClustersRequired; ti++)
  1523. {
  1524. if (FindNextCluster(pDrvInfo, nContigousStart+ti) != 0)
  1525. {
  1526. break;
  1527. }
  1528. }
  1529. if (ti == nClustersRequired)
  1530. {
  1531. return nContigousStart;
  1532. }
  1533. else
  1534. {
  1535. nContigousStart = nContigousStart+ti+1;
  1536. }
  1537. }
  1538. return 0;
  1539. }
  1540. UINT32 OccupyClusters(BPBINFO *pDrvInfo, UINT32 nStartCluster, UINT32 nTotalClusters)
  1541. {
  1542. UINT32 ti, nCurrent, nPrevious;
  1543. if (!gnContig)
  1544. {
  1545. if (nStartCluster == 0)
  1546. {
  1547. nStartCluster = 2;
  1548. }
  1549. nCurrent = nStartCluster;
  1550. nPrevious = nStartCluster;
  1551. //
  1552. // First locate a free cluster
  1553. //
  1554. while (nCurrent <= pDrvInfo->TotalClusters)
  1555. {
  1556. if (FindNextCluster(pDrvInfo, nCurrent) == 0)
  1557. {
  1558. break;
  1559. }
  1560. nCurrent++;
  1561. }
  1562. nPrevious = nCurrent;
  1563. gnClusterStart = nCurrent;
  1564. nCurrent++;
  1565. // one cluster almost allocated, set ti to 2
  1566. ti = 2;
  1567. while (ti <= nTotalClusters && nCurrent <= pDrvInfo->TotalClusters)
  1568. {
  1569. if (FindNextCluster(pDrvInfo, nCurrent) == 0)
  1570. {
  1571. //
  1572. // occupy this cluster
  1573. //
  1574. UpdateFATLocation(pDrvInfo, nPrevious, nCurrent);
  1575. nPrevious = nCurrent;
  1576. ti++;
  1577. }
  1578. nCurrent++;
  1579. }
  1580. UpdateFATLocation(pDrvInfo, nPrevious, GetFATEOF(pDrvInfo));
  1581. if (ti < nTotalClusters)
  1582. {
  1583. Mes("*** WARNING: Disk full, fewer than required clusters allocated.***\n");
  1584. }
  1585. return ti-1;
  1586. }
  1587. else
  1588. {
  1589. //
  1590. // This is a dangerous area. It trusts nStartCluster and nTotalClusters and
  1591. // allocates a contigous chain.
  1592. //
  1593. ti = 1;
  1594. nCurrent = nStartCluster;
  1595. while (ti < nTotalClusters)
  1596. {
  1597. nPrevious = nCurrent;
  1598. nCurrent++;
  1599. UpdateFATLocation(pDrvInfo, nPrevious, nCurrent);
  1600. ti++;
  1601. }
  1602. UpdateFATLocation(pDrvInfo, nCurrent, GetFATEOF(pDrvInfo));
  1603. return nTotalClusters;
  1604. }
  1605. }
  1606. //
  1607. // Directory related functions
  1608. //
  1609. UINT16 ReadRootDirSector(BPBINFO *DrvInfo, BYTE *pRootDirBuffer, UINT32 NthSector)
  1610. {
  1611. // !#! ReadRootDirSector is requested to return 1 sector. But two consiquitive
  1612. // sectors are returned so that it helps routine which process the file
  1613. // info when an LFN crosses sector boundary
  1614. UINT32 SeekSector;
  1615. UINT16 NthInChain;// Nth cluster 'order' in the root directory FAT chain
  1616. UINT16 ti;
  1617. UINT32 NextCluster;
  1618. BYTE RetVal;
  1619. UINT16 NthInCluster;
  1620. RetVal = 1;
  1621. switch (DrvInfo->FATType)
  1622. {
  1623. case 12:
  1624. case 16:
  1625. if (NthSector > DrvInfo->TotalRootDirSectors)
  1626. {
  1627. RetVal = 2;
  1628. break;
  1629. }
  1630. SeekSector = (UINT32) DrvInfo->FirstRootDirSector + NthSector - 1;
  1631. RetVal = (BYTE) ReadSector(DrvInfo->Drive, SeekSector, 2, pRootDirBuffer);
  1632. break;
  1633. case 32:
  1634. //
  1635. // Reading a FAT32 root directory sector is handled in a different way.
  1636. // Find out where the requested sector should be residing in the chain
  1637. //
  1638. NthInChain = (UINT16) (NthSector / (UINT32) DrvInfo->SectorsPerCluster);
  1639. NthInCluster = (UINT16) (NthSector - ((UINT32)NthInChain * (UINT32)DrvInfo->SectorsPerCluster));
  1640. if (!NthInCluster)
  1641. {
  1642. NthInChain--;
  1643. NthInCluster = DrvInfo->SectorsPerCluster;
  1644. }
  1645. // Find the cluster at this order in the FAT chain
  1646. NextCluster = DrvInfo->RootDirCluster;
  1647. ti = 0;
  1648. while (ti < NthInChain)
  1649. {
  1650. if (NextCluster >= (0x0fffffff-7))
  1651. {
  1652. RetVal = 2;
  1653. break;
  1654. }
  1655. NextCluster = FindNextCluster(DrvInfo, NextCluster);
  1656. ti++;
  1657. }
  1658. if (RetVal != 2)
  1659. {
  1660. SeekSector = (UINT32) DrvInfo->ReservedBeforeFAT +
  1661. DrvInfo->SectorsPerFAT *
  1662. (UINT32)DrvInfo->FATCount +
  1663. (UINT32) (NextCluster - 2) *
  1664. (UINT32) DrvInfo->SectorsPerCluster +
  1665. NthInCluster-1;
  1666. ReadSector(DrvInfo->Drive, SeekSector, 2, pRootDirBuffer);
  1667. // if this is the last sector OF the cluster get next cluster and
  1668. // get the first sector
  1669. if (NthInCluster == DrvInfo->SectorsPerCluster)
  1670. {
  1671. NthInCluster = 1;
  1672. NextCluster = FindNextCluster(DrvInfo, NextCluster);
  1673. if (NextCluster < (0x0fffffff-7))
  1674. {
  1675. SeekSector = (UINT32) DrvInfo->ReservedBeforeFAT +
  1676. DrvInfo->SectorsPerFAT *
  1677. (UINT32)DrvInfo->FATCount +
  1678. (UINT32) (NextCluster - 2) *
  1679. (UINT32) DrvInfo->SectorsPerCluster +
  1680. NthInCluster-1;
  1681. ReadSector(DrvInfo->Drive, SeekSector, 1, pRootDirBuffer+512); // note the 512 here
  1682. }
  1683. else
  1684. {
  1685. for (ti = 512; ti < 1024; ti++)
  1686. {
  1687. pRootDirBuffer[ti] = 0; // undo the second sector read
  1688. }
  1689. }
  1690. }
  1691. }
  1692. break;
  1693. }
  1694. return RetVal;
  1695. }
  1696. UINT16 WriteRootDirSector(BPBINFO *DrvInfo, BYTE *pRootDirBuffer, UINT32 NthSector)
  1697. {
  1698. UINT32 SeekSector;
  1699. UINT16 NthInChain; // Nth cluster 'order' in the root directory FAT chain
  1700. UINT16 ti;
  1701. UINT32 NextCluster;
  1702. BYTE RetVal;
  1703. UINT16 NthInCluster;
  1704. RetVal = 1;
  1705. switch (DrvInfo->FATType)
  1706. {
  1707. case 12: // FAT12 and FAT32 are handled the same way
  1708. case 16:
  1709. if (NthSector > DrvInfo->TotalRootDirSectors)
  1710. {
  1711. RetVal = 2;
  1712. break;
  1713. }
  1714. SeekSector = (UINT32) DrvInfo->FirstRootDirSector + NthSector-1;
  1715. RetVal = (BYTE) WriteSector(DrvInfo->Drive, SeekSector, 1, pRootDirBuffer);
  1716. break;
  1717. case 32:
  1718. // Find out where the requested sector should be going in the chain
  1719. NthInChain = (UINT16) (NthSector / (UINT32) DrvInfo->SectorsPerCluster);
  1720. NthInCluster = (UINT16) (NthSector - ((UINT32)NthInChain * (UINT32)DrvInfo->SectorsPerCluster));
  1721. if (!NthInCluster)
  1722. {
  1723. NthInChain--;
  1724. NthInCluster = DrvInfo->SectorsPerCluster;
  1725. }
  1726. // Find the cluster at this order in the FAT chain
  1727. NextCluster = DrvInfo->RootDirCluster;
  1728. ti = 0;
  1729. while (ti < NthInChain)
  1730. {
  1731. if (NextCluster == 0x0fffffff)
  1732. {
  1733. RetVal = 2;
  1734. break;
  1735. }
  1736. NextCluster = FindNextCluster(DrvInfo, NextCluster);
  1737. ti++;
  1738. }
  1739. if (RetVal != 2)
  1740. {
  1741. SeekSector = (UINT32) DrvInfo->ReservedBeforeFAT +
  1742. DrvInfo->SectorsPerFAT * (UINT32)DrvInfo->FATCount +
  1743. (UINT32) (NextCluster - 2) *
  1744. (UINT32) DrvInfo->SectorsPerCluster + NthInCluster-1;
  1745. WriteSector(DrvInfo->Drive, SeekSector, 1, pRootDirBuffer);
  1746. }
  1747. break;
  1748. }
  1749. return RetVal;
  1750. }
  1751. //
  1752. // File related functions
  1753. //
  1754. void FindFileLocation(BPBINFO *DrvInfo, BYTE *TraversePath, FILELOC *FileLocation)
  1755. {
  1756. // Parameter TraversePath must be a file name(or dir name) with full path
  1757. // The first character must be "\". If the function fails 0 is returned
  1758. // in FILELOC->Found. eg. You can pass \Windows\System32\Program Files
  1759. // to get "Program Files" location
  1760. FILEINFO FileInfo;
  1761. BYTE Found;
  1762. UINT16 RetVal;
  1763. BYTE DirInfo[300];
  1764. BYTE CheckInfo[300];
  1765. UINT16 ti,tj,n,TraverseCount, Offset;
  1766. BYTE i;
  1767. UINT32 NthRootDirSector, NextCluster, SectorToRead;
  1768. BYTE SectorBuffer[1024];
  1769. Found = 0;
  1770. ti = strlen(TraversePath);
  1771. if (ti < 2)
  1772. {
  1773. FileLocation->Found = 0;
  1774. return;
  1775. }
  1776. TraverseCount = 0;
  1777. // start from next character as the first char is "\" and i value should not change inside while loop
  1778. ti = 1;
  1779. while (TraversePath[ti] != 0)
  1780. {
  1781. tj = 0;
  1782. for (n = 0; n < 300; n++) DirInfo[n] = 0;
  1783. if (TraverseCount != 0)
  1784. {
  1785. ti++; // increment only after traversing root directory.
  1786. }
  1787. while (TraversePath[ti] != '\\' && TraversePath[ti] != 0)
  1788. {
  1789. DirInfo[tj] = TraversePath[ti];
  1790. tj++; ti++;
  1791. }
  1792. DirInfo[tj] = 0;
  1793. TraverseCount++;
  1794. if (TraverseCount == 1)
  1795. {
  1796. //
  1797. // We are in root directory entry if TraverseCount equals 1
  1798. //
  1799. Found = 0;
  1800. NthRootDirSector = 1;
  1801. Offset = 0;
  1802. while (!Found)
  1803. {
  1804. RetVal = ReadRootDirSector(DrvInfo, SectorBuffer, NthRootDirSector);
  1805. if (RetVal == 0 || RetVal == 2)
  1806. {
  1807. break;
  1808. }
  1809. else
  1810. {
  1811. while (SectorBuffer[Offset] != 0)
  1812. {
  1813. if (SectorBuffer[Offset] == 0xe5)
  1814. {
  1815. Offset+=32;
  1816. }
  1817. else
  1818. {
  1819. GetFileInfo(DrvInfo, SectorBuffer, Offset, &FileInfo);
  1820. strcpy(CheckInfo, (char *)FileInfo.LFName);
  1821. if (strcmpi(CheckInfo, DirInfo) == 0)
  1822. {
  1823. FileLocation->InCluster = 1;
  1824. FileLocation->StartCluster = FileInfo.StartCluster;
  1825. FileLocation->NthSector = NthRootDirSector;
  1826. FileLocation->NthEntry = Offset/32 + 1;
  1827. FileLocation->EntriesTakenUp = FileInfo.EntriesTakenUp;
  1828. FileLocation->Size = FileInfo.Size;
  1829. FileLocation->Attribute = FileInfo.Attribute;
  1830. Found = 1;
  1831. break;
  1832. }
  1833. Offset = Offset + FileInfo.EntriesTakenUp * 32;
  1834. }
  1835. if (Offset > 511)
  1836. {
  1837. break;
  1838. }
  1839. }
  1840. }
  1841. if (SectorBuffer[Offset] == 0 || Found)
  1842. {
  1843. break;
  1844. }
  1845. //
  1846. // do not set it to 0 directly
  1847. //
  1848. Offset = Offset - 512;
  1849. NthRootDirSector++;
  1850. }
  1851. if (!Found)
  1852. {
  1853. FileLocation->Found = 0;
  1854. return;
  1855. }
  1856. }
  1857. else
  1858. {
  1859. NextCluster = FileLocation->StartCluster;
  1860. Offset = 0;
  1861. Found = 0;
  1862. while (NextCluster < (GetFATEOF(DrvInfo) - 7))
  1863. {
  1864. for (i = 0; i < DrvInfo->SectorsPerCluster; i++)
  1865. {
  1866. SectorToRead = (UINT32) ((UINT32)DrvInfo->TotalSystemSectors + (NextCluster - 2) * (UINT32)DrvInfo->SectorsPerCluster + i);
  1867. ReadSector(DrvInfo->Drive, SectorToRead, 2, SectorBuffer);
  1868. if (i == DrvInfo->SectorsPerCluster-1)
  1869. {
  1870. if (FindNextCluster(DrvInfo, NextCluster) < (GetFATEOF(DrvInfo) - 7))
  1871. { // Note the +512 carefully
  1872. SectorToRead = (UINT32) ((UINT32)DrvInfo->TotalSystemSectors +
  1873. (FindNextCluster(DrvInfo, NextCluster) - 2) *
  1874. (UINT32)DrvInfo->SectorsPerCluster);
  1875. ReadSector(DrvInfo->Drive, SectorToRead, 1, SectorBuffer+512);
  1876. }
  1877. }
  1878. while (1)
  1879. {
  1880. if (Offset > 511 || SectorBuffer[Offset] == 0)
  1881. {
  1882. break;
  1883. }
  1884. if (SectorBuffer[Offset] == 0xe5)
  1885. {
  1886. Offset+=32;
  1887. continue;
  1888. }
  1889. GetFileInfo(DrvInfo, SectorBuffer, Offset, &FileInfo);
  1890. //
  1891. // Refer to GetFileInfo if confused
  1892. //
  1893. strcpy(CheckInfo, FileInfo.LFName);
  1894. if (strcmpi(CheckInfo, DirInfo) == 0)
  1895. {
  1896. FileLocation->InCluster = NextCluster;
  1897. FileLocation->StartCluster = FileInfo.StartCluster;
  1898. FileLocation->NthSector = (UINT32) i+1;
  1899. FileLocation->NthEntry = Offset/32 + 1;
  1900. FileLocation->EntriesTakenUp = FileInfo.EntriesTakenUp;
  1901. FileLocation->Size = FileInfo.Size;
  1902. FileLocation->Attribute = FileInfo.Attribute;
  1903. Found = 1;
  1904. break;
  1905. }
  1906. Offset = Offset + FileInfo.EntriesTakenUp * 32;
  1907. }
  1908. if (Found)
  1909. {
  1910. break;
  1911. }
  1912. Offset = Offset - 512; // Should not simply set it to 0
  1913. }
  1914. if (Found)
  1915. {
  1916. break;
  1917. }
  1918. NextCluster = FindNextCluster(DrvInfo, NextCluster);
  1919. }
  1920. }
  1921. }
  1922. FileLocation->Found = Found;
  1923. }
  1924. void GetFileInfo(BPBINFO *DrvInfo, BYTE *DirBuffer, UINT16 Offset, FILEINFO *FileInfo)
  1925. {
  1926. // GetFileInfo gets the file information from DirBuffer at Offset and
  1927. // It supports long file names. Also it stores the number of
  1928. // entries that are occupied by this file name in FileInfo->EntriesTakenUp
  1929. // !#! If the entry is not a long file name a proper file name is stored
  1930. // in LFName with a dot in between primary and ext names to help routines
  1931. // which compare file names
  1932. UINT16 ti,tj;
  1933. UINT16 TimeDateWord;
  1934. BYTE StrCompare[7];
  1935. UINT32 Temp;
  1936. FileInfo->LFName[0] = '\0';
  1937. FileInfo->LFNOrphaned = 0;
  1938. FileInfo->TrashedEntry = 0;
  1939. // Get file attribute
  1940. FileInfo->Attribute = DirBuffer[Offset+11];
  1941. if ((FileInfo->Attribute & 0x0f) == 0x0f)
  1942. {
  1943. if (DirBuffer[Offset] >= 'A' && DirBuffer[Offset] <= 'T')
  1944. { // Count of minimum and maximum entries to be an LFN
  1945. FileInfo->EntriesTakenUp = (DirBuffer[Offset] & 0x3f) + 1;
  1946. // Get the real attribute if it is a long file name. EntriesTakenUp > 1 is a long file name
  1947. FileInfo->Attribute = DirBuffer[(FileInfo->EntriesTakenUp-1)*32+Offset+11];
  1948. }
  1949. else
  1950. {
  1951. FileInfo->TrashedEntry = 1;
  1952. FileInfo->LFNOrphaned = 1; // Could be
  1953. return;
  1954. }
  1955. }
  1956. else
  1957. {
  1958. FileInfo->EntriesTakenUp = 1;
  1959. }
  1960. // Get Primary name
  1961. for (ti = 0; ti < 8; ti++)
  1962. {
  1963. FileInfo->DOSName[ti] = DirBuffer[(FileInfo->EntriesTakenUp-1)*32+Offset+ti];
  1964. }
  1965. // Get extension
  1966. FileInfo->DOSExt[0] = DirBuffer[(FileInfo->EntriesTakenUp-1)*32+Offset+8];
  1967. FileInfo->DOSExt[1] = DirBuffer[(FileInfo->EntriesTakenUp-1)*32+Offset+9];
  1968. FileInfo->DOSExt[2] = DirBuffer[(FileInfo->EntriesTakenUp-1)*32+Offset+10];
  1969. Rx.e.evx = 0;
  1970. Rx.h.vl = DirBuffer[(FileInfo->EntriesTakenUp-1)*32+Offset+0x1c];
  1971. Rx.h.vh = DirBuffer[(FileInfo->EntriesTakenUp-1)*32+Offset+0x1d];
  1972. Rx.h.xvl = DirBuffer[(FileInfo->EntriesTakenUp-1)*32+Offset+0x1e];
  1973. Rx.h.xvh = DirBuffer[(FileInfo->EntriesTakenUp-1)*32+Offset+0x1f];
  1974. FileInfo->Size = Rx.e.evx;
  1975. switch (DrvInfo->FATType)
  1976. {
  1977. case 12:
  1978. case 16:
  1979. // Starting Cluster
  1980. Rx.e.evx = 0;
  1981. Rx.h.vl = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x1a]; Rx.h.vh = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x1b];
  1982. FileInfo->StartCluster = (UINT32) Rx.x.vx;
  1983. // Get File time
  1984. Rx.e.evx = 0;
  1985. Rx.h.vl = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x16]; Rx.h.vh = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x17];
  1986. TimeDateWord = Rx.x.vx;
  1987. FileInfo->Second = (BYTE) (TimeDateWord & 0x001f);
  1988. FileInfo->Minute = (BYTE) ((TimeDateWord & 0x07e0) >> 5);
  1989. FileInfo->Hour = (BYTE) ((TimeDateWord & 0xf800) >> 11);
  1990. // Get File date
  1991. Rx.e.evx = 0;
  1992. Rx.h.vl = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x18];
  1993. Rx.h.vh = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x19];
  1994. TimeDateWord = Rx.x.vx;
  1995. FileInfo->Day = (BYTE) (TimeDateWord & 0x001f);
  1996. FileInfo->Month = (BYTE) ((TimeDateWord & 0x01e0) >> 5);
  1997. FileInfo->Year = ((TimeDateWord & 0xfe00) >> 9) + 1980;
  1998. break;
  1999. case 32:
  2000. // Starting Cluster
  2001. Rx.e.evx = 0;
  2002. Rx.h.vl = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x1a];
  2003. Rx.h.vh = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x1b];
  2004. Rx.h.xvl = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x14];
  2005. Rx.h.xvh = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x15];
  2006. FileInfo->StartCluster = Rx.e.evx;
  2007. // Get File time
  2008. Rx.e.evx = 0;
  2009. Rx.h.vl = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x16];
  2010. Rx.h.vh = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x17];
  2011. TimeDateWord = Rx.x.vx;
  2012. FileInfo->Second = (BYTE) (TimeDateWord & 0x001f);
  2013. FileInfo->Minute = (BYTE) ((TimeDateWord & 0x07e0) >> 5);
  2014. FileInfo->Hour = (BYTE) ((TimeDateWord & 0xf800) >> 11);
  2015. // Get File date
  2016. Rx.e.evx = 0;
  2017. Rx.h.vl = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x18];
  2018. Rx.h.vh = DirBuffer[Offset+(FileInfo->EntriesTakenUp-1)*32+0x19];
  2019. TimeDateWord = Rx.x.vx;
  2020. FileInfo->Day = (BYTE) (TimeDateWord & 0x001f);
  2021. FileInfo->Month = (BYTE) ((TimeDateWord & 0x01e0) >> 5);
  2022. FileInfo->Year = ((TimeDateWord & 0xfe00) >> 9) + 1980;
  2023. break;
  2024. default:
  2025. break;
  2026. }
  2027. if (FileInfo->EntriesTakenUp < 2) // copy DOSName and DOSExt as proper file name to LFName
  2028. {
  2029. ti = 0; tj = 0;
  2030. while(1)
  2031. {
  2032. if (FileInfo->DOSName[ti] == ' ' || ti == 8)
  2033. {
  2034. break;
  2035. }
  2036. FileInfo->LFName[tj] = FileInfo->DOSName[ti];
  2037. tj++; ti++;
  2038. }
  2039. if (ti != 0 && FileInfo->DOSExt[0] != ' ') // Avoid empty names and . in case of no extension
  2040. {
  2041. FileInfo->LFName[tj] = '.';
  2042. ti = 0; tj++;
  2043. while (1)
  2044. {
  2045. if (FileInfo->DOSExt[ti] == ' ' || ti == 3)
  2046. {
  2047. break;
  2048. }
  2049. FileInfo->LFName[tj] = FileInfo->DOSExt[ti];
  2050. tj++; ti++;
  2051. }
  2052. }
  2053. FileInfo->LFName[tj] = 0; // Terminate with NULL Character
  2054. }
  2055. else
  2056. { // Fetch the Long file name
  2057. ti = 0; tj = FileInfo->EntriesTakenUp - 1;
  2058. while( tj > 0)
  2059. {
  2060. FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 1]; ti++; FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 3]; ti++;
  2061. FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 5]; ti++; FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 7]; ti++;
  2062. FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 9]; ti++; FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 14]; ti++;
  2063. FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 16]; ti++; FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 18]; ti++;
  2064. FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 20]; ti++; FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 22]; ti++;
  2065. FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 24]; ti++; FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 28]; ti++;
  2066. FileInfo->LFName[ti] = DirBuffer[Offset + (tj-1)*32 + 30]; ti++;
  2067. tj--;
  2068. }
  2069. FileInfo->LFName[ti] = 0;
  2070. }
  2071. // Check for orphaned LFN
  2072. if (FileInfo->EntriesTakenUp > 1)
  2073. { // it is a long file name
  2074. // Get the strings from the LFN without space for comparison purpose
  2075. // Example - if LFN is "Very Long name" the corresponding
  2076. // DOS file name would be "VERYLO~?". We extract VeryLo and check
  2077. // against VERYLO.
  2078. ti = 0; tj = 0;
  2079. while (ti < 8 && FileInfo->LFName[tj] != 0 && FileInfo->LFName[tj] != '.')
  2080. {
  2081. if (FileInfo->LFName[tj] != 32 && FileInfo->LFName[tj] != '.')
  2082. {
  2083. StrCompare[ti] = FileInfo->LFName[tj];
  2084. ti++;
  2085. }
  2086. tj++;
  2087. }
  2088. StrCompare[tj] = 0;
  2089. // But when there are to many file starting with name "Very Long name"
  2090. // the dos file name need not be "VERYLO~?" in all the cases. It could
  2091. // be "VERYL~??" or "VERY~???" and so on...
  2092. tj = 0;
  2093. while (FileInfo->DOSName[tj] != '~' && FileInfo->DOSName[tj] != ' ' && tj < 8)
  2094. {
  2095. tj++;
  2096. }
  2097. // ******* This if condition is not efficient
  2098. // it is only modified to avoid false LFN errors.
  2099. // replace the one with tj after getting more info about CRC values
  2100. // *******
  2101. if (strnicmp(StrCompare, FileInfo->DOSName, 1) != 0)
  2102. {
  2103. FileInfo->LFNOrphaned = 1;
  2104. }
  2105. }
  2106. // Check if this file is a trashed entry
  2107. if (DrvInfo->BigTotalSectors)
  2108. {
  2109. Temp = DrvInfo->BigTotalSectors;
  2110. }
  2111. else
  2112. {
  2113. Temp = DrvInfo->TotalSectors;
  2114. }
  2115. if (FileInfo->Year < 1981 || FileInfo->Day > 31 || FileInfo->Month < 1 ||
  2116. FileInfo->Month > 12 || FileInfo->Second > 30 ||
  2117. FileInfo->Minute > 60 || FileInfo->Hour > 23 ||
  2118. FileInfo->StartCluster > DrvInfo->TotalClusters ||
  2119. FileInfo->Size/512 > Temp)
  2120. {
  2121. FileInfo->TrashedEntry = 1;
  2122. }
  2123. }
  2124. BYTE GetAllInfoOfFile(BPBINFO *pDrvInfo, BYTE *FileName, FILELOC *pFileLoc, FILEINFO *pFileInfo)
  2125. {
  2126. UINT16 Offset;
  2127. UINT32 SectorToRead;
  2128. BYTE Sector[1024];
  2129. FindFileLocation(pDrvInfo, FileName, pFileLoc);
  2130. if (!pFileLoc->Found)
  2131. { // need not proceed to find FileInfo
  2132. return 0;
  2133. }
  2134. Offset = (pFileLoc->NthEntry-1) * 32;
  2135. if (pFileLoc->InCluster == 1)
  2136. { // file in root directory
  2137. ReadRootDirSector(pDrvInfo, Sector, pFileLoc->NthSector);
  2138. }
  2139. else
  2140. {
  2141. SectorToRead = (UINT32) ((UINT32)pDrvInfo->TotalSystemSectors + (pFileLoc->InCluster - 2) * (UINT32)pDrvInfo->SectorsPerCluster + pFileLoc->NthSector-1);
  2142. ReadSector(pDrvInfo->Drive, SectorToRead, 1, Sector);
  2143. }
  2144. GetFileInfo(pDrvInfo, Sector, Offset, pFileInfo);
  2145. return 1;
  2146. }
  2147. UINT16 SetFileInfo(BPBINFO *pDrvInfo, FILELOC *pFileLoc, FILEINFO *pFileInfo)
  2148. {
  2149. // This function loads the entry of a file from its directory sector
  2150. // specified in FileLocation and updates it with the new File Info in FILEINFO
  2151. // At present this function only changes StartCluster, Size
  2152. UINT32 SectorToRead, EmergencySectorToRead;
  2153. UINT16 Offset, Temp;
  2154. BYTE SectorBuffer[1024];
  2155. Offset = (pFileLoc->NthEntry-1)*32;
  2156. if (pFileLoc->InCluster == 1)
  2157. { // the file is in root directory. Refer to FindFileLocation function for more info
  2158. if (ReadRootDirSector(pDrvInfo, SectorBuffer, pFileLoc->NthSector) != 1)
  2159. { // The return value of the above function is either 0 or 1 or 2. We only want return value 1
  2160. return 0;
  2161. }
  2162. }
  2163. else
  2164. {
  2165. SectorToRead = (UINT32) ((UINT32)pDrvInfo->TotalSystemSectors + (pFileLoc->InCluster - 2) * (UINT32)pDrvInfo->SectorsPerCluster + pFileLoc->NthSector-1);
  2166. EmergencySectorToRead = SectorToRead + 1;
  2167. if (!ReadSector(pDrvInfo->Drive, SectorToRead, 2, SectorBuffer))
  2168. {
  2169. return 0;
  2170. }
  2171. if (pFileLoc->NthSector == pDrvInfo->SectorsPerCluster)
  2172. {
  2173. if (FindNextCluster(pDrvInfo, pFileLoc->InCluster) < (GetFATEOF(pDrvInfo) - 7)) // EOF can be FFF8 to FFFF
  2174. { // Note the +512 carefully
  2175. EmergencySectorToRead = (UINT32) ((UINT32)pDrvInfo->TotalSystemSectors + (FindNextCluster(pDrvInfo, pFileLoc->InCluster) - 2) * (UINT32)pDrvInfo->SectorsPerCluster);
  2176. if (!ReadSector(pDrvInfo->Drive, EmergencySectorToRead, 1, SectorBuffer+512))
  2177. {
  2178. return 0;
  2179. }
  2180. }
  2181. }
  2182. }
  2183. //
  2184. // We have the file entry in SectorBuffer
  2185. // Now update the file info located in the SHORTNAME area
  2186. //
  2187. Temp = (pFileInfo->EntriesTakenUp-1)*32;
  2188. //
  2189. // Change Cluster value
  2190. //
  2191. Rx.e.evx = 0;
  2192. Rx.e.evx = (UINT32) pFileInfo->StartCluster;
  2193. if (pDrvInfo->FATType == 32)
  2194. {
  2195. SectorBuffer[Offset+Temp+0x1a] = Rx.h.vl;
  2196. SectorBuffer[Offset+Temp+0x1b] = Rx.h.vh;
  2197. SectorBuffer[Offset+Temp+0x14] = Rx.h.xvl;
  2198. SectorBuffer[Offset+Temp+0x15] = Rx.h.xvh;
  2199. }
  2200. else
  2201. {
  2202. SectorBuffer[Offset+Temp+0x1a] = Rx.h.vl;
  2203. SectorBuffer[Offset+Temp+0x1b] = Rx.h.vh;
  2204. }
  2205. // Change Size
  2206. Rx.e.evx = pFileInfo->Size;
  2207. SectorBuffer[Offset+Temp+0x1c] = Rx.h.vl; SectorBuffer[Offset+Temp+0x1d] = Rx.h.vh;
  2208. SectorBuffer[Offset+Temp+0x1e] = Rx.h.xvl; SectorBuffer[Offset+Temp+0x1f] = Rx.h.xvh;
  2209. if (pFileLoc->InCluster == 1)
  2210. {
  2211. WriteRootDirSector(pDrvInfo, SectorBuffer, pFileLoc->NthSector);
  2212. if (Offset + pFileLoc->EntriesTakenUp * 32 > 512) // Did it cross sector boundary
  2213. {
  2214. WriteRootDirSector(pDrvInfo, SectorBuffer+512, pFileLoc->NthSector+1);
  2215. }
  2216. }
  2217. else
  2218. {
  2219. WriteSector(pDrvInfo->Drive, SectorToRead, 1, SectorBuffer);
  2220. if (Offset + pFileLoc->EntriesTakenUp * 32 > 512) // Did it cross sector boundary
  2221. {
  2222. WriteSector(pDrvInfo->Drive, EmergencySectorToRead, 1, SectorBuffer+512);
  2223. }
  2224. }
  2225. // File entry updated
  2226. return 1;
  2227. }