iso9660.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. /* iso9660.c - iso9660 implementation with extensions:
  2. SUSP, Rock Ridge. */
  3. /*
  4. * GRUB -- GRand Unified Bootloader
  5. * Copyright (C) 2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
  6. *
  7. * GRUB is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * GRUB is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <grub/err.h>
  21. #include <grub/file.h>
  22. #include <grub/mm.h>
  23. #include <grub/misc.h>
  24. #include <grub/disk.h>
  25. #include <grub/dl.h>
  26. #include <grub/types.h>
  27. #include <grub/fshelp.h>
  28. #include <grub/charset.h>
  29. #include <grub/datetime.h>
  30. #include <grub/safemath.h>
  31. GRUB_MOD_LICENSE ("GPLv3+");
  32. #define GRUB_ISO9660_FSTYPE_DIR 0040000
  33. #define GRUB_ISO9660_FSTYPE_REG 0100000
  34. #define GRUB_ISO9660_FSTYPE_SYMLINK 0120000
  35. #define GRUB_ISO9660_FSTYPE_MASK 0170000
  36. #define GRUB_ISO9660_LOG2_BLKSZ 2
  37. #define GRUB_ISO9660_BLKSZ 2048
  38. #define GRUB_ISO9660_RR_DOT 2
  39. #define GRUB_ISO9660_RR_DOTDOT 4
  40. #define GRUB_ISO9660_VOLDESC_BOOT 0
  41. #define GRUB_ISO9660_VOLDESC_PRIMARY 1
  42. #define GRUB_ISO9660_VOLDESC_SUPP 2
  43. #define GRUB_ISO9660_VOLDESC_PART 3
  44. #define GRUB_ISO9660_VOLDESC_END 255
  45. #define GRUB_ISO9660_SUSP_HEADER_SZ 4
  46. #define GRUB_ISO9660_MAX_CE_HOPS 100000
  47. /* The head of a volume descriptor. */
  48. struct grub_iso9660_voldesc
  49. {
  50. grub_uint8_t type;
  51. grub_uint8_t magic[5];
  52. grub_uint8_t version;
  53. } GRUB_PACKED;
  54. struct grub_iso9660_date2
  55. {
  56. grub_uint8_t year;
  57. grub_uint8_t month;
  58. grub_uint8_t day;
  59. grub_uint8_t hour;
  60. grub_uint8_t minute;
  61. grub_uint8_t second;
  62. grub_uint8_t offset;
  63. } GRUB_PACKED;
  64. /* A directory entry. */
  65. struct grub_iso9660_dir
  66. {
  67. grub_uint8_t len;
  68. grub_uint8_t ext_sectors;
  69. grub_uint32_t first_sector;
  70. grub_uint32_t first_sector_be;
  71. grub_uint32_t size;
  72. grub_uint32_t size_be;
  73. struct grub_iso9660_date2 mtime;
  74. grub_uint8_t flags;
  75. grub_uint8_t unused2[6];
  76. #define MAX_NAMELEN 255
  77. grub_uint8_t namelen;
  78. } GRUB_PACKED;
  79. struct grub_iso9660_date
  80. {
  81. grub_uint8_t year[4];
  82. grub_uint8_t month[2];
  83. grub_uint8_t day[2];
  84. grub_uint8_t hour[2];
  85. grub_uint8_t minute[2];
  86. grub_uint8_t second[2];
  87. grub_uint8_t hundredth[2];
  88. grub_uint8_t offset;
  89. } GRUB_PACKED;
  90. /* The primary volume descriptor. Only little endian is used. */
  91. struct grub_iso9660_primary_voldesc
  92. {
  93. struct grub_iso9660_voldesc voldesc;
  94. grub_uint8_t unused1[33];
  95. grub_uint8_t volname[32];
  96. grub_uint8_t unused2[16];
  97. grub_uint8_t escape[32];
  98. grub_uint8_t unused3[12];
  99. grub_uint32_t path_table_size;
  100. grub_uint8_t unused4[4];
  101. grub_uint32_t path_table;
  102. grub_uint8_t unused5[12];
  103. struct grub_iso9660_dir rootdir;
  104. grub_uint8_t unused6[624];
  105. struct grub_iso9660_date created;
  106. struct grub_iso9660_date modified;
  107. } GRUB_PACKED;
  108. /* A single entry in the path table. */
  109. struct grub_iso9660_path
  110. {
  111. grub_uint8_t len;
  112. grub_uint8_t sectors;
  113. grub_uint32_t first_sector;
  114. grub_uint16_t parentdir;
  115. grub_uint8_t name[0];
  116. } GRUB_PACKED;
  117. /* An entry in the System Usage area of the directory entry. */
  118. struct grub_iso9660_susp_entry
  119. {
  120. grub_uint8_t sig[2];
  121. grub_uint8_t len;
  122. grub_uint8_t version;
  123. grub_uint8_t data[0];
  124. } GRUB_PACKED;
  125. /* The CE entry. This is used to describe the next block where data
  126. can be found. */
  127. struct grub_iso9660_susp_ce
  128. {
  129. struct grub_iso9660_susp_entry entry;
  130. grub_uint32_t blk;
  131. grub_uint32_t blk_be;
  132. grub_uint32_t off;
  133. grub_uint32_t off_be;
  134. grub_uint32_t len;
  135. grub_uint32_t len_be;
  136. } GRUB_PACKED;
  137. struct grub_iso9660_data
  138. {
  139. struct grub_iso9660_primary_voldesc voldesc;
  140. grub_disk_t disk;
  141. int rockridge;
  142. int susp_skip;
  143. int joliet;
  144. struct grub_fshelp_node *node;
  145. };
  146. struct grub_fshelp_node
  147. {
  148. struct grub_iso9660_data *data;
  149. grub_size_t have_dirents, alloc_dirents;
  150. int have_symlink;
  151. struct grub_iso9660_dir dirents[8];
  152. char symlink[0];
  153. };
  154. enum
  155. {
  156. FLAG_TYPE_PLAIN = 0,
  157. FLAG_TYPE_DIR = 2,
  158. FLAG_TYPE = 3,
  159. FLAG_MORE_EXTENTS = 0x80
  160. };
  161. static grub_dl_t my_mod;
  162. static grub_err_t
  163. iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int64_t *nix)
  164. {
  165. struct grub_datetime datetime;
  166. if (! i->year[0] && ! i->year[1]
  167. && ! i->year[2] && ! i->year[3]
  168. && ! i->month[0] && ! i->month[1]
  169. && ! i->day[0] && ! i->day[1]
  170. && ! i->hour[0] && ! i->hour[1]
  171. && ! i->minute[0] && ! i->minute[1]
  172. && ! i->second[0] && ! i->second[1]
  173. && ! i->hundredth[0] && ! i->hundredth[1])
  174. return grub_error (GRUB_ERR_BAD_NUMBER, "empty date");
  175. datetime.year = (i->year[0] - '0') * 1000 + (i->year[1] - '0') * 100
  176. + (i->year[2] - '0') * 10 + (i->year[3] - '0');
  177. datetime.month = (i->month[0] - '0') * 10 + (i->month[1] - '0');
  178. datetime.day = (i->day[0] - '0') * 10 + (i->day[1] - '0');
  179. datetime.hour = (i->hour[0] - '0') * 10 + (i->hour[1] - '0');
  180. datetime.minute = (i->minute[0] - '0') * 10 + (i->minute[1] - '0');
  181. datetime.second = (i->second[0] - '0') * 10 + (i->second[1] - '0');
  182. if (!grub_datetime2unixtime (&datetime, nix))
  183. return grub_error (GRUB_ERR_BAD_NUMBER, "incorrect date");
  184. *nix -= i->offset * 60 * 15;
  185. return GRUB_ERR_NONE;
  186. }
  187. static int
  188. iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int64_t *nix)
  189. {
  190. struct grub_datetime datetime;
  191. datetime.year = i->year + 1900;
  192. datetime.month = i->month;
  193. datetime.day = i->day;
  194. datetime.hour = i->hour;
  195. datetime.minute = i->minute;
  196. datetime.second = i->second;
  197. if (!grub_datetime2unixtime (&datetime, nix))
  198. return 0;
  199. *nix -= i->offset * 60 * 15;
  200. return 1;
  201. }
  202. static grub_err_t
  203. read_node (grub_fshelp_node_t node, grub_off_t off, grub_size_t len, char *buf)
  204. {
  205. grub_size_t i = 0;
  206. while (len > 0)
  207. {
  208. grub_size_t toread;
  209. grub_err_t err;
  210. while (i < node->have_dirents
  211. && off >= grub_le_to_cpu32 (node->dirents[i].size))
  212. {
  213. off -= grub_le_to_cpu32 (node->dirents[i].size);
  214. i++;
  215. }
  216. if (i == node->have_dirents)
  217. return grub_error (GRUB_ERR_OUT_OF_RANGE, "read out of range");
  218. toread = grub_le_to_cpu32 (node->dirents[i].size);
  219. if (toread > len)
  220. toread = len;
  221. err = grub_disk_read (node->data->disk,
  222. ((grub_disk_addr_t) grub_le_to_cpu32 (node->dirents[i].first_sector)) << GRUB_ISO9660_LOG2_BLKSZ,
  223. off, toread, buf);
  224. if (err)
  225. return err;
  226. len -= toread;
  227. off += toread;
  228. buf += toread;
  229. }
  230. return GRUB_ERR_NONE;
  231. }
  232. /* Iterate over the susp entries, starting with block SUA_BLOCK on the
  233. offset SUA_POS with a size of SUA_SIZE bytes. Hook is called for
  234. every entry. */
  235. static grub_err_t
  236. grub_iso9660_susp_iterate (grub_fshelp_node_t node, grub_off_t off,
  237. grub_ssize_t sua_size,
  238. grub_err_t (*hook)
  239. (struct grub_iso9660_susp_entry *entry, void *hook_arg),
  240. void *hook_arg)
  241. {
  242. char *sua;
  243. struct grub_iso9660_susp_entry *entry;
  244. grub_err_t err;
  245. int ce_counter = 0;
  246. grub_ssize_t ce_sua_size = 0;
  247. grub_off_t ce_off;
  248. grub_disk_addr_t ce_block;
  249. if (sua_size <= 0)
  250. return GRUB_ERR_NONE;
  251. if (sua_size < GRUB_ISO9660_SUSP_HEADER_SZ)
  252. return grub_error (GRUB_ERR_BAD_FS, "invalid susp entry size");
  253. sua = grub_malloc (sua_size);
  254. if (!sua)
  255. return grub_errno;
  256. /* Load a part of the System Usage Area. */
  257. err = read_node (node, off, sua_size, sua);
  258. if (err)
  259. {
  260. grub_free (sua);
  261. return err;
  262. }
  263. entry = (struct grub_iso9660_susp_entry *) sua;
  264. next_susp_area:
  265. while (entry->len > 0)
  266. {
  267. /* Ensure the entry is within System Use Area. */
  268. if ((char *) entry + entry->len > (sua + sua_size))
  269. break;
  270. /* The last entry. */
  271. if (grub_strncmp ((char *) entry->sig, "ST", 2) == 0)
  272. break;
  273. /* Additional entries are stored elsewhere. */
  274. if (grub_strncmp ((char *) entry->sig, "CE", 2) == 0)
  275. {
  276. struct grub_iso9660_susp_ce *ce;
  277. if (ce_sua_size > 0)
  278. {
  279. grub_free (sua);
  280. return grub_error (GRUB_ERR_BAD_FS,
  281. "more than one CE entry in SUSP area");
  282. }
  283. /* Buffer CE parameters for use after the end of this loop. */
  284. ce = (struct grub_iso9660_susp_ce *) entry;
  285. ce_sua_size = grub_le_to_cpu32 (ce->len);
  286. ce_off = grub_le_to_cpu32 (ce->off);
  287. ce_block = grub_le_to_cpu32 (ce->blk) << GRUB_ISO9660_LOG2_BLKSZ;
  288. }
  289. else if (hook (entry, hook_arg))
  290. {
  291. grub_free (sua);
  292. return 0;
  293. }
  294. entry = (struct grub_iso9660_susp_entry *) ((char *) entry + entry->len);
  295. if (((sua + sua_size) - (char *) entry) < GRUB_ISO9660_SUSP_HEADER_SZ)
  296. break;
  297. }
  298. if (ce_sua_size > 0)
  299. {
  300. /* Load the next System Use Area by buffered CE entry parameters. */
  301. if (++ce_counter > GRUB_ISO9660_MAX_CE_HOPS)
  302. {
  303. grub_free (sua);
  304. return grub_error (GRUB_ERR_BAD_FS, "suspecting endless CE loop");
  305. }
  306. if (ce_sua_size < GRUB_ISO9660_SUSP_HEADER_SZ)
  307. {
  308. grub_free (sua);
  309. return grub_error (GRUB_ERR_BAD_FS, "invalid continuation area in CE entry");
  310. }
  311. grub_free (sua);
  312. sua = grub_malloc (ce_sua_size);
  313. if (!sua)
  314. return grub_errno;
  315. err = grub_disk_read (node->data->disk, ce_block, ce_off, ce_sua_size, sua);
  316. if (err)
  317. {
  318. grub_free (sua);
  319. return err;
  320. }
  321. entry = (struct grub_iso9660_susp_entry *) sua;
  322. sua_size = ce_sua_size;
  323. ce_sua_size = 0;
  324. goto next_susp_area;
  325. }
  326. grub_free (sua);
  327. return 0;
  328. }
  329. static char *
  330. grub_iso9660_convert_string (grub_uint8_t *us, int len)
  331. {
  332. char *p;
  333. int i;
  334. grub_uint16_t t[MAX_NAMELEN / 2 + 1];
  335. p = grub_calloc (len, GRUB_MAX_UTF8_PER_UTF16 + 1);
  336. if (! p)
  337. return NULL;
  338. for (i=0; i<len; i++)
  339. t[i] = grub_be_to_cpu16 (grub_get_unaligned16 (us + 2 * i));
  340. *grub_utf16_to_utf8 ((grub_uint8_t *) p, t, len) = '\0';
  341. return p;
  342. }
  343. static grub_err_t
  344. susp_iterate_set_rockridge (struct grub_iso9660_susp_entry *susp_entry,
  345. void *_data)
  346. {
  347. struct grub_iso9660_data *data = _data;
  348. /* The "ER" entry is used to detect extensions. The
  349. `IEEE_P1285' extension means Rock ridge. */
  350. if (grub_strncmp ((char *) susp_entry->sig, "ER", 2) == 0)
  351. {
  352. data->rockridge = 1;
  353. return 1;
  354. }
  355. return 0;
  356. }
  357. static grub_err_t
  358. set_rockridge (struct grub_iso9660_data *data)
  359. {
  360. int sua_pos;
  361. int sua_size;
  362. char *sua;
  363. struct grub_iso9660_dir rootdir;
  364. struct grub_iso9660_susp_entry *entry;
  365. data->rockridge = 0;
  366. /* Read the system use area and test it to see if SUSP is
  367. supported. */
  368. if (grub_disk_read (data->disk,
  369. (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
  370. << GRUB_ISO9660_LOG2_BLKSZ), 0,
  371. sizeof (rootdir), (char *) &rootdir))
  372. return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
  373. sua_pos = (sizeof (rootdir) + rootdir.namelen
  374. + (rootdir.namelen % 2) - 1);
  375. sua_size = rootdir.len - sua_pos;
  376. if (!sua_size)
  377. return GRUB_ERR_NONE;
  378. if (sua_size < GRUB_ISO9660_SUSP_HEADER_SZ)
  379. return grub_error (GRUB_ERR_BAD_FS, "invalid rock ridge entry size");
  380. sua = grub_malloc (sua_size);
  381. if (! sua)
  382. return grub_errno;
  383. if (grub_disk_read (data->disk,
  384. (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
  385. << GRUB_ISO9660_LOG2_BLKSZ), sua_pos,
  386. sua_size, sua))
  387. {
  388. grub_free (sua);
  389. return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
  390. }
  391. entry = (struct grub_iso9660_susp_entry *) sua;
  392. /* Test if the SUSP protocol is used on this filesystem. */
  393. if (grub_strncmp ((char *) entry->sig, "SP", 2) == 0)
  394. {
  395. struct grub_fshelp_node rootnode;
  396. rootnode.data = data;
  397. rootnode.alloc_dirents = ARRAY_SIZE (rootnode.dirents);
  398. rootnode.have_dirents = 1;
  399. rootnode.have_symlink = 0;
  400. rootnode.dirents[0] = data->voldesc.rootdir;
  401. /* The size of SP (version 1) is fixed to 7. */
  402. if (sua_size < 7 || entry->len < 7)
  403. {
  404. grub_free (sua);
  405. return grub_error (GRUB_ERR_BAD_FS, "corrupted rock ridge entry");
  406. }
  407. /*
  408. * The 2nd data byte stored how many bytes are skipped every time
  409. * to get to the SUA (System Usage Area).
  410. */
  411. data->susp_skip = entry->data[2];
  412. entry = (struct grub_iso9660_susp_entry *) ((char *) entry + entry->len);
  413. /* Iterate over the entries in the SUA area to detect
  414. extensions. */
  415. if (grub_iso9660_susp_iterate (&rootnode,
  416. sua_pos, sua_size, susp_iterate_set_rockridge,
  417. data))
  418. {
  419. grub_free (sua);
  420. return grub_errno;
  421. }
  422. }
  423. grub_free (sua);
  424. return GRUB_ERR_NONE;
  425. }
  426. static struct grub_iso9660_data *
  427. grub_iso9660_mount (grub_disk_t disk)
  428. {
  429. struct grub_iso9660_data *data = 0;
  430. struct grub_iso9660_primary_voldesc voldesc;
  431. int block;
  432. data = grub_zalloc (sizeof (struct grub_iso9660_data));
  433. if (! data)
  434. return 0;
  435. data->disk = disk;
  436. block = 16;
  437. do
  438. {
  439. int copy_voldesc = 0;
  440. /* Read the superblock. */
  441. if (grub_disk_read (disk, block << GRUB_ISO9660_LOG2_BLKSZ, 0,
  442. sizeof (struct grub_iso9660_primary_voldesc),
  443. (char *) &voldesc))
  444. {
  445. grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
  446. goto fail;
  447. }
  448. if (grub_strncmp ((char *) voldesc.voldesc.magic, "CD001", 5) != 0)
  449. {
  450. grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
  451. goto fail;
  452. }
  453. if (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_PRIMARY)
  454. copy_voldesc = 1;
  455. else if (!data->rockridge
  456. && (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_SUPP)
  457. && (voldesc.escape[0] == 0x25) && (voldesc.escape[1] == 0x2f)
  458. &&
  459. ((voldesc.escape[2] == 0x40) || /* UCS-2 Level 1. */
  460. (voldesc.escape[2] == 0x43) || /* UCS-2 Level 2. */
  461. (voldesc.escape[2] == 0x45))) /* UCS-2 Level 3. */
  462. {
  463. copy_voldesc = 1;
  464. data->joliet = 1;
  465. }
  466. if (copy_voldesc)
  467. {
  468. grub_memcpy((char *) &data->voldesc, (char *) &voldesc,
  469. sizeof (struct grub_iso9660_primary_voldesc));
  470. if (set_rockridge (data))
  471. goto fail;
  472. }
  473. block++;
  474. } while (voldesc.voldesc.type != GRUB_ISO9660_VOLDESC_END);
  475. return data;
  476. fail:
  477. grub_free (data);
  478. return 0;
  479. }
  480. static char *
  481. grub_iso9660_read_symlink (grub_fshelp_node_t node)
  482. {
  483. return node->have_symlink
  484. ? grub_strdup (node->symlink
  485. + (node->have_dirents) * sizeof (node->dirents[0])
  486. - sizeof (node->dirents)) : grub_strdup ("");
  487. }
  488. static grub_off_t
  489. get_node_size (grub_fshelp_node_t node)
  490. {
  491. grub_off_t ret = 0;
  492. grub_size_t i;
  493. for (i = 0; i < node->have_dirents; i++)
  494. ret += grub_le_to_cpu32 (node->dirents[i].size);
  495. return ret;
  496. }
  497. struct iterate_dir_ctx
  498. {
  499. char *filename;
  500. int filename_alloc;
  501. enum grub_fshelp_filetype type;
  502. char *symlink;
  503. int was_continue;
  504. };
  505. /* Extend the symlink. */
  506. static void
  507. add_part (struct iterate_dir_ctx *ctx,
  508. const char *part,
  509. int len2)
  510. {
  511. int size = ctx->symlink ? grub_strlen (ctx->symlink) : 0;
  512. grub_size_t sz;
  513. char *new;
  514. if (grub_add (size, len2, &sz) ||
  515. grub_add (sz, 1, &sz))
  516. return;
  517. new = grub_realloc (ctx->symlink, sz);
  518. if (!new)
  519. {
  520. grub_free (ctx->symlink);
  521. ctx->symlink = NULL;
  522. return;
  523. }
  524. ctx->symlink = new;
  525. grub_memcpy (ctx->symlink + size, part, len2);
  526. ctx->symlink[size + len2] = 0;
  527. }
  528. static grub_err_t
  529. susp_iterate_dir (struct grub_iso9660_susp_entry *entry,
  530. void *_ctx)
  531. {
  532. struct iterate_dir_ctx *ctx = _ctx;
  533. /* The filename in the rock ridge entry. */
  534. if (grub_strncmp ("NM", (char *) entry->sig, 2) == 0)
  535. {
  536. /* The flags are stored at the data position 0, here the
  537. filename type is stored. */
  538. /* FIXME: Fix this slightly improper cast. */
  539. if (entry->data[0] & GRUB_ISO9660_RR_DOT)
  540. ctx->filename = (char *) ".";
  541. else if (entry->data[0] & GRUB_ISO9660_RR_DOTDOT)
  542. ctx->filename = (char *) "..";
  543. else if (entry->len >= 5)
  544. {
  545. grub_size_t off = 0, csize = 1;
  546. char *old;
  547. grub_size_t sz;
  548. csize = entry->len - 5;
  549. old = ctx->filename;
  550. if (ctx->filename_alloc)
  551. {
  552. off = grub_strlen (ctx->filename);
  553. if (grub_add (csize, off, &sz) ||
  554. grub_add (sz, 1, &sz))
  555. return GRUB_ERR_OUT_OF_RANGE;
  556. ctx->filename = grub_realloc (ctx->filename, sz);
  557. }
  558. else
  559. {
  560. off = 0;
  561. if (grub_add (csize, 1, &sz))
  562. return GRUB_ERR_OUT_OF_RANGE;
  563. ctx->filename = grub_zalloc (sz);
  564. }
  565. if (!ctx->filename)
  566. {
  567. ctx->filename = old;
  568. return grub_errno;
  569. }
  570. ctx->filename_alloc = 1;
  571. grub_memcpy (ctx->filename + off, (char *) &entry->data[1], csize);
  572. ctx->filename[off + csize] = '\0';
  573. }
  574. }
  575. /* The mode information (st_mode). */
  576. else if (grub_strncmp ((char *) entry->sig, "PX", 2) == 0)
  577. {
  578. /* At position 0 of the PX record the st_mode information is
  579. stored (little-endian). */
  580. grub_uint32_t mode = ((entry->data[0] + (entry->data[1] << 8))
  581. & GRUB_ISO9660_FSTYPE_MASK);
  582. switch (mode)
  583. {
  584. case GRUB_ISO9660_FSTYPE_DIR:
  585. ctx->type = GRUB_FSHELP_DIR;
  586. break;
  587. case GRUB_ISO9660_FSTYPE_REG:
  588. ctx->type = GRUB_FSHELP_REG;
  589. break;
  590. case GRUB_ISO9660_FSTYPE_SYMLINK:
  591. ctx->type = GRUB_FSHELP_SYMLINK;
  592. break;
  593. default:
  594. ctx->type = GRUB_FSHELP_UNKNOWN;
  595. }
  596. }
  597. else if (grub_strncmp ("SL", (char *) entry->sig, 2) == 0)
  598. {
  599. unsigned int pos = 1;
  600. unsigned int csize;
  601. /* The symlink is not stored as a POSIX symlink, translate it. */
  602. while ((pos + GRUB_ISO9660_SUSP_HEADER_SZ + 1) < entry->len)
  603. {
  604. /*
  605. * entry->len is GRUB_ISO9660_SUSP_HEADER_SZ + 1 (the FLAGS) +
  606. * length of the "Component Area". The length of a component
  607. * record is 2 (pos and pos + 1) plus the "Component Content",
  608. * of which starts at pos + 2. entry->data[pos] is the
  609. * "Component Flags"; entry->data[pos + 1] is the length
  610. * of the component.
  611. */
  612. csize = entry->data[pos + 1] + 2;
  613. if (GRUB_ISO9660_SUSP_HEADER_SZ + 1 + csize > entry->len)
  614. break;
  615. /* The current position is the `Component Flag'. */
  616. switch (entry->data[pos] & 30)
  617. {
  618. case 0:
  619. {
  620. /* The data on pos + 2 is the actual data, pos + 1
  621. is the length. Both are part of the `Component
  622. Record'. */
  623. if (ctx->symlink && !ctx->was_continue)
  624. {
  625. add_part (ctx, "/", 1);
  626. if (grub_errno)
  627. return grub_errno;
  628. }
  629. add_part (ctx, (char *) &entry->data[pos + 2],
  630. entry->data[pos + 1]);
  631. ctx->was_continue = (entry->data[pos] & 1);
  632. break;
  633. }
  634. case 2:
  635. add_part (ctx, "./", 2);
  636. break;
  637. case 4:
  638. add_part (ctx, "../", 3);
  639. break;
  640. case 8:
  641. add_part (ctx, "/", 1);
  642. break;
  643. }
  644. /* Check if grub_realloc() failed in add_part(). */
  645. if (grub_errno)
  646. return grub_errno;
  647. /* In pos + 1 the length of the `Component Record' is
  648. stored. */
  649. pos += entry->data[pos + 1] + 2;
  650. }
  651. /* Check if `grub_realloc' failed. */
  652. if (grub_errno)
  653. return grub_errno;
  654. }
  655. return 0;
  656. }
  657. static int
  658. grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
  659. grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
  660. {
  661. struct grub_iso9660_dir dirent;
  662. grub_off_t offset = 0;
  663. grub_off_t len;
  664. struct iterate_dir_ctx ctx;
  665. len = get_node_size (dir);
  666. for (; offset < len; offset += dirent.len)
  667. {
  668. ctx.symlink = 0;
  669. ctx.was_continue = 0;
  670. if (read_node (dir, offset, sizeof (dirent), (char *) &dirent))
  671. return 0;
  672. /* The end of the block, skip to the next one. */
  673. if (!dirent.len)
  674. {
  675. offset = (offset / GRUB_ISO9660_BLKSZ + 1) * GRUB_ISO9660_BLKSZ;
  676. continue;
  677. }
  678. {
  679. char name[MAX_NAMELEN + 1];
  680. int nameoffset = offset + sizeof (dirent);
  681. struct grub_fshelp_node *node;
  682. int sua_off = (sizeof (dirent) + dirent.namelen + 1
  683. - (dirent.namelen % 2));
  684. int sua_size = dirent.len - sua_off;
  685. sua_off += offset + dir->data->susp_skip;
  686. ctx.filename = 0;
  687. ctx.filename_alloc = 0;
  688. ctx.type = GRUB_FSHELP_UNKNOWN;
  689. if (dir->data->rockridge
  690. && grub_iso9660_susp_iterate (dir, sua_off, sua_size,
  691. susp_iterate_dir, &ctx))
  692. return 0;
  693. /* Read the name. */
  694. if (read_node (dir, nameoffset, dirent.namelen, (char *) name))
  695. return 0;
  696. node = grub_malloc (sizeof (struct grub_fshelp_node));
  697. if (!node)
  698. return 0;
  699. node->alloc_dirents = ARRAY_SIZE (node->dirents);
  700. node->have_dirents = 1;
  701. /* Setup a new node. */
  702. node->data = dir->data;
  703. node->have_symlink = 0;
  704. /* If the filetype was not stored using rockridge, use
  705. whatever is stored in the iso9660 filesystem. */
  706. if (ctx.type == GRUB_FSHELP_UNKNOWN)
  707. {
  708. if ((dirent.flags & FLAG_TYPE) == FLAG_TYPE_DIR)
  709. ctx.type = GRUB_FSHELP_DIR;
  710. else
  711. ctx.type = GRUB_FSHELP_REG;
  712. }
  713. /* . and .. */
  714. if (!ctx.filename && dirent.namelen == 1 && name[0] == 0)
  715. ctx.filename = (char *) ".";
  716. if (!ctx.filename && dirent.namelen == 1 && name[0] == 1)
  717. ctx.filename = (char *) "..";
  718. /* The filename was not stored in a rock ridge entry. Read it
  719. from the iso9660 filesystem. */
  720. if (!dir->data->joliet && !ctx.filename)
  721. {
  722. char *ptr;
  723. name[dirent.namelen] = '\0';
  724. ctx.filename = grub_strrchr (name, ';');
  725. if (ctx.filename)
  726. *ctx.filename = '\0';
  727. /* ISO9660 names are not case-preserving. */
  728. ctx.type |= GRUB_FSHELP_CASE_INSENSITIVE;
  729. for (ptr = name; *ptr; ptr++)
  730. *ptr = grub_tolower (*ptr);
  731. if (ptr != name && *(ptr - 1) == '.')
  732. *(ptr - 1) = 0;
  733. ctx.filename = name;
  734. }
  735. if (dir->data->joliet && !ctx.filename)
  736. {
  737. char *semicolon;
  738. ctx.filename = grub_iso9660_convert_string
  739. ((grub_uint8_t *) name, dirent.namelen >> 1);
  740. semicolon = grub_strrchr (ctx.filename, ';');
  741. if (semicolon)
  742. *semicolon = '\0';
  743. ctx.filename_alloc = 1;
  744. }
  745. node->dirents[0] = dirent;
  746. while (dirent.flags & FLAG_MORE_EXTENTS)
  747. {
  748. offset += dirent.len;
  749. /* offset should within the dir's len. */
  750. if (offset > len)
  751. {
  752. if (ctx.filename_alloc)
  753. grub_free (ctx.filename);
  754. grub_free (node);
  755. return 0;
  756. }
  757. if (read_node (dir, offset, sizeof (dirent), (char *) &dirent))
  758. {
  759. if (ctx.filename_alloc)
  760. grub_free (ctx.filename);
  761. grub_free (node);
  762. return 0;
  763. }
  764. /*
  765. * It is either the end of block or zero-padded sector,
  766. * skip to the next block.
  767. */
  768. if (!dirent.len)
  769. {
  770. offset = (offset / GRUB_ISO9660_BLKSZ + 1) * GRUB_ISO9660_BLKSZ;
  771. dirent.flags |= FLAG_MORE_EXTENTS;
  772. continue;
  773. }
  774. if (node->have_dirents >= node->alloc_dirents)
  775. {
  776. struct grub_fshelp_node *new_node;
  777. grub_size_t sz;
  778. if (grub_mul (node->alloc_dirents, 2, &node->alloc_dirents) ||
  779. grub_sub (node->alloc_dirents, ARRAY_SIZE (node->dirents), &sz) ||
  780. grub_mul (sz, sizeof (node->dirents[0]), &sz) ||
  781. grub_add (sz, sizeof (struct grub_fshelp_node), &sz))
  782. goto fail_0;
  783. new_node = grub_realloc (node, sz);
  784. if (!new_node)
  785. {
  786. fail_0:
  787. if (ctx.filename_alloc)
  788. grub_free (ctx.filename);
  789. grub_free (node);
  790. return 0;
  791. }
  792. node = new_node;
  793. }
  794. node->dirents[node->have_dirents++] = dirent;
  795. }
  796. if (ctx.symlink)
  797. {
  798. if ((node->alloc_dirents - node->have_dirents)
  799. * sizeof (node->dirents[0]) < grub_strlen (ctx.symlink) + 1)
  800. {
  801. struct grub_fshelp_node *new_node;
  802. grub_size_t sz;
  803. if (grub_sub (node->alloc_dirents, ARRAY_SIZE (node->dirents), &sz) ||
  804. grub_mul (sz, sizeof (node->dirents[0]), &sz) ||
  805. grub_add (sz, sizeof (struct grub_fshelp_node) + 1, &sz) ||
  806. grub_add (sz, grub_strlen (ctx.symlink), &sz))
  807. goto fail_1;
  808. new_node = grub_realloc (node, sz);
  809. if (!new_node)
  810. {
  811. fail_1:
  812. if (ctx.filename_alloc)
  813. grub_free (ctx.filename);
  814. grub_free (node);
  815. return 0;
  816. }
  817. node = new_node;
  818. }
  819. node->have_symlink = 1;
  820. grub_strcpy (node->symlink
  821. + node->have_dirents * sizeof (node->dirents[0])
  822. - sizeof (node->dirents), ctx.symlink);
  823. grub_free (ctx.symlink);
  824. ctx.symlink = 0;
  825. ctx.was_continue = 0;
  826. }
  827. if (hook (ctx.filename, ctx.type, node, hook_data))
  828. {
  829. if (ctx.filename_alloc)
  830. grub_free (ctx.filename);
  831. return 1;
  832. }
  833. if (ctx.filename_alloc)
  834. grub_free (ctx.filename);
  835. }
  836. }
  837. return 0;
  838. }
  839. /* Context for grub_iso9660_dir. */
  840. struct grub_iso9660_dir_ctx
  841. {
  842. grub_fs_dir_hook_t hook;
  843. void *hook_data;
  844. };
  845. /* Helper for grub_iso9660_dir. */
  846. static int
  847. grub_iso9660_dir_iter (const char *filename,
  848. enum grub_fshelp_filetype filetype,
  849. grub_fshelp_node_t node, void *data)
  850. {
  851. struct grub_iso9660_dir_ctx *ctx = data;
  852. struct grub_dirhook_info info;
  853. grub_memset (&info, 0, sizeof (info));
  854. info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
  855. info.mtimeset = !!iso9660_to_unixtime2 (&node->dirents[0].mtime, &info.mtime);
  856. grub_free (node);
  857. return ctx->hook (filename, &info, ctx->hook_data);
  858. }
  859. static grub_err_t
  860. grub_iso9660_dir (grub_device_t device, const char *path,
  861. grub_fs_dir_hook_t hook, void *hook_data)
  862. {
  863. struct grub_iso9660_dir_ctx ctx = { hook, hook_data };
  864. struct grub_iso9660_data *data = 0;
  865. struct grub_fshelp_node rootnode;
  866. struct grub_fshelp_node *foundnode;
  867. grub_dl_ref (my_mod);
  868. data = grub_iso9660_mount (device->disk);
  869. if (! data)
  870. goto fail;
  871. rootnode.data = data;
  872. rootnode.alloc_dirents = 0;
  873. rootnode.have_dirents = 1;
  874. rootnode.have_symlink = 0;
  875. rootnode.dirents[0] = data->voldesc.rootdir;
  876. /* Use the fshelp function to traverse the path. */
  877. if (grub_fshelp_find_file (path, &rootnode,
  878. &foundnode,
  879. grub_iso9660_iterate_dir,
  880. grub_iso9660_read_symlink,
  881. GRUB_FSHELP_DIR))
  882. goto fail;
  883. /* List the files in the directory. */
  884. grub_iso9660_iterate_dir (foundnode, grub_iso9660_dir_iter, &ctx);
  885. if (foundnode != &rootnode)
  886. grub_free (foundnode);
  887. fail:
  888. grub_free (data);
  889. grub_dl_unref (my_mod);
  890. return grub_errno;
  891. }
  892. /* Open a file named NAME and initialize FILE. */
  893. static grub_err_t
  894. grub_iso9660_open (struct grub_file *file, const char *name)
  895. {
  896. struct grub_iso9660_data *data;
  897. struct grub_fshelp_node rootnode;
  898. struct grub_fshelp_node *foundnode;
  899. grub_dl_ref (my_mod);
  900. data = grub_iso9660_mount (file->device->disk);
  901. if (!data)
  902. goto fail;
  903. rootnode.data = data;
  904. rootnode.alloc_dirents = 0;
  905. rootnode.have_dirents = 1;
  906. rootnode.have_symlink = 0;
  907. rootnode.dirents[0] = data->voldesc.rootdir;
  908. /* Use the fshelp function to traverse the path. */
  909. if (grub_fshelp_find_file (name, &rootnode,
  910. &foundnode,
  911. grub_iso9660_iterate_dir,
  912. grub_iso9660_read_symlink,
  913. GRUB_FSHELP_REG))
  914. goto fail;
  915. data->node = foundnode;
  916. file->data = data;
  917. file->size = get_node_size (foundnode);
  918. file->offset = 0;
  919. return 0;
  920. fail:
  921. grub_dl_unref (my_mod);
  922. grub_free (data);
  923. return grub_errno;
  924. }
  925. static grub_ssize_t
  926. grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len)
  927. {
  928. struct grub_iso9660_data *data =
  929. (struct grub_iso9660_data *) file->data;
  930. grub_err_t err;
  931. /* XXX: The file is stored in as a single extent. */
  932. data->disk->read_hook = file->read_hook;
  933. data->disk->read_hook_data = file->read_hook_data;
  934. err = read_node (data->node, file->offset, len, buf);
  935. data->disk->read_hook = NULL;
  936. if (err || grub_errno)
  937. return -1;
  938. return len;
  939. }
  940. static grub_err_t
  941. grub_iso9660_close (grub_file_t file)
  942. {
  943. struct grub_iso9660_data *data =
  944. (struct grub_iso9660_data *) file->data;
  945. grub_free (data->node);
  946. grub_free (data);
  947. grub_dl_unref (my_mod);
  948. return GRUB_ERR_NONE;
  949. }
  950. static grub_err_t
  951. grub_iso9660_label (grub_device_t device, char **label)
  952. {
  953. struct grub_iso9660_data *data;
  954. data = grub_iso9660_mount (device->disk);
  955. if (data)
  956. {
  957. if (data->joliet)
  958. *label = grub_iso9660_convert_string (data->voldesc.volname, 16);
  959. else
  960. *label = grub_strndup ((char *) data->voldesc.volname, 32);
  961. if (*label)
  962. {
  963. char *ptr;
  964. for (ptr = *label; *ptr;ptr++);
  965. ptr--;
  966. while (ptr >= *label && *ptr == ' ')
  967. *ptr-- = 0;
  968. }
  969. grub_free (data);
  970. }
  971. else
  972. *label = 0;
  973. return grub_errno;
  974. }
  975. static grub_err_t
  976. grub_iso9660_uuid (grub_device_t device, char **uuid)
  977. {
  978. struct grub_iso9660_data *data;
  979. grub_disk_t disk = device->disk;
  980. grub_dl_ref (my_mod);
  981. data = grub_iso9660_mount (disk);
  982. if (data)
  983. {
  984. if (! data->voldesc.modified.year[0] && ! data->voldesc.modified.year[1]
  985. && ! data->voldesc.modified.year[2] && ! data->voldesc.modified.year[3]
  986. && ! data->voldesc.modified.month[0] && ! data->voldesc.modified.month[1]
  987. && ! data->voldesc.modified.day[0] && ! data->voldesc.modified.day[1]
  988. && ! data->voldesc.modified.hour[0] && ! data->voldesc.modified.hour[1]
  989. && ! data->voldesc.modified.minute[0] && ! data->voldesc.modified.minute[1]
  990. && ! data->voldesc.modified.second[0] && ! data->voldesc.modified.second[1]
  991. && ! data->voldesc.modified.hundredth[0] && ! data->voldesc.modified.hundredth[1])
  992. {
  993. grub_error (GRUB_ERR_BAD_NUMBER, "no creation date in filesystem to generate UUID");
  994. *uuid = NULL;
  995. }
  996. else
  997. {
  998. *uuid = grub_xasprintf ("%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c",
  999. data->voldesc.modified.year[0],
  1000. data->voldesc.modified.year[1],
  1001. data->voldesc.modified.year[2],
  1002. data->voldesc.modified.year[3],
  1003. data->voldesc.modified.month[0],
  1004. data->voldesc.modified.month[1],
  1005. data->voldesc.modified.day[0],
  1006. data->voldesc.modified.day[1],
  1007. data->voldesc.modified.hour[0],
  1008. data->voldesc.modified.hour[1],
  1009. data->voldesc.modified.minute[0],
  1010. data->voldesc.modified.minute[1],
  1011. data->voldesc.modified.second[0],
  1012. data->voldesc.modified.second[1],
  1013. data->voldesc.modified.hundredth[0],
  1014. data->voldesc.modified.hundredth[1]);
  1015. }
  1016. }
  1017. else
  1018. *uuid = NULL;
  1019. grub_dl_unref (my_mod);
  1020. grub_free (data);
  1021. return grub_errno;
  1022. }
  1023. /* Get writing time of filesystem. */
  1024. static grub_err_t
  1025. grub_iso9660_mtime (grub_device_t device, grub_int64_t *timebuf)
  1026. {
  1027. struct grub_iso9660_data *data;
  1028. grub_disk_t disk = device->disk;
  1029. grub_err_t err;
  1030. grub_dl_ref (my_mod);
  1031. data = grub_iso9660_mount (disk);
  1032. if (!data)
  1033. {
  1034. grub_dl_unref (my_mod);
  1035. return grub_errno;
  1036. }
  1037. err = iso9660_to_unixtime (&data->voldesc.modified, timebuf);
  1038. grub_dl_unref (my_mod);
  1039. grub_free (data);
  1040. return err;
  1041. }
  1042. static struct grub_fs grub_iso9660_fs =
  1043. {
  1044. .name = "iso9660",
  1045. .fs_dir = grub_iso9660_dir,
  1046. .fs_open = grub_iso9660_open,
  1047. .fs_read = grub_iso9660_read,
  1048. .fs_close = grub_iso9660_close,
  1049. .fs_label = grub_iso9660_label,
  1050. .fs_uuid = grub_iso9660_uuid,
  1051. .fs_mtime = grub_iso9660_mtime,
  1052. #ifdef GRUB_UTIL
  1053. .reserved_first_sector = 1,
  1054. .blocklist_install = 1,
  1055. #endif
  1056. .next = 0
  1057. };
  1058. GRUB_MOD_INIT(iso9660)
  1059. {
  1060. grub_fs_register (&grub_iso9660_fs);
  1061. my_mod = mod;
  1062. }
  1063. GRUB_MOD_FINI(iso9660)
  1064. {
  1065. grub_fs_unregister (&grub_iso9660_fs);
  1066. }