dfs_iso9660.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-25 GuEe-GUI the first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <rtservice.h>
  13. #define DBG_TAG "dfs.iso9660"
  14. #define DBG_LVL DBG_INFO
  15. #include <rtdbg.h>
  16. #include "dfs_iso9660.h"
  17. #include <dfs.h>
  18. #include <dfs_fs.h>
  19. #include <dfs_file.h>
  20. #include <posix/string.h>
  21. #include <drivers/misc.h>
  22. #include <drivers/byteorder.h>
  23. #include <sys/time.h>
  24. #define ISO9660_FSTYPE_DIR 0040000
  25. #define ISO9660_FSTYPE_REG 0100000
  26. #define ISO9660_FSTYPE_SYMLINK 0120000
  27. #define ISO9660_FSTYPE_MASK 0170000
  28. #define ISO9660_BLKSZ 2048
  29. #define ISO9660_VOLDESC_BOOT 0
  30. #define ISO9660_VOLDESC_PRIMARY 1
  31. #define ISO9660_VOLDESC_SUPP 2
  32. #define ISO9660_VOLDESC_PART 3
  33. #define ISO9660_VOLDESC_END 255
  34. rt_packed(struct iso9660_voldesc
  35. {
  36. rt_uint8_t type;
  37. rt_uint8_t magic[5];
  38. rt_uint8_t version;
  39. });
  40. rt_packed(struct iso9660_date2
  41. {
  42. rt_uint8_t year;
  43. rt_uint8_t month;
  44. rt_uint8_t day;
  45. rt_uint8_t hour;
  46. rt_uint8_t minute;
  47. rt_uint8_t second;
  48. rt_uint8_t offset;
  49. });
  50. /* Directory entry */
  51. rt_packed(struct iso9660_dir
  52. {
  53. rt_uint8_t len;
  54. rt_uint8_t ext_sectors;
  55. rt_le32_t first_sector;
  56. rt_le32_t first_sector_be;
  57. rt_le32_t size;
  58. rt_le32_t size_be;
  59. struct iso9660_date2 mtime;
  60. #define FLAG_TYPE_PLAIN 0
  61. #define FLAG_TYPE_DIR 2
  62. #define FLAG_TYPE 3
  63. #define FLAG_MORE_EXTENTS 0x80
  64. rt_uint8_t flags;
  65. rt_uint8_t file_unit_size;
  66. rt_uint8_t interleave_gap_size;
  67. rt_le16_t vol_seq_num;
  68. rt_le16_t vol_seq_num_be;
  69. #define MAX_NAMELEN 255
  70. rt_uint8_t namelen;
  71. char name[0];
  72. });
  73. rt_packed(struct iso9660_date
  74. {
  75. rt_uint8_t year[4];
  76. rt_uint8_t month[2];
  77. rt_uint8_t day[2];
  78. rt_uint8_t hour[2];
  79. rt_uint8_t minute[2];
  80. rt_uint8_t second[2];
  81. rt_uint8_t hundredth[2];
  82. rt_uint8_t offset;
  83. });
  84. /* Common volume descriptor */
  85. rt_packed(struct iso9660_common_voldesc
  86. {
  87. struct iso9660_voldesc voldesc;
  88. rt_uint8_t sysname[33];
  89. rt_uint8_t volname[32];
  90. rt_uint8_t unused2[8];
  91. rt_le32_t vol_space_size_le;
  92. rt_le32_t vol_space_size_be;
  93. rt_uint8_t escape[32];
  94. rt_le16_t vol_set_size_le;
  95. rt_le16_t vol_set_size_be;
  96. rt_le16_t vol_seq_num_le;
  97. rt_le16_t vol_seq_num_be;
  98. rt_le16_t logical_block_size_le;
  99. rt_le16_t logical_block_size_be;
  100. rt_le32_t path_table_size;
  101. rt_le32_t path_table_size_be;
  102. rt_le32_t path_table;
  103. rt_le32_t path_table_be;
  104. rt_uint8_t unused3[8];
  105. struct iso9660_dir rootdir;
  106. rt_uint8_t unused4[624];
  107. struct iso9660_date created;
  108. struct iso9660_date modified;
  109. rt_uint8_t unused5[0 /* 1201 */];
  110. });
  111. struct iso9660
  112. {
  113. struct rt_device *dev;
  114. rt_uint8_t joliet;
  115. rt_uint8_t swap[ISO9660_BLKSZ];
  116. struct iso9660_common_voldesc primary, supp;
  117. };
  118. struct iso9660_fd
  119. {
  120. struct iso9660 *iso;
  121. struct iso9660_dir dirent;
  122. };
  123. struct iso9660_iterate
  124. {
  125. struct iso9660_fd *fd;
  126. int i, index, count;
  127. struct dirent *dirp;
  128. };
  129. static void iso9660_convert_string(char *dest, rt_uint16_t *src, int len)
  130. {
  131. /* UTF16 to ASCII */
  132. len >>= 1;
  133. for (int i = 0; i < len; ++i)
  134. {
  135. rt_uint16_t utf16 = rt_be16_to_cpu(*src++);
  136. if (utf16 < 0x80)
  137. {
  138. *dest++ = (rt_uint8_t)utf16;
  139. }
  140. else
  141. {
  142. *dest++ = '?';
  143. }
  144. }
  145. *dest = '\0';
  146. }
  147. static void iso9660_convert_lower(char *dest, rt_uint8_t *src, int len)
  148. {
  149. for (int i = 0; i < len; ++i, ++src)
  150. {
  151. if (*src >= 'A' && *src <= 'Z')
  152. {
  153. *dest++ = *src - ('A' - 'a');
  154. }
  155. else
  156. {
  157. *dest++ = *src;
  158. }
  159. }
  160. *dest = '\0';
  161. }
  162. static time_t iso9660_convert_unixtime(struct iso9660_date *date)
  163. {
  164. struct tm tm;
  165. tm.tm_sec = (date->second[0] - '0') * 10 + (date->second[1] - '0');
  166. tm.tm_min = (date->minute[0] - '0') * 10 + (date->minute[1] - '0');
  167. tm.tm_hour = (date->hour[0] - '0') * 10 + (date->hour[1] - '0');
  168. tm.tm_mday = (date->day[0] - '0') * 10 + (date->day[1] - '0');
  169. tm.tm_mon = (date->month[0] - '0') * 10 + (date->month[1] - '0');
  170. tm.tm_year = (date->year[0] - '0') * 1000 + (date->year[1] - '0') * 100 +
  171. (date->year[2] - '0') * 10 + (date->year[3] - '0');
  172. tm.tm_wday = 0;
  173. return mktime(&tm);
  174. }
  175. static time_t iso9660_convert_unixtime2(struct iso9660_date2 *date)
  176. {
  177. struct tm tm;
  178. tm.tm_sec = date->second;
  179. tm.tm_min = date->minute;
  180. tm.tm_hour = date->hour;
  181. tm.tm_mday = date->day;
  182. tm.tm_mon = date->month;
  183. tm.tm_year = date->year + 1900;
  184. tm.tm_wday = 0;
  185. return mktime(&tm);
  186. }
  187. static struct iso9660_fd *iso9660_lookup(struct iso9660 *iso, const char *path,
  188. struct iso9660_iterate *it)
  189. {
  190. rt_uint32_t lba;
  191. rt_size_t sz, len, namelen;
  192. char sname[MAX_NAMELEN];
  193. struct iso9660_fd *fd;
  194. struct iso9660_dir *dirent;
  195. if (it)
  196. {
  197. fd = it->fd;
  198. iso = fd->iso;
  199. dirent = &fd->dirent;
  200. /* No next entry, always goon */
  201. len = 1;
  202. }
  203. else
  204. {
  205. if (!(fd = rt_malloc(sizeof(*fd))))
  206. {
  207. return fd;
  208. }
  209. fd->iso = iso;
  210. dirent = iso->joliet ? &iso->supp.rootdir : &iso->primary.rootdir;
  211. if (!rt_strcmp(path, "/"))
  212. {
  213. rt_memcpy(&fd->dirent, dirent, sizeof(*dirent));
  214. return fd;
  215. }
  216. /* Skip the first '/' */
  217. ++path;
  218. len = strchrnul(path, '/') - path;
  219. }
  220. lba = rt_le32_to_cpu(dirent->first_sector);
  221. if (rt_device_read(iso->dev, lba, iso->swap, 1) <= 0)
  222. {
  223. goto _fail;
  224. }
  225. dirent = (void *)iso->swap;
  226. sz = 0;
  227. do {
  228. /* Ignore "." and ".." */
  229. do {
  230. rt_uint32_t dlen = rt_le32_to_cpu(dirent->len);
  231. dirent = (void *)dirent + dlen;
  232. sz += dlen;
  233. if (ISO9660_BLKSZ - sz < sizeof(*dirent))
  234. {
  235. /* Sector end, goto the next sector */
  236. if (rt_device_read(iso->dev, ++lba, iso->swap, 1) <= 0)
  237. {
  238. goto _fail;
  239. }
  240. dirent = (void *)iso->swap;
  241. sz = 0;
  242. }
  243. if (rt_le32_to_cpu(dirent->first_sector) == 0)
  244. {
  245. /* Is end, no found. */
  246. goto _fail;
  247. }
  248. } while (dirent->name[0] >> 1 == 0 && rt_le32_to_cpu(dirent->namelen) == 1);
  249. namelen = rt_le32_to_cpu(dirent->namelen);
  250. if (iso->joliet)
  251. {
  252. iso9660_convert_string(sname, (rt_uint16_t *)dirent->name, namelen);
  253. }
  254. else
  255. {
  256. if (!(rt_le32_to_cpu(dirent->flags) & FLAG_TYPE_DIR))
  257. {
  258. /* Remove ";1" */
  259. namelen -= 2;
  260. }
  261. iso9660_convert_lower(sname, (rt_uint8_t *)dirent->name, namelen);
  262. }
  263. if (it)
  264. {
  265. if (it->i < it->index)
  266. {
  267. goto _next;
  268. }
  269. if ((rt_le32_to_cpu(dirent->flags) & FLAG_TYPE) == FLAG_TYPE_DIR)
  270. {
  271. it->dirp->d_type = DT_DIR;
  272. }
  273. else
  274. {
  275. it->dirp->d_type = DT_REG;
  276. }
  277. it->dirp->d_namlen = namelen;
  278. rt_strncpy(it->dirp->d_name, sname, namelen);
  279. it->dirp->d_name[namelen] = '\0';
  280. it->dirp->d_reclen = (rt_uint16_t)sizeof(struct dirent);
  281. ++it->dirp;
  282. _next:
  283. ++it->i;
  284. if (it->i - it->index >= it->count)
  285. {
  286. /* Iterate end */
  287. return RT_NULL;
  288. }
  289. /* No next entry */
  290. continue;
  291. }
  292. if (!rt_strncmp(sname, path, len))
  293. {
  294. /* The end of path, found ok */
  295. if (!path[len])
  296. {
  297. rt_memcpy(&fd->dirent, dirent, sizeof(*dirent));
  298. return fd;
  299. }
  300. /* Next entry */
  301. lba = rt_le32_to_cpu(dirent->first_sector);
  302. if (rt_device_read(iso->dev, lba, iso->swap, 1) <= 0)
  303. {
  304. goto _fail;
  305. }
  306. dirent = (void *)iso->swap;
  307. sz = 0;
  308. path += len + 1;
  309. len = strchrnul(path, '/') - path;
  310. }
  311. } while (len);
  312. _fail:
  313. if (!it)
  314. {
  315. rt_free(fd);
  316. }
  317. return RT_NULL;
  318. }
  319. static int dfs_iso9660_open(struct dfs_file *fd)
  320. {
  321. struct iso9660 *iso = fd->vnode->fs->data;
  322. fd->vnode->data = iso9660_lookup(iso, fd->vnode->path, RT_NULL);
  323. return fd->vnode->data ? 0 : -EINVAL;
  324. }
  325. static int dfs_iso9660_close(struct dfs_file *fd)
  326. {
  327. struct iso9660_fd *iso_fd = fd->vnode->data;
  328. rt_free(iso_fd);
  329. return 0;
  330. }
  331. static ssize_t dfs_iso9660_read(struct dfs_file *fd, void *buf, size_t count)
  332. {
  333. rt_uint32_t pos;
  334. void *buf_ptr;
  335. ssize_t read_blk, toread_blk;
  336. size_t rcount = 0, remain, size;
  337. struct iso9660_fd *iso_fd = fd->vnode->data;
  338. struct iso9660 *iso = iso_fd->iso;
  339. if (fd->pos + count > rt_le32_to_cpu(iso_fd->dirent.size))
  340. {
  341. count = rt_le32_to_cpu(iso_fd->dirent.size) - fd->pos;
  342. }
  343. pos = rt_le32_to_cpu(iso_fd->dirent.first_sector);
  344. /* Align to a sector */
  345. if (fd->pos)
  346. {
  347. pos += fd->pos / ISO9660_BLKSZ;
  348. remain = fd->pos & (ISO9660_BLKSZ - 1);
  349. if (rt_device_read(iso->dev, pos, iso->swap, 1) <= 0)
  350. {
  351. return -EIO;
  352. }
  353. size = rt_min_t(size_t, ISO9660_BLKSZ - remain, count);
  354. rt_memcpy(buf, &iso->swap[remain], size);
  355. rcount += size;
  356. count -= size;
  357. buf += size;
  358. pos += 1;
  359. fd->pos += size;
  360. if (!count)
  361. {
  362. goto _end;
  363. }
  364. }
  365. remain = count & (ISO9660_BLKSZ - 1);
  366. count = rt_max_t(size_t, count / ISO9660_BLKSZ, 1);
  367. while ((ssize_t)count > 0)
  368. {
  369. if (count == 1)
  370. {
  371. buf_ptr = iso->swap;
  372. toread_blk = 1;
  373. }
  374. else
  375. {
  376. buf_ptr = buf;
  377. toread_blk = count;
  378. }
  379. read_blk = rt_device_read(iso->dev, pos, buf_ptr, toread_blk);
  380. if (read_blk <= 0)
  381. {
  382. return (int)read_blk;
  383. }
  384. if (count == 1)
  385. {
  386. size = remain;
  387. rt_memcpy(buf, iso->swap, size);
  388. }
  389. else
  390. {
  391. size = read_blk * ISO9660_BLKSZ;
  392. }
  393. rcount += size;
  394. count -= read_blk;
  395. buf += size;
  396. pos += read_blk;
  397. fd->pos += size;
  398. }
  399. _end:
  400. return rcount;
  401. }
  402. static off_t dfs_iso9660_lseek(struct dfs_file *fd, off_t offset)
  403. {
  404. int ret = -EIO;
  405. if (offset <= fd->vnode->size)
  406. {
  407. fd->pos = offset;
  408. ret = fd->pos;
  409. }
  410. return ret;
  411. }
  412. static int dfs_iso9660_getdents(struct dfs_file *fd, struct dirent *dirp, uint32_t count)
  413. {
  414. struct iso9660_iterate it;
  415. struct iso9660_fd *iso_fd = fd->vnode->data;
  416. count = (count / sizeof(struct dirent));
  417. if (!count)
  418. {
  419. return -EINVAL;
  420. }
  421. it.fd = iso_fd;
  422. it.i = 0;
  423. it.index = fd->pos;
  424. it.count = count;
  425. it.dirp = dirp;
  426. iso9660_lookup(RT_NULL, RT_NULL, &it);
  427. count = it.i - it.index;
  428. if (count > 0)
  429. {
  430. fd->pos += count;
  431. }
  432. count *= sizeof(struct dirent);
  433. return count;
  434. }
  435. static const struct dfs_file_ops _iso9660_fops =
  436. {
  437. .open = dfs_iso9660_open,
  438. .close = dfs_iso9660_close,
  439. .read = dfs_iso9660_read,
  440. .lseek = dfs_iso9660_lseek,
  441. .getdents = dfs_iso9660_getdents,
  442. };
  443. static int dfs_iso9660_mount(struct dfs_filesystem *fs,
  444. unsigned long rwflag, const void *data)
  445. {
  446. int err;
  447. struct iso9660 *iso;
  448. struct iso9660_voldesc *voldesc;
  449. struct rt_device_blk_geometry geometry;
  450. if (!(iso = rt_malloc(sizeof(*iso))))
  451. {
  452. return -RT_ENOMEM;
  453. }
  454. iso->dev = fs->dev_id;
  455. rt_device_control(iso->dev, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
  456. if (geometry.bytes_per_sector != ISO9660_BLKSZ)
  457. {
  458. LOG_E("%s: Logical block size = %d is not supported",
  459. iso->dev->parent.name, geometry.bytes_per_sector);
  460. err = -EINVAL;
  461. goto _fail;
  462. }
  463. iso->primary.rootdir.first_sector = 0;
  464. iso->supp.rootdir.first_sector = 0;
  465. /* LBA 0-15 is the bootloader's information */
  466. for (int lba = 16; ; ++lba)
  467. {
  468. if (rt_device_read(iso->dev, lba, &iso->swap, 1) <= 0)
  469. {
  470. err = -EIO;
  471. goto _fail;
  472. }
  473. voldesc = (void *)iso->swap;
  474. if (rt_strncmp((char *)voldesc->magic, "CD001", 5))
  475. {
  476. LOG_E("%s: Invalid magic \"%s\"", voldesc->magic);
  477. err = -EINVAL;
  478. goto _fail;
  479. }
  480. if (voldesc->type == ISO9660_VOLDESC_BOOT)
  481. {
  482. LOG_D("System Name: %s", ((struct iso9660_common_voldesc *)voldesc)->sysname);
  483. LOG_D("Volume Name: %s", ((struct iso9660_common_voldesc *)voldesc)->volname);
  484. }
  485. else if (voldesc->type == ISO9660_VOLDESC_PRIMARY)
  486. {
  487. iso->joliet = 0;
  488. rt_memcpy(&iso->primary, &iso->swap, sizeof(iso->primary));
  489. }
  490. else if (voldesc->type == ISO9660_VOLDESC_SUPP)
  491. {
  492. rt_memcpy(&iso->supp, &iso->swap, sizeof(iso->supp));
  493. if (iso->supp.escape[0] == 0x25 && iso->supp.escape[1] == 0x2f)
  494. {
  495. if (iso->supp.escape[2] == 0x40)
  496. {
  497. iso->joliet = 1;
  498. }
  499. else if (iso->supp.escape[2] == 0x43)
  500. {
  501. iso->joliet = 2;
  502. }
  503. else if (iso->supp.escape[2] == 0x45)
  504. {
  505. iso->joliet = 3;
  506. }
  507. else
  508. {
  509. continue;
  510. }
  511. }
  512. }
  513. else if (voldesc->type == ISO9660_VOLDESC_PART)
  514. {
  515. LOG_D("System Name: %s", ((struct iso9660_common_voldesc *)voldesc)->sysname);
  516. LOG_D("Volume Name: %s", ((struct iso9660_common_voldesc *)voldesc)->volname);
  517. }
  518. else if (voldesc->type == ISO9660_VOLDESC_END)
  519. {
  520. break;
  521. }
  522. }
  523. if (!iso->primary.rootdir.first_sector || !iso->supp.rootdir.first_sector)
  524. {
  525. LOG_E("No primary or secondary partition found");
  526. err = -EINVAL;
  527. goto _fail;
  528. }
  529. fs->data = iso;
  530. return 0;
  531. _fail:
  532. rt_free(iso);
  533. return err;
  534. }
  535. static int dfs_iso9660_unmount(struct dfs_filesystem *fs)
  536. {
  537. struct iso9660 *iso = fs->data;
  538. rt_free(iso);
  539. return 0;
  540. }
  541. static int dfs_iso9660_stat(struct dfs_filesystem *fs,
  542. const char *filename, struct stat *st)
  543. {
  544. struct iso9660 *iso = fs->data;
  545. struct iso9660_fd *fd = iso9660_lookup(iso, filename, RT_NULL);
  546. if (!fd)
  547. {
  548. return -EINVAL;
  549. }
  550. st->st_dev = 0;
  551. st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
  552. S_IWUSR | S_IWGRP | S_IWOTH;
  553. if ((fd->dirent.flags & FLAG_TYPE) == FLAG_TYPE_DIR)
  554. {
  555. st->st_mode &= ~S_IFREG;
  556. st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
  557. }
  558. st->st_atime = iso9660_convert_unixtime(iso->joliet ?
  559. &iso->supp.created : &iso->primary.created);
  560. st->st_mtime = iso9660_convert_unixtime2(&fd->dirent.mtime);
  561. st->st_size = rt_le32_to_cpu(fd->dirent.size);
  562. rt_free(fd);
  563. return 0;
  564. }
  565. static const struct dfs_filesystem_ops _iso9660 =
  566. {
  567. .name = "iso9660",
  568. .flags = DFS_FS_FLAG_DEFAULT,
  569. .fops = &_iso9660_fops,
  570. .mount = dfs_iso9660_mount,
  571. .unmount = dfs_iso9660_unmount,
  572. .stat = dfs_iso9660_stat,
  573. };
  574. int dfs_iso9660_init(void)
  575. {
  576. /* register iso9660 file system */
  577. return dfs_register(&_iso9660);
  578. }
  579. INIT_COMPONENT_EXPORT(dfs_iso9660_init);