PageRenderTime 75ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/tmpfs/orig/msdos.c

https://github.com/jaapweel/os134
C | 1794 lines | 1567 code | 124 blank | 103 comment | 138 complexity | 56544dee9c3aeea1fe046643c01a61b6 MD5 | raw file
  1. /*
  2. * Program for interacting with an MSDOS filesystem.
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <memory.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <errno.h>
  11. #include <fcntl.h>
  12. #include <time.h>
  13. #include <ctype.h>
  14. #include <math.h>
  15. /*
  16. * Constants.
  17. */
  18. /* #define BYTES_PER_SECTOR 512 */
  19. #define BITS_PER_FAT_ENTRY 12
  20. #define BYTES_PER_DIR_ENTRY 32
  21. /* #define SECTOR_OFFSET 31 */
  22. #define BYTES_PER_SECTOR (dosp->boot_sector->bytes_per_sector)
  23. #define SECTORS_PER_CLUSTER (dosp->boot_sector->sectors_per_cluster)
  24. #define BYTES_PER_CLUSTER (BYTES_PER_SECTOR*SECTORS_PER_CLUSTER)
  25. #define NUMBER_OF_LOGICAL_CLUSTERS (dosp->boot_sector->number_of_logical_clusters)
  26. #define SECTORS_PER_FAT (dosp->boot_sector->sectors_per_fat)
  27. #define NUMBER_OF_FATS (dosp->boot_sector->number_of_fats)
  28. #define BOOT_RECORD_SECTORS (dosp->boot_sector->boot_record_sectors)
  29. #define NUMBER_OF_ROOT_ENTRIES (dosp->boot_sector->number_of_root_entries)
  30. #define CLUSTER__SECTOR_OFFSET (ROOT_DIR_SECTOR-(2*SECTORS_PER_CLUSTER)+ROOT_DIR_LEN)
  31. #define TOTAL_FILENAME_LEN (DE_FILENAME_LEN+DE_EXTENSION_LEN)
  32. #define MAX_PATH_LEN 1024
  33. #define BITS_PER_BYTE 8
  34. /*
  35. * Sector numbers for the DOS things.
  36. */
  37. #define BOOT_SECTOR 0
  38. /*
  39. * #define FIRST_FAT_SECTOR 1
  40. * #define FIRST_FAT_LEN 9
  41. * #define SECOND_FAT_SECTOR 10
  42. * #define SECOND_FAT_LEN 9
  43. * #define ROOT_DIR_SECTOR 19
  44. */
  45. #define FIRST_FAT_SECTOR (BOOT_SECTOR+1)
  46. #define FIRST_FAT_LEN SECTORS_PER_FAT
  47. #define SECOND_FAT_SECTOR (FIRST_FAT_SECTOR+SECTORS_PER_FAT)
  48. #define SECOND_FAT_LEN SECTORS_PER_FAT
  49. #define ROOT_DIR_SECTOR (BOOT_SECTOR+NUMBER_OF_FATS*SECTORS_PER_FAT+BOOT_RECORD_SECTORS)
  50. #define ROOT_DIR_LEN (NUMBER_OF_ROOT_ENTRIES*BYTES_PER_DIR_ENTRY/BYTES_PER_SECTOR)
  51. /*
  52. * Struct for the boot sector.
  53. */
  54. #define BS_JUMP_OFF 0
  55. #define BS_JUMP_LEN 3
  56. #define BS_MANUFACTURER_NAME_OFF 0x03
  57. #define BS_MANUFACTURER_NAME_LEN 8
  58. #define BS_BYTES_PER_SECTOR_OFF 0x0b
  59. #define BS_BYTES_PER_SECTOR_LEN 2
  60. #define BS_SECTORS_PER_CLUSTER_OFF 0x0d
  61. #define BS_SECTORS_PER_CLUSTER_LEN 1
  62. #define BS_BOOT_RECORD_SECTORS_OFF 0x0e
  63. #define BS_BOOT_RECORD_SECTORS_LEN 2
  64. #define BS_NUMBER_OF_FATS_OFF 0x10
  65. #define BS_NUMBER_OF_FATS_LEN 1
  66. #define BS_NUMBER_OF_ROOT_ENTRIES_OFF 0x11
  67. #define BS_NUMBER_OF_ROOT_ENTRIES_LEN 2
  68. /* #define BS_NUMBER_OF_LOGICAL_SECTORS_OFF 0x13 */
  69. /* #define BS_NUMBER_OF_LOGICAL_SECTORS_LEN 2 */
  70. #define BS_NUMBER_OF_LOGICAL_CLUSTERS_OFF 0x13
  71. #define BS_NUMBER_OF_LOGICAL_CLUSTERS_LEN 2
  72. #define BS_MEDIA_TYPE_OFF 0x15
  73. #define BS_MEDIA_TYPE_LEN 1
  74. #define BS_SECTORS_PER_FAT_OFF 0x16
  75. #define BS_SECTORS_PER_FAT_LEN 2
  76. #define BS_SECTORS_PER_TRACK_OFF 0x18
  77. #define BS_SECTORS_PER_TRACK_LEN 2
  78. #define BS_NUMBER_OF_HEADS_OFF 0x1a
  79. #define BS_NUMBER_OF_HEADS_LEN 2
  80. #define BS_NUMBER_OF_HIDDEN_SECTORS_OFF 0x1c
  81. #define BS_NUMBER_OF_HIDDEN_SECTORS_LEN 2
  82. #define BS_BOOTSTRAP_PROGRAM 0x1e
  83. #define BS_SIGNATURE_OFF 0x1fe
  84. #define BS_SIGNATURE_LEN 2
  85. typedef struct msdos_boot_sector {
  86. unsigned jump[BS_JUMP_LEN+1];
  87. char manufacturer_name[BS_MANUFACTURER_NAME_LEN+1];
  88. unsigned bytes_per_sector;
  89. unsigned sectors_per_cluster;
  90. unsigned boot_record_sectors;
  91. unsigned number_of_fats;
  92. unsigned number_of_root_entries;
  93. unsigned number_of_logical_clusters;
  94. unsigned media_type;
  95. unsigned sectors_per_fat;
  96. unsigned sectors_per_track;
  97. unsigned number_of_heads;
  98. unsigned number_of_hidden_sectors;
  99. unsigned signature[BS_SIGNATURE_LEN+1];
  100. } MSDOSBootSector;
  101. /*
  102. * Directory entries.
  103. */
  104. #define DE_FILENAME_OFF 0
  105. #define DE_FILENAME_LEN 8
  106. #define DE_EXTENSION_OFF 8
  107. #define DE_EXTENSION_LEN 3
  108. #define DE_ATTR_OFF 0x0b
  109. #define DE_ATTR_LEN 1
  110. #define ATTR_READ_ONLY_SHIFT 0
  111. #define ATTR_HIDDEN_SHIFT 1
  112. #define ATTR_SYSTEM_SHIFT 2
  113. #define ATTR_VLABEL_SHIFT 3
  114. #define ATTR_SUBDIR_SHIFT 4
  115. #define ATTR_ARCHIVE_SHIFT 5
  116. #define DE_RESERVED_OFF 0x0c
  117. #define DE_RESERVED_LEN 10
  118. #define DE_TIME_OFF 0x16
  119. #define DE_TIME_LEN 2
  120. #define DE_TIME_SEC(i) (((i) * 2) % 64)
  121. #define DE_TIME_MIN(i) (((i) / 32) % 64)
  122. #define DE_TIME_HOUR(i) (((i) / 2048))
  123. #define DE_TIME(sec, min, hour) (((hour) * 2048) | ((min) * 32) | ((sec) / 2))
  124. #define DE_DATE_OFF 0x18
  125. #define DE_DATE_LEN 2
  126. #define DE_DATE_DAY(i) ((i) % 32)
  127. #define DE_DATE_MONTH(i) (((i) / 32) % 32)
  128. #define DE_DATE_YEAR(i) (((i) / 512) + 1980)
  129. #define DE_DATE(day, mon, year) ((((year) - 1980) * 512) | ((mon) * 32) | (day))
  130. #define DE_FIRST_CLUSTER_OFF 0x1a
  131. #define DE_FIRST_CLUSTER_LEN 2
  132. #define DE_FILESIZE_OFF 0x1c
  133. #define DE_FILESIZE_LEN 4
  134. typedef struct msdos_time_stamp {
  135. unsigned second;
  136. unsigned char minute;
  137. unsigned hour;
  138. unsigned day;
  139. unsigned month;
  140. unsigned year;
  141. char monthStr[4];
  142. } MSDOSTimeStamp;
  143. typedef struct msdos_dir_entry MSDOSDirEntry;
  144. struct msdos_dir_entry {
  145. unsigned char filename[DE_FILENAME_LEN+1];
  146. unsigned char extension[DE_EXTENSION_LEN+1];
  147. unsigned char attr;
  148. unsigned attr_read_only : 1;
  149. unsigned attr_hidden : 1;
  150. unsigned attr_system : 1;
  151. unsigned attr_vlabel : 1;
  152. unsigned attr_subdir : 1;
  153. unsigned attr_archive : 1;
  154. unsigned char reserved[DE_RESERVED_LEN];
  155. unsigned time;
  156. unsigned date;
  157. MSDOSTimeStamp timestamp;
  158. unsigned first_cluster;
  159. unsigned filesize;
  160. MSDOSDirEntry *parent;
  161. unsigned char path[MAX_PATH_LEN];
  162. unsigned char tname[TOTAL_FILENAME_LEN+1]; /* Trimmed name + extension */
  163. };
  164. /*
  165. * Filesystem info.
  166. */
  167. typedef struct msdos {
  168. int fd; /* File descriptor for the device */
  169. /*
  170. * TODO: you probably want to add additional fields,
  171. * like the current directory, and a copy of the FAT
  172. * table for the filesystem.
  173. */
  174. MSDOSBootSector *boot_sector;
  175. unsigned short *fat_table;
  176. unsigned fat_entries;
  177. MSDOSDirEntry *root_dir;
  178. MSDOSDirEntry *current_dir;
  179. } MSDOS;
  180. /************************************************************************
  181. * I/O
  182. ************************************************************************/
  183. /*
  184. * DO NOT use the read/write functions directly.
  185. * Use these block operations instead.
  186. */
  187. int msdos_block_read(MSDOS *dosp, int block, char *buffer);
  188. int msdos_block_write(MSDOS *dosp, int block, char *buffer);
  189. int msdos_nblock_read(MSDOS *dosp, int block, int num, char *buffer);
  190. int msdos_nblock_write(MSDOS *dosp, int block, int num, char *buffer);
  191. int msdos_sector_read(MSDOS *dosp, int sector, char *buffer);
  192. int msdos_sector_write(MSDOS *dosp, int sector, const char *buffer);
  193. int msdos_cluster_read(MSDOS *dosp, int cluster, char *buffer);
  194. int msdos_cluster_write(MSDOS *dosp, int cluster, char *buffer);
  195. int msdos_nsector_read(MSDOS *dosp, int sector, int num, char *buffer);
  196. int msdos_nsector_write(MSDOS *dosp, int sector, int num, char *buffer);
  197. int msdos_ncluster_read(MSDOS *dosp, int sector, int num, char *buffer);
  198. int msdos_ncluster_write(MSDOS *dosp, int sector, int num, char *buffer);
  199. /*
  200. * Read a logical block from the file.
  201. * Returns -1 on error.
  202. */
  203. int msdos_block_read(MSDOS *dosp, int block, char *buffer)
  204. {
  205. if (block == 0)
  206. return msdos_sector_read(dosp, block, buffer);
  207. else
  208. return msdos_cluster_read(dosp, block, buffer);
  209. }
  210. /*
  211. * Write a logical block to the file.
  212. * Returns -1 on error.
  213. */
  214. int msdos_block_write(MSDOS *dosp, int block, char *buffer)
  215. {
  216. if (block == 0)
  217. return msdos_sector_write(dosp, block, buffer);
  218. else
  219. return msdos_cluster_write(dosp, block, buffer);
  220. }
  221. /*
  222. * Read n logical blocks from the file.
  223. * Returns -1 on error.
  224. */
  225. int msdos_nblock_read(MSDOS *dosp, int block, int num, char *buffer)
  226. {
  227. if (block == 0)
  228. return msdos_nsector_read(dosp, block, num, buffer);
  229. else
  230. return msdos_ncluster_read(dosp, block, num, buffer);
  231. }
  232. /*
  233. * Write n logical blocks to the file.
  234. * Returns -1 on error.
  235. */
  236. int msdos_nblock_write(MSDOS *dosp, int block, int num, char *buffer)
  237. {
  238. if (block == 0)
  239. return msdos_nsector_write(dosp, block, num, buffer);
  240. else
  241. return msdos_ncluster_write(dosp, block, num, buffer);
  242. }
  243. /*
  244. * Read a sector from the file.
  245. * Returns -1 on error.
  246. */
  247. int msdos_sector_read(MSDOS *dosp, int sector, char *buffer)
  248. {
  249. int dest, len;
  250. /* Seek to the sector */
  251. dest = lseek(dosp->fd, sector * BYTES_PER_SECTOR, SEEK_SET);
  252. if (dest < 0)
  253. {
  254. perror("msdos_sector_read: lseek");
  255. return -1;
  256. }
  257. /* Assume the read happens all at once */
  258. len = read(dosp->fd, buffer, BYTES_PER_SECTOR);
  259. if (len != BYTES_PER_SECTOR)
  260. {
  261. perror("msdos_sector_read: read");
  262. return -1;
  263. }
  264. return len;
  265. }
  266. /*
  267. * Write a sector to the file.
  268. * Returns -1 on error.
  269. */
  270. int msdos_sector_write(MSDOS *dosp, int sector, const char *buffer)
  271. {
  272. int dest, len;
  273. /* Seek to the sector */
  274. dest = lseek(dosp->fd, sector * BYTES_PER_SECTOR, SEEK_SET);
  275. if (dest < 0)
  276. {
  277. perror("msdos_sector_write: lseek");
  278. return -1;
  279. }
  280. /* Assume the read happens all at once */
  281. len = write(dosp->fd, buffer, BYTES_PER_SECTOR);
  282. if (len != BYTES_PER_SECTOR)
  283. {
  284. perror("msdos_sector_read: read");
  285. return -1;
  286. }
  287. return len;
  288. }
  289. /*
  290. * Read a cluster from the file.
  291. * Returns -1 on error.
  292. */
  293. int msdos_cluster_read(MSDOS *dosp, int cluster, char *buffer)
  294. {
  295. if (cluster == 0)
  296. {
  297. perror("msdos_cluster_read: no cluster 0.");
  298. return -1;
  299. }
  300. else if (cluster > NUMBER_OF_LOGICAL_CLUSTERS)
  301. {
  302. perror("msdos_cluster_read: cluster too high\n");
  303. return -1;
  304. }
  305. else
  306. return msdos_nsector_read(dosp, cluster*SECTORS_PER_CLUSTER + CLUSTER__SECTOR_OFFSET, SECTORS_PER_CLUSTER, buffer);
  307. }
  308. /*
  309. * Write a cluster to the file.
  310. * Returns -1 on error.
  311. */
  312. int msdos_cluster_write(MSDOS *dosp, int cluster, char *buffer)
  313. {
  314. if (cluster == 0)
  315. {
  316. perror("msdos_cluster_write: no cluster 0.");
  317. return -1;
  318. }
  319. else if (cluster > NUMBER_OF_LOGICAL_CLUSTERS)
  320. {
  321. perror("msdos_cluster_write: cluster too high\n");
  322. return -1;
  323. }
  324. else
  325. return msdos_nsector_write(dosp, cluster*SECTORS_PER_CLUSTER + CLUSTER__SECTOR_OFFSET, SECTORS_PER_CLUSTER, buffer);
  326. }
  327. /*
  328. * Read n sectors from the file.
  329. * Returns -1 on error.
  330. */
  331. int msdos_nsector_read(MSDOS *dosp, int sector, int num, char *buffer)
  332. {
  333. int i, ret, len=0;
  334. char *ptr=buffer;
  335. for (i=0; i<num; i++)
  336. {
  337. ret = msdos_sector_read(dosp, sector + i, ptr);
  338. if (ret == -1)
  339. return -1;
  340. len += ret;
  341. ptr += ret;
  342. }
  343. return len;
  344. }
  345. /*
  346. * Write n sectors to the file.
  347. * Returns -1 on error.
  348. */
  349. int msdos_nsector_write(MSDOS *dosp, int sector, int num, char *buffer)
  350. {
  351. int i, ret, len=0;
  352. char *ptr=buffer;
  353. for (i=0; i<num; i++)
  354. {
  355. ret = msdos_sector_write(dosp, sector + i, ptr);
  356. if (ret == -1)
  357. return -1;
  358. len += ret;
  359. ptr += ret;
  360. }
  361. return len;
  362. }
  363. /*
  364. * Read n clusters from the file.
  365. * Returns -1 on error.
  366. */
  367. int msdos_ncluster_read(MSDOS *dosp, int cluster, int num, char *buffer)
  368. {
  369. int i, ret, len=0;
  370. char *ptr=buffer;
  371. for (i=0; i<num; i++)
  372. {
  373. ret = msdos_cluster_read(dosp, cluster + i, ptr);
  374. if (ret == -1)
  375. return -1;
  376. len += ret;
  377. ptr += ret;
  378. }
  379. return len;
  380. }
  381. /*
  382. * Write n clusters to the file.
  383. * Returns -1 on error.
  384. */
  385. int msdos_ncluster_write(MSDOS *dosp, int cluster, int num, char *buffer)
  386. {
  387. int i, ret, len=0;
  388. char *ptr=buffer;
  389. for (i=0; i<num; i++)
  390. {
  391. ret = msdos_cluster_write(dosp, cluster + i, ptr);
  392. if (ret == -1)
  393. return -1;
  394. len += ret;
  395. ptr += ret;
  396. }
  397. return len;
  398. }
  399. /************************************************************************
  400. * TOOLS
  401. ************************************************************************/
  402. void convert_to_timestamp(MSDOSDirEntry *dirp);
  403. void convert_from_timestamp(MSDOSDirEntry *dirp);
  404. void convert_from_attr_byte(MSDOSDirEntry *dirp);
  405. void convert_to_attr_byte(MSDOSDirEntry *dirp);
  406. void msdos_read_boot_sector(MSDOS *dosp);
  407. void msdos_write_boot_sector(MSDOS *dosp);
  408. void msdos_read_fat_table(MSDOS *dosp);
  409. void msdos_write_fat_table(MSDOS *dosp);
  410. void msdos_read_dir_entry(MSDOS *dosp, MSDOSDirEntry *parent, MSDOSDirEntry *child, char *buffer);
  411. void msdos_write_dir_entry(MSDOS *dosp, MSDOSDirEntry *dirp, char *buffer);
  412. MSDOSDirEntry *msdos_read_new_dir_entry(MSDOS *dosp, MSDOSDirEntry *parent, char *buffer);
  413. void msdos_close(MSDOS *dosp);
  414. MSDOS *msdos_open(const char *devname);
  415. /*
  416. * Get an unsigned value from a buffer.
  417. */
  418. unsigned get_unsigned(unsigned char *bufp, int len)
  419. {
  420. unsigned value = 0;
  421. int shift = 0;
  422. while(len--)
  423. {
  424. value |= *bufp++ << shift;
  425. shift += 8;
  426. }
  427. return value;
  428. }
  429. void put_unsigned(unsigned char *bufp, int len, unsigned value)
  430. {
  431. while(len--)
  432. {
  433. *bufp++ = value;
  434. value >>= 8;
  435. }
  436. }
  437. void DE_MONTH_NAME(int month, char *monthStr)
  438. {
  439. switch(month+1)
  440. {
  441. case 1:
  442. strcpy(monthStr, "Jan");
  443. break;
  444. case 2:
  445. strcpy(monthStr, "Feb");
  446. break;
  447. case 3:
  448. strcpy(monthStr, "Mar");
  449. break;
  450. case 4:
  451. strcpy(monthStr, "Apr");
  452. break;
  453. case 5:
  454. strcpy(monthStr, "May");
  455. break;
  456. case 6:
  457. strcpy(monthStr, "Jun");
  458. break;
  459. case 7:
  460. strcpy(monthStr, "Jul");
  461. break;
  462. case 8:
  463. strcpy(monthStr, "Aug");
  464. break;
  465. case 9:
  466. strcpy(monthStr, "Sep");
  467. break;
  468. case 10:
  469. strcpy(monthStr, "Oct");
  470. break;
  471. case 11:
  472. strcpy(monthStr, "Nov");
  473. break;
  474. case 12:
  475. strcpy(monthStr, "Dec");
  476. break;
  477. default:
  478. strcpy(monthStr, "Err");
  479. break;
  480. }
  481. }
  482. void DE_NOW(MSDOSDirEntry *dirp)
  483. {
  484. time_t sec;
  485. struct tm *now;
  486. MSDOSTimeStamp *ts;
  487. sec = time(NULL);
  488. now = localtime(&sec);
  489. ts = &dirp->timestamp;
  490. ts->second = now->tm_sec;
  491. ts->minute = now->tm_min;
  492. ts->hour = now->tm_hour;
  493. ts->day = now->tm_mday;
  494. ts->month = now->tm_mon;
  495. ts->year = (now->tm_year)+1900;
  496. DE_MONTH_NAME(ts->month, ts->monthStr);
  497. convert_from_timestamp(dirp);
  498. }
  499. /* remove trailing whitespace from a filename */
  500. void ws_trim(char *str)
  501. {
  502. int i=0;
  503. while (str[i]!='\0')
  504. i++;
  505. i--;
  506. while (str[i]==' ')
  507. {
  508. str[i]='\0';
  509. i--;
  510. }
  511. }
  512. /* pad a filename with whitespace */
  513. void ws_pad(char *str, int len)
  514. {
  515. int i=0;
  516. for(i=0;i<len;i++)
  517. {
  518. if (str[i]=='\0')
  519. {
  520. str[i]=' ';
  521. str[i+1]='\0';
  522. }
  523. }
  524. }
  525. void convert_to_timestamp(MSDOSDirEntry *dirp)
  526. {
  527. MSDOSTimeStamp *ts = &dirp->timestamp;
  528. ts->second = DE_TIME_SEC(dirp->time);
  529. ts->minute = DE_TIME_MIN(dirp->time);
  530. ts->hour = DE_TIME_HOUR(dirp->time);
  531. ts->day = DE_DATE_DAY(dirp->date);
  532. ts->month = DE_DATE_MONTH(dirp->date);
  533. ts->year = DE_DATE_YEAR(dirp->date);
  534. DE_MONTH_NAME(ts->month, ts->monthStr);
  535. }
  536. void convert_from_timestamp(MSDOSDirEntry *dirp)
  537. {
  538. MSDOSTimeStamp *ts = &dirp->timestamp;
  539. dirp->time = DE_TIME(ts->second, ts->minute, ts->hour);
  540. dirp->date = DE_DATE(ts->day, ts->month, ts->year);
  541. }
  542. void convert_from_attr_byte(MSDOSDirEntry *dirp)
  543. {
  544. int attr = dirp->attr;
  545. dirp->attr_read_only = (0x1 & (attr >> ATTR_READ_ONLY_SHIFT));
  546. dirp->attr_hidden = (0x1 & (attr >> ATTR_HIDDEN_SHIFT));
  547. dirp->attr_system = (0x1 & (attr >> ATTR_SYSTEM_SHIFT));
  548. dirp->attr_vlabel = (0x1 & (attr >> ATTR_VLABEL_SHIFT));
  549. dirp->attr_subdir = (0x1 & (attr >> ATTR_SUBDIR_SHIFT));
  550. dirp->attr_archive = (0x1 & (attr >> ATTR_ARCHIVE_SHIFT));
  551. }
  552. void convert_to_attr_byte(MSDOSDirEntry *dirp)
  553. {
  554. int attr = dirp->attr;
  555. attr |= (dirp->attr_read_only << ATTR_READ_ONLY_SHIFT);
  556. attr |= (dirp->attr_hidden << ATTR_HIDDEN_SHIFT);
  557. attr |= (dirp->attr_system << ATTR_SYSTEM_SHIFT);
  558. attr |= (dirp->attr_vlabel << ATTR_VLABEL_SHIFT);
  559. attr |= (dirp->attr_subdir << ATTR_SUBDIR_SHIFT);
  560. attr |= (dirp->attr_archive << ATTR_ARCHIVE_SHIFT);
  561. dirp->attr = attr;
  562. }
  563. int wipe_file_fat(MSDOS *dosp, MSDOSDirEntry *dirp)
  564. {
  565. int temp, cluster = dirp->first_cluster;
  566. while (!((0xff8 <= cluster) && (cluster <= 0xfff)))
  567. {
  568. if ((cluster == 0x000) || (cluster == 0xff7) || ((0xff0 <= cluster) && (cluster <= 0xff6)) || (cluster > 0xfff))
  569. return -1;
  570. temp = cluster;
  571. cluster = dosp->fat_table[cluster];
  572. dosp->fat_table[temp] = 0x000;
  573. }
  574. dosp->fat_table[cluster] = 0x000;
  575. return 0;
  576. }
  577. int insert_file_fat(MSDOS *dosp, int start, int prev)
  578. {
  579. int cluster;
  580. cluster = (start + 1) % NUMBER_OF_LOGICAL_CLUSTERS;
  581. while ((cluster != start) && (dosp->fat_table[cluster] != 0x000))
  582. {
  583. cluster = (cluster + 1) % NUMBER_OF_LOGICAL_CLUSTERS;
  584. }
  585. if (cluster == start)
  586. return -1;
  587. if (prev == 0xfff)
  588. dosp->fat_table[cluster] = 0xfff;
  589. else
  590. {
  591. dosp->fat_table[cluster] = dosp->fat_table[prev];
  592. dosp->fat_table[prev] = cluster;
  593. }
  594. return cluster;
  595. }
  596. int count_clusters(MSDOS *dosp, MSDOSDirEntry *dirp)
  597. {
  598. int cluster = dirp->first_cluster;
  599. int count = 0;
  600. if (dirp->filename[0] == 0xe5)
  601. return -1;
  602. while (!((0xff8 <= cluster) && (cluster <= 0xfff)))
  603. {
  604. if ((cluster == 0x000) || (cluster == 0xff7) || ((0xff0 <= cluster) && (cluster <= 0xff6)) || (cluster > 0xfff))
  605. return -1;
  606. cluster = dosp->fat_table[cluster];
  607. count++;
  608. }
  609. return count;
  610. }
  611. int get_last_cluster(MSDOS *dosp, MSDOSDirEntry *dirp)
  612. {
  613. int temp, cluster = dirp->first_cluster;
  614. if (dirp->filename[0] == 0xe5)
  615. return -1;
  616. while (!((0xff8 <= cluster) && (cluster <= 0xfff)))
  617. {
  618. if ((cluster == 0x000) || (cluster == 0xff7) || ((0xff0 <= cluster) && (cluster <= 0xff6)) || (cluster > 0xfff))
  619. return -1;
  620. temp = cluster;
  621. cluster = dosp->fat_table[cluster];
  622. }
  623. return temp;
  624. }
  625. char valid_dos_char(const char c)
  626. {
  627. if ( (c == '"') || (c == '*') || (c == '+') || (c == ',') ||
  628. (c == '.') || (c == '/') || (c == ':') || (c == ';') ||
  629. (c == '<') || (c == '=') || (c == '>') || (c == '?') ||
  630. (c == '[') || (c == '\\') || (c == ']') || (c == '|') )
  631. return '$';
  632. else
  633. return toupper(c);
  634. }
  635. void valid_dos_name(const char *name, char *fname, char *ext)
  636. {
  637. int i, ext_pos, max;
  638. i=0;
  639. while (name[i]!='\0')
  640. i++;
  641. max=i;
  642. while ((name[i]!='.') && (i>0))
  643. {
  644. i--;
  645. }
  646. ext_pos = i;
  647. if (ext_pos!=0)
  648. {
  649. for (i=0;(((i+ext_pos)<max)&&(i<DE_EXTENSION_LEN));i++)
  650. ext[i]=name[i+ext_pos+1];
  651. }
  652. else
  653. {
  654. ext_pos=max;
  655. }
  656. for (i=0;((i<ext_pos)&&(i<DE_FILENAME_LEN));i++)
  657. fname[i]=name[i];
  658. for (i=0;i<DE_FILENAME_LEN;i++)
  659. fname[i] = valid_dos_char(fname[i]);
  660. for (i=0;i<DE_EXTENSION_LEN;i++)
  661. ext[i] = valid_dos_char(ext[i]);
  662. if ((unsigned char)fname[0]==0xe5)
  663. fname[0]=0x05;
  664. if (fname[0]==' ')
  665. fname[0]='$';
  666. }
  667. void msdos_print_dir_entry_name_override(MSDOSDirEntry *dirp, char *name_override)
  668. {
  669. MSDOSTimeStamp *ts = &dirp->timestamp;
  670. char out_name[TOTAL_FILENAME_LEN+1];
  671. if (name_override[0] != '\0')
  672. strcpy(out_name, name_override);
  673. else
  674. {
  675. strcpy(out_name, dirp->tname);
  676. }
  677. if (out_name[0]==0x05)
  678. out_name[0]=0xe5;
  679. if (dirp->attr_read_only)
  680. printf("R");
  681. else
  682. printf("W");
  683. if (dirp->attr_hidden)
  684. printf("H");
  685. else
  686. printf("-");
  687. if (dirp->attr_system)
  688. printf("S");
  689. else
  690. printf("-");
  691. if (dirp->attr_vlabel)
  692. printf("V");
  693. else
  694. printf("-");
  695. if (dirp->attr_subdir)
  696. printf("D");
  697. else
  698. printf("-");
  699. if (dirp->attr_archive)
  700. printf("A");
  701. else
  702. printf("-");
  703. printf(" %s %02d, %02d; %02d:%02d:%02d ", ts->monthStr, ts->day, ts->year,
  704. ts->hour, ts->minute, ts->second);
  705. printf("%11d %-13s -> %03x (%d)\n", dirp->filesize, out_name, dirp->first_cluster, dirp->first_cluster);
  706. }
  707. void msdos_print_dir_entry(MSDOSDirEntry *dirp)
  708. {
  709. msdos_print_dir_entry_name_override(dirp, "");
  710. }
  711. int read_dir_entry_contents(MSDOS *dosp, MSDOSDirEntry *dirp, char *buffer)
  712. {
  713. int ret, len = 0;
  714. unsigned cluster = dirp->first_cluster;
  715. char *ptr = buffer;
  716. if (cluster == 0x000)
  717. return -1;
  718. while ((cluster != 0x000) && (!((0xff8 <= cluster) && (cluster <= 0xfff))))
  719. {
  720. if ((cluster == 0xff7) || ((0xff0 <= cluster) && (cluster <= 0xff6)) || (cluster > 0xfff))
  721. return -1;
  722. ret = msdos_cluster_read(dosp, cluster, ptr);
  723. if (ret == -1)
  724. return -1;
  725. len += ret;
  726. ptr += ret;
  727. cluster = dosp->fat_table[cluster];
  728. }
  729. return len;
  730. }
  731. int write_dir_entry_contents(MSDOS *dosp, MSDOSDirEntry *dirp, char *buffer)
  732. {
  733. int ret, len = 0;
  734. unsigned cluster = dirp->first_cluster;
  735. char *ptr = buffer;
  736. if (cluster == 0x000)
  737. return -1;
  738. while ((cluster != 0x000) && (!((0xff8 <= cluster) && (cluster <= 0xfff))))
  739. {
  740. if ((cluster == 0xff7) || ((0xff0 <= cluster) && (cluster <= 0xff6)) || (cluster > 0xfff))
  741. return -1;
  742. ret = msdos_cluster_write(dosp, cluster, ptr);
  743. if (ret == -1)
  744. return -1;
  745. len += ret;
  746. ptr += ret;
  747. cluster = dosp->fat_table[cluster];
  748. }
  749. return len;
  750. }
  751. int read_dir_from_disk(MSDOS *dosp, MSDOSDirEntry *dirp, char **buffer)
  752. {
  753. int ret, clusters_read;
  754. if (!(dirp->path[1]))
  755. {
  756. clusters_read = ROOT_DIR_LEN*BYTES_PER_SECTOR;
  757. *buffer = (char *) malloc(sizeof(char)*clusters_read);
  758. ret = msdos_nsector_read(dosp, ROOT_DIR_SECTOR, ROOT_DIR_LEN, *buffer);
  759. }
  760. else
  761. {
  762. clusters_read = count_clusters(dosp, dirp)*BYTES_PER_CLUSTER;
  763. *buffer = (char *) malloc(sizeof(char)*clusters_read);
  764. ret = read_dir_entry_contents(dosp, dirp, *buffer);
  765. }
  766. if (ret == -1)
  767. {
  768. perror("Error reading directory from disk.\n");
  769. free(*buffer);
  770. return -1;
  771. }
  772. return clusters_read;
  773. }
  774. int write_dir_to_disk(MSDOS *dosp, MSDOSDirEntry *dirp, char **buffer)
  775. {
  776. int ret, clusters_write;
  777. if (!(dirp->path[1]))
  778. {
  779. clusters_write = ROOT_DIR_LEN*BYTES_PER_SECTOR;
  780. ret = msdos_nsector_write(dosp, ROOT_DIR_SECTOR, ROOT_DIR_LEN, *buffer);
  781. }
  782. else
  783. {
  784. clusters_write = count_clusters(dosp, dirp)*BYTES_PER_CLUSTER;
  785. if (clusters_write <= 0)
  786. return -1;
  787. ret = write_dir_entry_contents(dosp, dirp, *buffer);
  788. }
  789. if (ret == -1)
  790. {
  791. perror("Error writing directory from disk.\n");
  792. free(*buffer);
  793. return -1;
  794. }
  795. return clusters_write;
  796. }
  797. int remove_dir_entry(MSDOS *dosp, MSDOSDirEntry *dirp)
  798. {
  799. char *buffer;
  800. int i, max_read;
  801. MSDOSDirEntry *parent = dirp->parent;
  802. max_read = read_dir_from_disk(dosp, parent, &buffer);
  803. if (max_read == -1)
  804. {
  805. perror("Directory read error.\n");
  806. return -1;
  807. }
  808. for(i=0;i<max_read;i+=BYTES_PER_DIR_ENTRY)
  809. {
  810. if (((get_unsigned(buffer+i+DE_ATTR_OFF, DE_ATTR_LEN) >> ATTR_VLABEL_SHIFT) & 0x1) == 1)
  811. continue;
  812. if (strncmp(dirp->filename, buffer+i+DE_FILENAME_OFF, DE_FILENAME_LEN)==0)
  813. {
  814. buffer[i+DE_FILENAME_OFF] = 0xe5;
  815. max_read = write_dir_to_disk(dosp, parent, &buffer);
  816. if (max_read == -1)
  817. {
  818. perror("Directory write error.\n");
  819. free(buffer);
  820. return -1;
  821. }
  822. free(buffer);
  823. return 0;
  824. }
  825. }
  826. free(buffer);
  827. return -1;
  828. }
  829. int add_dir_entry(MSDOS *dosp, MSDOSDirEntry *dirp)
  830. {
  831. char *buffer, *tmp;
  832. int i, max_read, last_cluster, num_clusters, cluster;
  833. MSDOSDirEntry *parent = dirp->parent;
  834. max_read = read_dir_from_disk(dosp, parent, &buffer);
  835. if (max_read == -1)
  836. {
  837. perror("Directory read error.\n");
  838. return -1;
  839. }
  840. for(i=0;i<max_read;i+=BYTES_PER_DIR_ENTRY)
  841. {
  842. if (((unsigned char) buffer[i+DE_FILENAME_OFF] == 0xe5) || (buffer[i+DE_FILENAME_OFF] == 0x00))
  843. break;
  844. }
  845. if (!(i<max_read))
  846. {
  847. if (parent == dosp->root_dir)
  848. {
  849. perror("Max number of entries for root dir already reached.\n");
  850. free(buffer);
  851. return -1;
  852. }
  853. /* Last sector of directory is full, so add a new one to the chain. */
  854. last_cluster = get_last_cluster(dosp, dirp);
  855. cluster = insert_file_fat(dosp, last_cluster, last_cluster);
  856. if ((cluster == 0x000) || (cluster == 0xff7) || ((0xff0 <= cluster) && (cluster <= 0xff6))
  857. || (cluster == -1) || (cluster > 0xfff) || ((0xff8 <= cluster) && (cluster <= 0xfff)))
  858. {
  859. perror("Directory entry allocation error.\n");
  860. free(buffer);
  861. return -1;
  862. }
  863. num_clusters = count_clusters(dosp, parent);
  864. tmp = (char *) malloc(sizeof(char)*num_clusters*BYTES_PER_CLUSTER);
  865. memset(tmp, '\0', sizeof(char)*num_clusters*BYTES_PER_CLUSTER);
  866. memcpy(tmp, buffer, sizeof(char)*(num_clusters-1)*BYTES_PER_CLUSTER);
  867. free(buffer);
  868. buffer = tmp;
  869. tmp = NULL;
  870. }
  871. msdos_write_dir_entry(dosp, dirp, buffer+i);
  872. max_read = write_dir_to_disk(dosp, parent, &buffer);
  873. if (max_read == -1)
  874. {
  875. perror("Directory write error.\n");
  876. free(buffer);
  877. return -1;
  878. }
  879. free(buffer);
  880. return 0;
  881. }
  882. MSDOSDirEntry* find_dir_entry(MSDOS *dosp, MSDOSDirEntry *parent, const char *name)
  883. {
  884. char *buffer;
  885. int i, max_read;
  886. MSDOSDirEntry *dirp, *cur_dir = dosp->current_dir;
  887. dirp = (MSDOSDirEntry *) malloc(sizeof(MSDOSDirEntry));
  888. memset(dirp, '\0', sizeof(MSDOSDirEntry));
  889. max_read = read_dir_from_disk(dosp, cur_dir, &buffer);
  890. if (max_read == -1)
  891. {
  892. perror("Directory read error.\n");
  893. free(dirp);
  894. return 0;
  895. }
  896. for(i=0;i<max_read;i+=BYTES_PER_DIR_ENTRY)
  897. {
  898. msdos_read_dir_entry(dosp, cur_dir, dirp, buffer+i);
  899. if (dirp->filename[0] == 0x00)
  900. break;
  901. if (dirp->attr_vlabel==1)
  902. continue;
  903. if (strcmp(dirp->tname, name)==0)
  904. {
  905. free(buffer);
  906. return dirp;
  907. }
  908. }
  909. free(dirp);
  910. free(buffer);
  911. return 0;
  912. }
  913. /* Use "not-empty" so that an error isn't confuse with true */
  914. int dir_not_empty(MSDOS *dosp, MSDOSDirEntry *parent)
  915. {
  916. char *buffer;
  917. int i, max_read;
  918. MSDOSDirEntry *dirp, *cur_dir = dosp->current_dir;
  919. dirp = (MSDOSDirEntry *) malloc(sizeof(MSDOSDirEntry));
  920. memset(dirp, '\0', sizeof(MSDOSDirEntry));
  921. max_read = read_dir_from_disk(dosp, parent, &buffer);
  922. if (max_read == -1)
  923. {
  924. perror("Directory read error.\n");
  925. free(dirp);
  926. return -1;
  927. }
  928. for(i=0;i<max_read;i+=BYTES_PER_DIR_ENTRY)
  929. {
  930. msdos_read_dir_entry(dosp, cur_dir, dirp, buffer+i);
  931. if (dirp->filename[0] == 0x00)
  932. break;
  933. if ((strcmp(dirp->tname, ".")==0) || (strcmp(dirp->tname, "..")==0))
  934. continue;
  935. if (dirp->filename[0]!=0xe5)
  936. {
  937. free(buffer);
  938. free(dirp);
  939. return 1;
  940. }
  941. }
  942. free(dirp);
  943. free(buffer);
  944. return 0;
  945. }
  946. /************************************************************************
  947. * IMPLEMENTATION
  948. ************************************************************************/
  949. /*
  950. * TODO: put your implementation here.
  951. */
  952. int msdos_print_boot_sector(MSDOS *dosp)
  953. {
  954. int i;
  955. printf(" Boot Sector Info: \n");
  956. printf(" Jump to Bootstrap:");
  957. for(i=0;i<BS_JUMP_LEN;i++)
  958. printf(" %02x", dosp->boot_sector->jump[i]);
  959. printf("\n");
  960. printf(" Manufacturer Name: %s\n", (dosp->boot_sector->manufacturer_name));
  961. printf(" Bytes per Sector: %d\n", dosp->boot_sector->bytes_per_sector);
  962. printf(" Sectors per Cluster: %d\n", dosp->boot_sector->sectors_per_cluster);
  963. printf(" Boot Record Sectors: %d\n", dosp->boot_sector->boot_record_sectors);
  964. printf(" Number of Fats: %d\n", dosp->boot_sector->number_of_fats);
  965. printf(" Number of Root Entries: %d\n", dosp->boot_sector->number_of_root_entries);
  966. printf(" Number of Logical Clusters: %d\n", dosp->boot_sector->number_of_logical_clusters);
  967. printf(" Media Type: %x\n", dosp->boot_sector->media_type);
  968. printf(" Sectors per Fat: %d\n", dosp->boot_sector->sectors_per_fat);
  969. printf(" Sectors per Track: %d\n", dosp->boot_sector->sectors_per_track);
  970. printf(" Number of Heads: %d\n", dosp->boot_sector->number_of_heads);
  971. printf(" Number of Hidden Sectors: %d\n", dosp->boot_sector->number_of_hidden_sectors);
  972. printf(" Signature:");
  973. for(i=0;i<BS_SIGNATURE_LEN;i++)
  974. printf(" %02x", dosp->boot_sector->signature[i]);
  975. printf("\n");
  976. return 0;
  977. }
  978. int msdos_print_fat(MSDOS *dosp)
  979. {
  980. long i;
  981. for(i=0;i<dosp->fat_entries;i++)
  982. printf("FAT Entry 0x%03lx: 0x%03x (%ld: %d)\n", i, dosp->fat_table[i], i, dosp->fat_table[i]);
  983. return 0;
  984. }
  985. int msdos_ls(MSDOS *dosp)
  986. {
  987. char *buffer;
  988. int i, max_read=0, total_bytes=0, num_files=0, num_dirs=0;
  989. MSDOSDirEntry *dirp, *cur_dir = dosp->current_dir;
  990. max_read = read_dir_from_disk(dosp, cur_dir, &buffer);
  991. if (max_read == -1)
  992. {
  993. perror("Directory read error.\n");
  994. return -1;
  995. }
  996. printf(" Current Volume is %s\n", dosp->root_dir->tname);
  997. printf(" Directory of %s\n", cur_dir->path);
  998. /* Apparently this is included in the FAT system, at least on the floppy image.
  999. But in case it wasn't here's code to print the directories . and ..
  1000. Code in chdir is more efficient for using these, even though it is available in the FAT.
  1001. if (cur_dir->path[1])
  1002. {
  1003. msdos_print_dir_entry_name_override(cur_dir, ".");
  1004. msdos_print_dir_entry_name_override(cur_dir->parent, "..");
  1005. }
  1006. */
  1007. dirp = (MSDOSDirEntry *) malloc(sizeof(MSDOSDirEntry));
  1008. memset(dirp, '\0', sizeof(MSDOSDirEntry));
  1009. for(i=0;i<max_read;i+=BYTES_PER_DIR_ENTRY)
  1010. {
  1011. msdos_read_dir_entry(dosp, cur_dir, dirp, buffer+i);
  1012. if (dirp->filename[0] == 0x00)
  1013. break;
  1014. if (!(dirp->filename[0] == 0xe5))
  1015. {
  1016. msdos_print_dir_entry(dirp);
  1017. total_bytes += dirp->filesize;
  1018. if (dirp->attr_subdir)
  1019. num_dirs += 1;
  1020. else
  1021. num_files += 1;
  1022. }
  1023. }
  1024. printf(" %d File(s) %d bytes\n", num_files, total_bytes);
  1025. printf(" %d Dirs(s)\n", num_dirs);
  1026. printf("\n");
  1027. free(buffer);
  1028. free(dirp);
  1029. return 0;
  1030. }
  1031. /* Duplicate ls call, just because -> compatible with original dos. */
  1032. int msdos_dir(MSDOS *dosp)
  1033. {
  1034. return msdos_ls(dosp);
  1035. }
  1036. int msdos_chdir(MSDOS *dosp, const char *name)
  1037. {
  1038. MSDOSDirEntry *new_dir;
  1039. if (strcmp(".", name) == 0)
  1040. return 0;
  1041. else if (strcmp("..", name) == 0)
  1042. {
  1043. if (dosp->current_dir == dosp->root_dir)
  1044. {
  1045. printf("No parent of root directory.\n");
  1046. return -1;
  1047. }
  1048. new_dir = dosp->current_dir->parent;
  1049. free(dosp->current_dir);
  1050. }
  1051. else
  1052. {
  1053. new_dir = find_dir_entry(dosp, dosp->current_dir, name);
  1054. if ((!(new_dir)) || (!(new_dir->attr_subdir)))
  1055. {
  1056. printf("No such directory: %s\n", name);
  1057. free(new_dir);
  1058. return -1;
  1059. }
  1060. }
  1061. dosp->current_dir = new_dir;
  1062. return 0;
  1063. }
  1064. /* Duplicate cd call due to ill specification */
  1065. int msdos_cd(MSDOS *dosp, const char *name)
  1066. {
  1067. return msdos_chdir(dosp,name);
  1068. }
  1069. /* Print current directory name -> useful command to have.*/
  1070. int msdos_pwd(MSDOS *dosp)
  1071. {
  1072. printf(" %s\n", dosp->current_dir->path);
  1073. return 0;
  1074. }
  1075. /* Make file, or update time -> useful command to have.*/
  1076. int msdos_touch(MSDOS *dosp, const char *name)
  1077. {
  1078. MSDOSDirEntry *filep;
  1079. char *buffer, dos_name[TOTAL_FILENAME_LEN+1];
  1080. char filename[DE_FILENAME_LEN+1], extension[DE_EXTENSION_LEN+1];
  1081. int ret;
  1082. unsigned cluster;
  1083. memset(dos_name, 0, TOTAL_FILENAME_LEN+1);
  1084. memset(filename, 0, DE_FILENAME_LEN+1);
  1085. memset(extension, 0, DE_EXTENSION_LEN+1);
  1086. valid_dos_name(name, filename, extension);
  1087. strcpy(dos_name, filename);
  1088. ws_trim(dos_name);
  1089. ws_pad(filename, DE_FILENAME_LEN);
  1090. ws_pad(extension, DE_EXTENSION_LEN);
  1091. if (!(strcmp(extension, " ") == 0))
  1092. {
  1093. strcat(dos_name, ".");
  1094. strcat(dos_name, extension);
  1095. ws_trim(dos_name);
  1096. }
  1097. if (dos_name[0]==0x05)
  1098. dos_name[0]=0xe5;
  1099. filep = find_dir_entry(dosp, dosp->current_dir, dos_name);
  1100. if (filep)
  1101. {
  1102. if (filep->attr_read_only == 1)
  1103. {
  1104. printf("No access permissions to file: %s", name);
  1105. free(filep);
  1106. return -1;
  1107. }
  1108. /* Rather than actually updating the directory entry, be lazy.
  1109. remove the entry, then make a new one with the updated time. */
  1110. if (remove_dir_entry(dosp, filep))
  1111. {
  1112. printf("Update error. Filesystem possibly corrupted.\n");
  1113. msdos_write_fat_table(dosp);
  1114. free(filep);
  1115. return -1;
  1116. }
  1117. DE_NOW(filep);
  1118. if (add_dir_entry(dosp, filep))
  1119. {
  1120. printf("Update error. Filesystem possibly corrupted.\n");
  1121. msdos_write_fat_table(dosp);
  1122. free(filep);
  1123. return -1;
  1124. }
  1125. free(filep);
  1126. return 0;
  1127. }
  1128. buffer = (char *) malloc(sizeof(char)*BYTES_PER_CLUSTER);
  1129. filep = (MSDOSDirEntry *) malloc(sizeof(MSDOSDirEntry));
  1130. if ((buffer == 0) || (filep ==0))
  1131. {
  1132. fprintf(stderr, "Out of memory\n");
  1133. return -1;
  1134. }
  1135. memset(buffer, '\0', sizeof(char)*BYTES_PER_CLUSTER);
  1136. memset(filep, '\0', sizeof(MSDOSDirEntry));
  1137. strcpy(filep->filename, filename);
  1138. strcpy(filep->extension, extension);
  1139. filep->parent = dosp->current_dir;
  1140. strcpy(filep->tname, dos_name);
  1141. strcpy(filep->path, filep->parent->path);
  1142. if (filep->parent != dosp->root_dir)
  1143. strcat(filep->path, "\\");
  1144. strcat(filep->path, filep->tname);
  1145. DE_NOW(filep);
  1146. filep->filesize = 0;
  1147. filep->attr_subdir = 0;
  1148. convert_to_attr_byte(filep);
  1149. filep->first_cluster = insert_file_fat(dosp, dosp->current_dir->first_cluster, 0xfff);
  1150. cluster = filep->first_cluster;
  1151. if ((cluster == 0x000) || (cluster == 0xff7) || ((0xff0 <= cluster) && (cluster <= 0xff6))
  1152. || (cluster == -1) || (cluster > 0xfff) || ((0xff8 <= cluster) && (cluster <= 0xfff)))
  1153. {
  1154. perror("File allocation error.\n");
  1155. free(buffer);
  1156. free(filep);
  1157. return -1;
  1158. }
  1159. memset(buffer, '\0', sizeof(char)*BYTES_PER_CLUSTER);
  1160. ret = msdos_cluster_write(dosp, cluster, buffer);
  1161. if (ret == -1)
  1162. {
  1163. perror("File write error.\n");
  1164. free(buffer);
  1165. free(filep);
  1166. return -1;
  1167. }
  1168. if (add_dir_entry(dosp, filep))
  1169. {
  1170. printf("Creation error. Filesystem possibly corrupted.\n");
  1171. msdos_write_fat_table(dosp);
  1172. free(buffer);
  1173. free(filep);
  1174. return -1;
  1175. }
  1176. msdos_write_fat_table(dosp);
  1177. free(buffer);
  1178. free(filep);
  1179. return 0;
  1180. }
  1181. int msdos_rm(MSDOS *dosp, const char *name)
  1182. {
  1183. MSDOSDirEntry *filep;
  1184. filep = find_dir_entry(dosp, dosp->current_dir, name);
  1185. if ((!(filep)) || (filep->attr_subdir))
  1186. {
  1187. printf("No such file: %s\n", name);
  1188. free(filep);
  1189. return -1;
  1190. }
  1191. if (filep->first_cluster <= 0)
  1192. {
  1193. printf("Invalid file: %s\n", name);
  1194. free(filep);
  1195. return -1;
  1196. }
  1197. if (filep->attr_read_only == 1)
  1198. {
  1199. printf("No access permissions for file: %s", name);
  1200. free(filep);
  1201. return -1;
  1202. }
  1203. if (wipe_file_fat(dosp, filep) || remove_dir_entry(dosp, filep))
  1204. {
  1205. printf("Deletion error. Filesystem possibly corrupted.\n");
  1206. free(filep);
  1207. msdos_write_fat_table(dosp);
  1208. return -1;
  1209. }
  1210. free(filep);
  1211. msdos_write_fat_table(dosp);
  1212. return 0;
  1213. }
  1214. /* Duplicate rm call, just because -> compatible with original dos. */
  1215. int msdos_erase(MSDOS *dosp, const char *name)
  1216. {
  1217. return msdos_rm(dosp, name);
  1218. }
  1219. int msdos_mkdir(MSDOS *dosp, const char *name)
  1220. {
  1221. MSDOSDirEntry *filep, *child, *parent;
  1222. char *buffer, dos_name[TOTAL_FILENAME_LEN+1];
  1223. char filename[DE_FILENAME_LEN+1], extension[DE_EXTENSION_LEN+1];
  1224. int ret;
  1225. unsigned cluster;
  1226. memset(dos_name, 0, TOTAL_FILENAME_LEN+1);
  1227. memset(filename, 0, DE_FILENAME_LEN+1);
  1228. memset(extension, 0, DE_EXTENSION_LEN+1);
  1229. valid_dos_name(name, filename, extension);
  1230. strcpy(dos_name, filename);
  1231. ws_trim(dos_name);
  1232. if (dos_name[0]==0x05)
  1233. dos_name[0]=0xe5;
  1234. ws_pad(filename, DE_FILENAME_LEN);
  1235. ws_pad(extension, DE_EXTENSION_LEN);
  1236. filep = find_dir_entry(dosp, dosp->current_dir, dos_name);
  1237. if (filep)
  1238. {
  1239. printf("Directory already exists: %s\n", name);
  1240. printf(" Not overwritten.\n");
  1241. free(filep);
  1242. return -1;
  1243. }
  1244. buffer = (char *) malloc(sizeof(char)*BYTES_PER_CLUSTER);
  1245. filep = (MSDOSDirEntry *) malloc(sizeof(MSDOSDirEntry));
  1246. if ((buffer == 0) || (filep ==0))
  1247. {
  1248. fprintf(stderr, "Out of memory\n");
  1249. return -1;
  1250. }
  1251. memset(buffer, '\0', sizeof(char)*BYTES_PER_CLUSTER);
  1252. memset(filep, '\0', sizeof(MSDOSDirEntry));
  1253. strcpy(filep->filename, filename);
  1254. strcpy(filep->extension, extension);
  1255. filep->parent = dosp->current_dir;
  1256. strcpy(filep->tname, dos_name);
  1257. strcpy(filep->path, filep->parent->path);
  1258. if (filep->parent != dosp->root_dir)
  1259. strcat(filep->path, "\\");
  1260. strcat(filep->path, filep->tname);
  1261. DE_NOW(filep);
  1262. filep->filesize = 0;
  1263. filep->attr_subdir = 1;
  1264. convert_to_attr_byte(filep);
  1265. filep->first_cluster = insert_file_fat(dosp, dosp->current_dir->first_cluster, 0xfff);
  1266. cluster = filep->first_cluster;
  1267. if ((cluster == 0x000) || (cluster == 0xff7) || ((0xff0 <= cluster) && (cluster <= 0xff6))
  1268. || (cluster == -1) || (cluster > 0xfff) || ((0xff8 <= cluster) && (cluster <= 0xfff)))
  1269. {
  1270. perror("Directory allocation error.\n");
  1271. free(buffer);
  1272. free(filep);
  1273. return -1;
  1274. }
  1275. memset(buffer, '\0', sizeof(char)*BYTES_PER_CLUSTER);
  1276. ret = msdos_cluster_write(dosp, cluster, buffer);
  1277. if (ret == -1)
  1278. {
  1279. perror("File write error.\n");
  1280. free(buffer);
  1281. free(filep);
  1282. return -1;
  1283. }
  1284. /* make . and .. entries -- copy the directory entries,
  1285. then hack them a little to use add_dir_entry for simplicity */
  1286. child = (MSDOSDirEntry *) malloc(sizeof(MSDOSDirEntry));
  1287. parent = (MSDOSDirEntry *) malloc(sizeof(MSDOSDirEntry));
  1288. if ((child == 0) || (parent ==0))
  1289. {
  1290. fprintf(stderr, "Out of memory\n");
  1291. return -1;
  1292. }
  1293. memcpy(child, filep, sizeof(MSDOSDirEntry));
  1294. memcpy(parent, filep->parent, sizeof(MSDOSDirEntry));
  1295. strcpy(child->filename, ".");
  1296. strcpy(parent->filename, "..");
  1297. ws_pad(child->filename, DE_FILENAME_LEN);
  1298. ws_pad(parent->filename, DE_FILENAME_LEN);
  1299. child->parent = filep;
  1300. parent->parent = filep;
  1301. if ((add_dir_entry(dosp, filep)) || (add_dir_entry(dosp, child)) || (add_dir_entry(dosp, parent)))
  1302. {
  1303. printf("Creation error. Filesystem possibly corrupted.\n");
  1304. msdos_write_fat_table(dosp);
  1305. free(buffer);
  1306. free(filep);
  1307. free(child);
  1308. free(parent);
  1309. return -1;
  1310. }
  1311. msdos_write_fat_table(dosp);
  1312. free(buffer);
  1313. free(filep);
  1314. free(child);
  1315. free(parent);
  1316. return 0;
  1317. }
  1318. /* Duplicate mkdir call, just because -> compatible with original dos. */
  1319. int msdos_md(MSDOS *dosp, const char *name)
  1320. {
  1321. return msdos_md(dosp, name);
  1322. }
  1323. int msdos_rmdir(MSDOS *dosp, const char *name)
  1324. {
  1325. MSDOSDirEntry *filep;
  1326. filep = find_dir_entry(dosp, dosp->current_dir, name);
  1327. if ((!(filep)) || (!(filep->attr_subdir)))
  1328. {
  1329. printf("No such directory: %s\n", name);
  1330. free(filep);
  1331. return -1;
  1332. }
  1333. if ((filep->first_cluster <= 0) || (strcmp(name, ".")==0) || (strcmp(name, "..")==0))
  1334. {
  1335. printf("Invalid directory: %s\n", name);
  1336. free(filep);
  1337. return -1;
  1338. }
  1339. if (filep->attr_read_only == 1)
  1340. {
  1341. printf("No access permissions to directory: %s", name);
  1342. free(filep);
  1343. return -1;
  1344. }
  1345. if (dir_not_empty(dosp, filep))
  1346. {
  1347. printf("Directory not empty: %s\n", name);
  1348. free(filep);
  1349. return -1;
  1350. }
  1351. if (wipe_file_fat(dosp, filep) || remove_dir_entry(dosp, filep))
  1352. {
  1353. printf("Deletion error. Filesystem possibly corrupted.\n");
  1354. free(filep);
  1355. msdos_write_fat_table(dosp);
  1356. return -1;
  1357. }
  1358. free(filep);
  1359. msdos_write_fat_table(dosp);
  1360. return 0;
  1361. }
  1362. /* Duplicate rmdir call, just because -> compatible with original dos. */
  1363. int msdos_rd(MSDOS *dosp, const char *name)
  1364. {
  1365. return msdos_rmdir(dosp, name);
  1366. }
  1367. int msdos_save(MSDOS *dosp, const char *name)
  1368. {
  1369. MSDOSDirEntry *filep;
  1370. char *buffer;
  1371. int fd, ret, i, clusters_read;
  1372. unsigned cluster;
  1373. filep = find_dir_entry(dosp, dosp->current_dir, name);
  1374. if ((!(filep)) || (filep->attr_subdir))
  1375. {
  1376. printf("No such file: %s\n", name);
  1377. free(filep);
  1378. return -1;
  1379. }
  1380. clusters_read = count_clusters(dosp, filep);
  1381. if (clusters_read <= 0)
  1382. {
  1383. printf("Invalid file: %s\n", name);
  1384. free(filep);
  1385. return -1;
  1386. }
  1387. buffer = (char *) malloc(sizeof(char)*BYTES_PER_CLUSTER);
  1388. if (buffer == 0)
  1389. {
  1390. fprintf(stderr, "Out of memory\n");
  1391. free(filep);
  1392. return -1;
  1393. }
  1394. fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666);
  1395. if (fd < 0)
  1396. {
  1397. perror(name);
  1398. perror(" Not overwritten.\n");
  1399. return -1;
  1400. }
  1401. cluster = filep->first_cluster;
  1402. for(i=1;i<=clusters_read;i++)
  1403. {
  1404. if ((cluster == 0x000) || (cluster == 0xff7) || ((0xff0 <= cluster) && (cluster <= 0xff6))
  1405. || (cluster > 0xfff) || ((0xff8 <= cluster) && (cluster <= 0xfff)))
  1406. {
  1407. perror("File allocation error.\n");
  1408. close(fd);
  1409. free(buffer);
  1410. free(filep);
  1411. return -1;
  1412. }
  1413. ret = msdos_cluster_read(dosp, cluster, buffer);
  1414. if (ret == -1)
  1415. {
  1416. perror("File read error.\n");
  1417. close(fd);
  1418. free(buffer);
  1419. free(filep);
  1420. return -1;
  1421. }
  1422. /* If last cluster, and not full, just write extra, rather than whole cluster */
  1423. if ((i==clusters_read) && ((filep->filesize % BYTES_PER_CLUSTER)!=0))
  1424. write(fd, buffer, filep->filesize % BYTES_PER_CLUSTER);
  1425. else
  1426. write(fd, buffer, BYTES_PER_CLUSTER);
  1427. cluster = dosp->fat_table[cluster];
  1428. }
  1429. close(fd);
  1430. free(buffer);
  1431. free(filep);
  1432. return 0;
  1433. }
  1434. /* Duplicate save call, for clarity. */
  1435. int msdos_read(MSDOS *dosp, const char *name)
  1436. {
  1437. return msdos_save(dosp, name);
  1438. }
  1439. /* Duplicate save call, for clarity. */
  1440. int msdos_export(MSDOS *dosp, const char *name)
  1441. {
  1442. return msdos_save(dosp, name);
  1443. }
  1444. /* I don't like the use of write here, as the direction is ambiguous.
  1445. Call it load, instead, to mirror "save", though "write" has been included as well. */
  1446. int msdos_load(MSDOS *dosp, const char *name)
  1447. {
  1448. MSDOSDirEntry *filep;
  1449. char *buffer, dos_name[TOTAL_FILENAME_LEN+1];
  1450. char filename[DE_FILENAME_LEN+1], extension[DE_EXTENSION_LEN+1];
  1451. int fd, ret, i, clusters_write, max_write;
  1452. unsigned cluster;
  1453. memset(dos_name, 0, TOTAL_FILENAME_LEN+1);
  1454. memset(filename, 0, DE_FILENAME_LEN+1);
  1455. memset(extension, 0, DE_EXTENSION_LEN+1);
  1456. struct stat fstats;
  1457. ret = stat(name , &fstats);
  1458. if (ret == -1)
  1459. {
  1460. printf("No such file: %s\n", name);
  1461. return -1;
  1462. }
  1463. if (S_ISDIR(fstats.st_mode))
  1464. {
  1465. printf("Cannot load a directory.\n");
  1466. return -1;
  1467. }
  1468. fd = open(name, O_RDONLY | O_EXCL, 0666);
  1469. if (fd < 0)
  1470. {
  1471. perror(name);
  1472. return -1;
  1473. }
  1474. valid_dos_name(name, filename, extension);
  1475. strcpy(dos_name, filename);
  1476. ws_trim(dos_name);
  1477. ws_pad(filename, DE_FILENAME_LEN);
  1478. ws_pad(extension, DE_EXTENSION_LEN);
  1479. if (!(strcmp(extension, " ") == 0))
  1480. {
  1481. strcat(dos_name, ".");
  1482. strcat(dos_name, extension);
  1483. ws_trim(dos_name);
  1484. }
  1485. if (dos_name[0]==0x05)
  1486. dos_name[0]=0xe5;
  1487. filep = find_dir_entry(dosp, dosp->current_dir, dos_name);
  1488. if (filep)
  1489. {
  1490. printf("File already exists: %s\n", name);
  1491. printf(" Not overwritten.\n");
  1492. free(filep);
  1493. return -1;
  1494. }
  1495. buffer = (char *) malloc(sizeof(char)*BYTES_PER_CLUSTER);
  1496. filep = (MSDOSDirEntry *) malloc(sizeof(MSDOSDirEntry));
  1497. if ((buffer == 0) || (filep ==0))
  1498. {
  1499. fprintf(stderr, "Out of memory\n");
  1500. close(fd);
  1501. return -1;
  1502. }
  1503. memset(buffer, '\0', sizeof(char)*BYTES_PER_CLUSTER);
  1504. memset(filep, '\0', sizeof(MSDOSDirEntry));
  1505. strcpy(filep->filename, filename);
  1506. strcpy(filep->extension, extension);
  1507. filep->parent = dosp->current_dir;
  1508. strcpy(filep->tname, dos_name);
  1509. strcpy(filep->path, filep->parent->path);
  1510. if (filep->parent != dosp->root_dir)
  1511. strcat(filep->path, "\\");
  1512. strcat(filep->path, filep->tname);
  1513. DE_NOW(filep);
  1514. filep->filesize = fstats.st_size;
  1515. filep->parent = dosp->current_dir;
  1516. filep->first_cluster = insert_file_fat(dosp, dosp->current_dir->first_cluster, 0xfff);
  1517. cluster = filep->first_cluster;
  1518. if ((cluster == 0x000) || (cluster == 0xff7) || ((0xff0 <= cluster) && (cluster <= 0xff6))
  1519. || (cluster == -1) || (cluster > 0xfff) || ((0xff8 <= cluster) && (cluster <= 0xfff)))
  1520. {
  1521. perror("File allocation error.\n");
  1522. close(fd);
  1523. free(buffer);
  1524. free(filep);
  1525. return -1;
  1526. }
  1527. max_write = filep->filesize;
  1528. clusters_write = max_write/BYTES_PER_CLUSTER + ((max_write%BYTES_PER_CLUSTER)!=0);
  1529. for(i=1;i<=clusters_write;i++)
  1530. {
  1531. memset(buffer, '\0', sizeof(char)*BYTES_PER_CLUSTER);
  1532. /* If last cluster, and not full, just read extra, rather than whole cluster */
  1533. if ((i==clusters_write) && ((filep->filesize % BYTES_PER_CLUSTER)!=0))
  1534. read(fd, buffer, filep->filesize % BYTES_PER_CLUSTER);
  1535. else
  1536. read(fd, buffer, BYTES_PER_CLUSTER);
  1537. ret = msdos_cluster_write(dosp, cluster, buffer);
  1538. if (ret == -1)
  1539. {
  1540. perror("12File write error.\n");
  1541. close(fd);
  1542. free(buffer);
  1543. free(filep);
  1544. return -1;
  1545. }
  1546. if (i != clusters_write)
  1547. cluster = insert_file_fat(dosp, cluster, cluster);
  1548. if ((cluster == 0x000) || (cluster == 0xff7) || ((0xff0 <= cluster) && (cluster <= 0xff6))
  1549. || (cluster == -1) || (cluster > 0xfff) || ((0xff8 <= cluster) && (cluster <= 0xfff)))
  1550. {
  1551. perror("File allocation error.\n");
  1552. close(fd);
  1553. free(buffer);
  1554. free(filep);
  1555. return -1;
  1556. }
  1557. }
  1558. if (add_dir_entry(dosp, fil