hfs.c 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447
  1. /* hfs.c - HFS. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /* HFS is documented at
  20. http://developer.apple.com/documentation/mac/Files/Files-2.html */
  21. #include <grub/err.h>
  22. #include <grub/file.h>
  23. #include <grub/mm.h>
  24. #include <grub/misc.h>
  25. #include <grub/disk.h>
  26. #include <grub/dl.h>
  27. #include <grub/types.h>
  28. #include <grub/hfs.h>
  29. #include <grub/i18n.h>
  30. #include <grub/fshelp.h>
  31. #include <grub/lockdown.h>
  32. GRUB_MOD_LICENSE ("GPLv3+");
  33. #define GRUB_HFS_SBLOCK 2
  34. #define GRUB_HFS_EMBED_HFSPLUS_SIG 0x482B
  35. #define GRUB_HFS_BLKS (data->blksz >> 9)
  36. #define GRUB_HFS_NODE_LEAF 0xFF
  37. /* The two supported filesystems a record can have. */
  38. enum
  39. {
  40. GRUB_HFS_FILETYPE_DIR = 1,
  41. GRUB_HFS_FILETYPE_FILE = 2
  42. };
  43. /* Catalog node ID (CNID). */
  44. enum grub_hfs_cnid_type
  45. {
  46. GRUB_HFS_CNID_ROOT_PARENT = 1,
  47. GRUB_HFS_CNID_ROOT = 2,
  48. GRUB_HFS_CNID_EXT = 3,
  49. GRUB_HFS_CNID_CAT = 4,
  50. GRUB_HFS_CNID_BAD = 5
  51. };
  52. /* A node descriptor. This is the header of every node. */
  53. struct grub_hfs_node
  54. {
  55. grub_uint32_t next;
  56. grub_uint32_t prev;
  57. grub_uint8_t type;
  58. grub_uint8_t level;
  59. grub_uint16_t reccnt;
  60. grub_uint16_t unused;
  61. } GRUB_PACKED;
  62. /* The head of the B*-Tree. */
  63. struct grub_hfs_treeheader
  64. {
  65. grub_uint16_t tree_depth;
  66. /* The number of the first node. */
  67. grub_uint32_t root_node;
  68. grub_uint32_t leaves;
  69. grub_uint32_t first_leaf;
  70. grub_uint32_t last_leaf;
  71. grub_uint16_t node_size;
  72. grub_uint16_t key_size;
  73. grub_uint32_t nodes;
  74. grub_uint32_t free_nodes;
  75. grub_uint8_t unused[76];
  76. } GRUB_PACKED;
  77. /* The state of a mounted HFS filesystem. */
  78. struct grub_hfs_data
  79. {
  80. struct grub_hfs_sblock sblock;
  81. grub_disk_t disk;
  82. grub_hfs_datarecord_t extents;
  83. int fileid;
  84. int size;
  85. int ext_root;
  86. int ext_size;
  87. int cat_root;
  88. int cat_size;
  89. int blksz;
  90. int log2_blksz;
  91. int rootdir;
  92. };
  93. /* The key as used on disk in a catalog tree. This is used to lookup
  94. file/directory nodes by parent directory ID and filename. */
  95. struct grub_hfs_catalog_key
  96. {
  97. grub_uint8_t unused;
  98. grub_uint32_t parent_dir;
  99. /* Filename length. */
  100. grub_uint8_t strlen;
  101. /* Filename. */
  102. grub_uint8_t str[31];
  103. } GRUB_PACKED;
  104. /* The key as used on disk in a extent overflow tree. Using this key
  105. the extents can be looked up using a fileid and logical start block
  106. as index. */
  107. struct grub_hfs_extent_key
  108. {
  109. /* The kind of fork. This is used to store meta information like
  110. icons, attributes, etc. We will only use the datafork, which is
  111. 0. */
  112. grub_uint8_t forktype;
  113. grub_uint32_t fileid;
  114. grub_uint16_t first_block;
  115. } GRUB_PACKED;
  116. /* A directory record. This is used to find out the directory ID. */
  117. struct grub_hfs_dirrec
  118. {
  119. /* For a directory, type == 1. */
  120. grub_uint8_t type;
  121. grub_uint8_t unused[5];
  122. grub_uint32_t dirid;
  123. grub_uint32_t ctime;
  124. grub_uint32_t mtime;
  125. } GRUB_PACKED;
  126. /* Information about a file. */
  127. struct grub_hfs_filerec
  128. {
  129. /* For a file, type == 2. */
  130. grub_uint8_t type;
  131. grub_uint8_t unused[19];
  132. grub_uint32_t fileid;
  133. grub_uint8_t unused2[2];
  134. grub_uint32_t size;
  135. grub_uint8_t unused3[18];
  136. grub_uint32_t mtime;
  137. grub_uint8_t unused4[22];
  138. /* The first 3 extents of the file. The other extents can be found
  139. in the extent overflow file. */
  140. grub_hfs_datarecord_t extents;
  141. } GRUB_PACKED;
  142. /* A record descriptor, both key and data, used to pass to call back
  143. functions. */
  144. struct grub_hfs_record
  145. {
  146. void *key;
  147. grub_size_t keylen;
  148. void *data;
  149. grub_size_t datalen;
  150. };
  151. static grub_dl_t my_mod;
  152. static int grub_hfs_find_node (struct grub_hfs_data *, char *,
  153. grub_uint32_t, int, char *, grub_size_t);
  154. /* Find block BLOCK of the file FILE in the mounted UFS filesystem
  155. DATA. The first 3 extents are described by DAT. If cache is set,
  156. using caching to improve non-random reads. */
  157. static unsigned int
  158. grub_hfs_block (struct grub_hfs_data *data, grub_hfs_datarecord_t dat,
  159. int file, int block, int cache)
  160. {
  161. grub_hfs_datarecord_t dr;
  162. int pos = 0;
  163. struct grub_hfs_extent_key key;
  164. int tree = 0;
  165. static int cache_file = 0;
  166. static int cache_pos = 0;
  167. static grub_hfs_datarecord_t cache_dr;
  168. grub_memcpy (dr, dat, sizeof (dr));
  169. key.forktype = 0;
  170. key.fileid = grub_cpu_to_be32 (file);
  171. if (cache && cache_file == file && block > cache_pos)
  172. {
  173. pos = cache_pos;
  174. key.first_block = grub_cpu_to_be16 (pos);
  175. grub_memcpy (dr, cache_dr, sizeof (cache_dr));
  176. }
  177. for (;;)
  178. {
  179. int i;
  180. /* Try all 3 extents. */
  181. for (i = 0; i < 3; i++)
  182. {
  183. /* Check if the block is stored in this extent. */
  184. if (grub_be_to_cpu16 (dr[i].count) + pos > block)
  185. {
  186. int first = grub_be_to_cpu16 (dr[i].first_block);
  187. /* If the cache is enabled, store the current position
  188. in the tree. */
  189. if (tree && cache)
  190. {
  191. cache_file = file;
  192. cache_pos = pos;
  193. grub_memcpy (cache_dr, dr, sizeof (cache_dr));
  194. }
  195. return (grub_be_to_cpu16 (data->sblock.first_block)
  196. + (first + block - pos) * GRUB_HFS_BLKS);
  197. }
  198. /* Try the next extent. */
  199. pos += grub_be_to_cpu16 (dr[i].count);
  200. }
  201. /* Lookup the block in the extent overflow file. */
  202. key.first_block = grub_cpu_to_be16 (pos);
  203. tree = 1;
  204. grub_hfs_find_node (data, (char *) &key, data->ext_root,
  205. 1, (char *) &dr, sizeof (dr));
  206. if (grub_errno)
  207. return 0;
  208. }
  209. }
  210. /* Read LEN bytes from the file described by DATA starting with byte
  211. POS. Return the amount of read bytes in READ. */
  212. static grub_ssize_t
  213. grub_hfs_read_file (struct grub_hfs_data *data,
  214. grub_disk_read_hook_t read_hook, void *read_hook_data,
  215. grub_uint32_t pos, grub_size_t len, char *buf)
  216. {
  217. grub_off_t i;
  218. grub_off_t blockcnt;
  219. /* Files are at most 2G/4G - 1 bytes on hfs. Avoid 64-bit division.
  220. Moreover len > 0 as checked in upper layer. */
  221. blockcnt = (len + pos - 1) / data->blksz + 1;
  222. for (i = pos / data->blksz; i < blockcnt; i++)
  223. {
  224. grub_disk_addr_t blknr;
  225. grub_off_t blockoff;
  226. grub_off_t blockend = data->blksz;
  227. int skipfirst = 0;
  228. blockoff = pos % data->blksz;
  229. blknr = grub_hfs_block (data, data->extents, data->fileid, i, 1);
  230. if (grub_errno)
  231. return -1;
  232. /* Last block. */
  233. if (i == blockcnt - 1)
  234. {
  235. blockend = (len + pos) % data->blksz;
  236. /* The last portion is exactly EXT2_BLOCK_SIZE (data). */
  237. if (! blockend)
  238. blockend = data->blksz;
  239. }
  240. /* First block. */
  241. if (i == pos / data->blksz)
  242. {
  243. skipfirst = blockoff;
  244. blockend -= skipfirst;
  245. }
  246. /* If the block number is 0 this block is not stored on disk but
  247. is zero filled instead. */
  248. if (blknr)
  249. {
  250. data->disk->read_hook = read_hook;
  251. data->disk->read_hook_data = read_hook_data;
  252. grub_disk_read (data->disk, blknr, skipfirst,
  253. blockend, buf);
  254. data->disk->read_hook = 0;
  255. if (grub_errno)
  256. return -1;
  257. }
  258. buf += data->blksz - skipfirst;
  259. }
  260. return len;
  261. }
  262. /* Mount the filesystem on the disk DISK. */
  263. static struct grub_hfs_data *
  264. grub_hfs_mount (grub_disk_t disk)
  265. {
  266. struct grub_hfs_data *data;
  267. struct grub_hfs_catalog_key key;
  268. struct grub_hfs_dirrec dir;
  269. int first_block;
  270. struct
  271. {
  272. struct grub_hfs_node node;
  273. struct grub_hfs_treeheader head;
  274. } treehead;
  275. data = grub_malloc (sizeof (struct grub_hfs_data));
  276. if (!data)
  277. return 0;
  278. /* Read the superblock. */
  279. if (grub_disk_read (disk, GRUB_HFS_SBLOCK, 0,
  280. sizeof (struct grub_hfs_sblock), &data->sblock))
  281. goto fail;
  282. /* Check if this is a HFS filesystem. */
  283. if (grub_be_to_cpu16 (data->sblock.magic) != GRUB_HFS_MAGIC
  284. || data->sblock.blksz == 0
  285. || (data->sblock.blksz & grub_cpu_to_be32_compile_time (0xc00001ff)))
  286. {
  287. grub_error (GRUB_ERR_BAD_FS, "not an HFS filesystem");
  288. goto fail;
  289. }
  290. /* Check if this is an embedded HFS+ filesystem. */
  291. if (grub_be_to_cpu16 (data->sblock.embed_sig) == GRUB_HFS_EMBED_HFSPLUS_SIG)
  292. {
  293. grub_error (GRUB_ERR_BAD_FS, "embedded HFS+ filesystem");
  294. goto fail;
  295. }
  296. data->blksz = grub_be_to_cpu32 (data->sblock.blksz);
  297. data->disk = disk;
  298. /* Lookup the root node of the extent overflow tree. */
  299. first_block = ((grub_be_to_cpu16 (data->sblock.extent_recs[0].first_block)
  300. * GRUB_HFS_BLKS)
  301. + grub_be_to_cpu16 (data->sblock.first_block));
  302. if (grub_disk_read (data->disk, first_block, 0,
  303. sizeof (treehead), &treehead))
  304. goto fail;
  305. data->ext_root = grub_be_to_cpu32 (treehead.head.root_node);
  306. data->ext_size = grub_be_to_cpu16 (treehead.head.node_size);
  307. /* Lookup the root node of the catalog tree. */
  308. first_block = ((grub_be_to_cpu16 (data->sblock.catalog_recs[0].first_block)
  309. * GRUB_HFS_BLKS)
  310. + grub_be_to_cpu16 (data->sblock.first_block));
  311. if (grub_disk_read (data->disk, first_block, 0,
  312. sizeof (treehead), &treehead))
  313. goto fail;
  314. data->cat_root = grub_be_to_cpu32 (treehead.head.root_node);
  315. data->cat_size = grub_be_to_cpu16 (treehead.head.node_size);
  316. if (data->cat_size == 0
  317. || data->blksz < data->cat_size
  318. || data->blksz < data->ext_size)
  319. goto fail;
  320. /* Lookup the root directory node in the catalog tree using the
  321. volume name. */
  322. key.parent_dir = grub_cpu_to_be32_compile_time (1);
  323. key.strlen = data->sblock.volname[0];
  324. grub_strcpy ((char *) key.str, (char *) (data->sblock.volname + 1));
  325. if (grub_hfs_find_node (data, (char *) &key, data->cat_root,
  326. 0, (char *) &dir, sizeof (dir)) == 0)
  327. {
  328. grub_error (GRUB_ERR_BAD_FS, "cannot find the HFS root directory");
  329. goto fail;
  330. }
  331. if (grub_errno)
  332. goto fail;
  333. data->rootdir = grub_be_to_cpu32 (dir.dirid);
  334. return data;
  335. fail:
  336. grub_free (data);
  337. if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
  338. grub_error (GRUB_ERR_BAD_FS, "not a HFS filesystem");
  339. return 0;
  340. }
  341. /* Compare the K1 and K2 catalog file keys using HFS character ordering. */
  342. static int
  343. grub_hfs_cmp_catkeys (const struct grub_hfs_catalog_key *k1,
  344. const struct grub_hfs_catalog_key *k2)
  345. {
  346. /* Taken from hfsutils 3.2.6 and converted to a readable form */
  347. static const unsigned char hfs_charorder[256] = {
  348. [0x00] = 0,
  349. [0x01] = 1,
  350. [0x02] = 2,
  351. [0x03] = 3,
  352. [0x04] = 4,
  353. [0x05] = 5,
  354. [0x06] = 6,
  355. [0x07] = 7,
  356. [0x08] = 8,
  357. [0x09] = 9,
  358. [0x0A] = 10,
  359. [0x0B] = 11,
  360. [0x0C] = 12,
  361. [0x0D] = 13,
  362. [0x0E] = 14,
  363. [0x0F] = 15,
  364. [0x10] = 16,
  365. [0x11] = 17,
  366. [0x12] = 18,
  367. [0x13] = 19,
  368. [0x14] = 20,
  369. [0x15] = 21,
  370. [0x16] = 22,
  371. [0x17] = 23,
  372. [0x18] = 24,
  373. [0x19] = 25,
  374. [0x1A] = 26,
  375. [0x1B] = 27,
  376. [0x1C] = 28,
  377. [0x1D] = 29,
  378. [0x1E] = 30,
  379. [0x1F] = 31,
  380. [' '] = 32, [0xCA] = 32,
  381. ['!'] = 33,
  382. ['"'] = 34,
  383. [0xD2] = 35,
  384. [0xD3] = 36,
  385. [0xC7] = 37,
  386. [0xC8] = 38,
  387. ['#'] = 39,
  388. ['$'] = 40,
  389. ['%'] = 41,
  390. ['&'] = 42,
  391. ['\''] = 43,
  392. [0xD4] = 44,
  393. [0xD5] = 45,
  394. ['('] = 46,
  395. [')'] = 47,
  396. ['*'] = 48,
  397. ['+'] = 49,
  398. [','] = 50,
  399. ['-'] = 51,
  400. ['.'] = 52,
  401. ['/'] = 53,
  402. ['0'] = 54,
  403. ['1'] = 55,
  404. ['2'] = 56,
  405. ['3'] = 57,
  406. ['4'] = 58,
  407. ['5'] = 59,
  408. ['6'] = 60,
  409. ['7'] = 61,
  410. ['8'] = 62,
  411. ['9'] = 63,
  412. [':'] = 64,
  413. [';'] = 65,
  414. ['<'] = 66,
  415. ['='] = 67,
  416. ['>'] = 68,
  417. ['?'] = 69,
  418. ['@'] = 70,
  419. ['A'] = 71, ['a'] = 71,
  420. [0x88] = 72, [0xCB] = 72,
  421. [0x80] = 73, [0x8A] = 73,
  422. [0x8B] = 74, [0xCC] = 74,
  423. [0x81] = 75, [0x8C] = 75,
  424. [0xAE] = 76, [0xBE] = 76,
  425. ['`'] = 77,
  426. [0x87] = 78,
  427. [0x89] = 79,
  428. [0xBB] = 80,
  429. ['B'] = 81, ['b'] = 81,
  430. ['C'] = 82, ['c'] = 82,
  431. [0x82] = 83, [0x8D] = 83,
  432. ['D'] = 84, ['d'] = 84,
  433. ['E'] = 85, ['e'] = 85,
  434. [0x83] = 86, [0x8E] = 86,
  435. [0x8F] = 87,
  436. [0x90] = 88,
  437. [0x91] = 89,
  438. ['F'] = 90, ['f'] = 90,
  439. ['G'] = 91, ['g'] = 91,
  440. ['H'] = 92, ['h'] = 92,
  441. ['I'] = 93, ['i'] = 93,
  442. [0x92] = 94,
  443. [0x93] = 95,
  444. [0x94] = 96,
  445. [0x95] = 97,
  446. ['J'] = 98, ['j'] = 98,
  447. ['K'] = 99, ['k'] = 99,
  448. ['L'] = 100, ['l'] = 100,
  449. ['M'] = 101, ['m'] = 101,
  450. ['N'] = 102, ['n'] = 102,
  451. [0x84] = 103, [0x96] = 103,
  452. ['O'] = 104, ['o'] = 104,
  453. [0x85] = 105, [0x9A] = 105,
  454. [0x9B] = 106, [0xCD] = 106,
  455. [0xAF] = 107, [0xBF] = 107,
  456. [0xCE] = 108, [0xCF] = 108,
  457. [0x97] = 109,
  458. [0x98] = 110,
  459. [0x99] = 111,
  460. [0xBC] = 112,
  461. ['P'] = 113, ['p'] = 113,
  462. ['Q'] = 114, ['q'] = 114,
  463. ['R'] = 115, ['r'] = 115,
  464. ['S'] = 116, ['s'] = 116,
  465. [0xA7] = 117,
  466. ['T'] = 118, ['t'] = 118,
  467. ['U'] = 119, ['u'] = 119,
  468. [0x86] = 120, [0x9F] = 120,
  469. [0x9C] = 121,
  470. [0x9D] = 122,
  471. [0x9E] = 123,
  472. ['V'] = 124, ['v'] = 124,
  473. ['W'] = 125, ['w'] = 125,
  474. ['X'] = 126, ['x'] = 126,
  475. ['Y'] = 127, ['y'] = 127,
  476. [0xD8] = 128,
  477. ['Z'] = 129, ['z'] = 129,
  478. ['['] = 130,
  479. ['\\'] = 131,
  480. [']'] = 132,
  481. ['^'] = 133,
  482. ['_'] = 134,
  483. ['{'] = 135,
  484. ['|'] = 136,
  485. ['}'] = 137,
  486. ['~'] = 138,
  487. [0x7F] = 139,
  488. [0xA0] = 140,
  489. [0xA1] = 141,
  490. [0xA2] = 142,
  491. [0xA3] = 143,
  492. [0xA4] = 144,
  493. [0xA5] = 145,
  494. [0xA6] = 146,
  495. [0xA8] = 147,
  496. [0xA9] = 148,
  497. [0xAA] = 149,
  498. [0xAB] = 150,
  499. [0xAC] = 151,
  500. [0xAD] = 152,
  501. [0xB0] = 153,
  502. [0xB1] = 154,
  503. [0xB2] = 155,
  504. [0xB3] = 156,
  505. [0xB4] = 157,
  506. [0xB5] = 158,
  507. [0xB6] = 159,
  508. [0xB7] = 160,
  509. [0xB8] = 161,
  510. [0xB9] = 162,
  511. [0xBA] = 163,
  512. [0xBD] = 164,
  513. [0xC0] = 165,
  514. [0xC1] = 166,
  515. [0xC2] = 167,
  516. [0xC3] = 168,
  517. [0xC4] = 169,
  518. [0xC5] = 170,
  519. [0xC6] = 171,
  520. [0xC9] = 172,
  521. [0xD0] = 173,
  522. [0xD1] = 174,
  523. [0xD6] = 175,
  524. [0xD7] = 176,
  525. [0xD9] = 177,
  526. [0xDA] = 178,
  527. [0xDB] = 179,
  528. [0xDC] = 180,
  529. [0xDD] = 181,
  530. [0xDE] = 182,
  531. [0xDF] = 183,
  532. [0xE0] = 184,
  533. [0xE1] = 185,
  534. [0xE2] = 186,
  535. [0xE3] = 187,
  536. [0xE4] = 188,
  537. [0xE5] = 189,
  538. [0xE6] = 190,
  539. [0xE7] = 191,
  540. [0xE8] = 192,
  541. [0xE9] = 193,
  542. [0xEA] = 194,
  543. [0xEB] = 195,
  544. [0xEC] = 196,
  545. [0xED] = 197,
  546. [0xEE] = 198,
  547. [0xEF] = 199,
  548. [0xF0] = 200,
  549. [0xF1] = 201,
  550. [0xF2] = 202,
  551. [0xF3] = 203,
  552. [0xF4] = 204,
  553. [0xF5] = 205,
  554. [0xF6] = 206,
  555. [0xF7] = 207,
  556. [0xF8] = 208,
  557. [0xF9] = 209,
  558. [0xFA] = 210,
  559. [0xFB] = 211,
  560. [0xFC] = 212,
  561. [0xFD] = 213,
  562. [0xFE] = 214,
  563. [0xFF] = 215,
  564. };
  565. int i;
  566. int cmp;
  567. int minlen = (k1->strlen < k2->strlen) ? k1->strlen : k2->strlen;
  568. cmp = (grub_be_to_cpu32 (k1->parent_dir) - grub_be_to_cpu32 (k2->parent_dir));
  569. if (cmp != 0)
  570. return cmp;
  571. for (i = 0; i < minlen; i++)
  572. {
  573. cmp = (hfs_charorder[k1->str[i]] - hfs_charorder[k2->str[i]]);
  574. if (cmp != 0)
  575. return cmp;
  576. }
  577. /* Shorter strings precede long ones. */
  578. return (k1->strlen - k2->strlen);
  579. }
  580. /* Compare the K1 and K2 extent overflow file keys. */
  581. static int
  582. grub_hfs_cmp_extkeys (const struct grub_hfs_extent_key *k1,
  583. const struct grub_hfs_extent_key *k2)
  584. {
  585. int cmp = k1->forktype - k2->forktype;
  586. if (cmp == 0)
  587. cmp = grub_be_to_cpu32 (k1->fileid) - grub_be_to_cpu32 (k2->fileid);
  588. if (cmp == 0)
  589. cmp = (grub_be_to_cpu16 (k1->first_block)
  590. - grub_be_to_cpu16 (k2->first_block));
  591. return cmp;
  592. }
  593. /* Iterate the records in the node with index IDX in the mounted HFS
  594. filesystem DATA. This node holds data of the type TYPE (0 =
  595. catalog node, 1 = extent overflow node). If this is set, continue
  596. iterating to the next node. For every records, call NODE_HOOK. */
  597. static grub_err_t
  598. grub_hfs_iterate_records (struct grub_hfs_data *data, int type, int idx,
  599. int this, int (*node_hook) (struct grub_hfs_node *hnd,
  600. struct grub_hfs_record *,
  601. void *hook_arg),
  602. void *hook_arg)
  603. {
  604. grub_size_t nodesize = type == 0 ? data->cat_size : data->ext_size;
  605. union node_union
  606. {
  607. struct grub_hfs_node node;
  608. char rawnode[0];
  609. grub_uint16_t offsets[0];
  610. } *node;
  611. if (nodesize < sizeof (struct grub_hfs_node))
  612. nodesize = sizeof (struct grub_hfs_node);
  613. node = grub_malloc (nodesize);
  614. if (!node)
  615. return grub_errno;
  616. do
  617. {
  618. int i;
  619. struct grub_hfs_extent *dat;
  620. int blk;
  621. grub_uint16_t reccnt;
  622. dat = (struct grub_hfs_extent *) (type == 0
  623. ? (&data->sblock.catalog_recs)
  624. : (&data->sblock.extent_recs));
  625. /* Read the node into memory. */
  626. blk = grub_hfs_block (data, dat,
  627. (type == 0) ? GRUB_HFS_CNID_CAT : GRUB_HFS_CNID_EXT,
  628. idx / (data->blksz / nodesize), 0);
  629. blk += (idx % (data->blksz / nodesize));
  630. if (grub_errno || grub_disk_read (data->disk, blk, 0,
  631. nodesize, node))
  632. {
  633. grub_free (node);
  634. return grub_errno;
  635. }
  636. reccnt = grub_be_to_cpu16 (node->node.reccnt);
  637. if (reccnt > (nodesize >> 1))
  638. reccnt = (nodesize >> 1);
  639. /* Iterate over all records in this node. */
  640. for (i = 0; i < reccnt; i++)
  641. {
  642. int pos = (nodesize >> 1) - 1 - i;
  643. struct pointer
  644. {
  645. grub_uint8_t keylen;
  646. grub_uint8_t key;
  647. } GRUB_PACKED *pnt;
  648. grub_uint16_t off = grub_be_to_cpu16 (node->offsets[pos]);
  649. if (off > nodesize - sizeof(*pnt))
  650. continue;
  651. pnt = (struct pointer *) (off + node->rawnode);
  652. if (nodesize < (grub_size_t) off + pnt->keylen + 1)
  653. continue;
  654. struct grub_hfs_record rec =
  655. {
  656. &pnt->key,
  657. pnt->keylen,
  658. &pnt->key + pnt->keylen +(pnt->keylen + 1) % 2,
  659. nodesize - off - pnt->keylen - 1
  660. };
  661. if (node_hook (&node->node, &rec, hook_arg))
  662. {
  663. grub_free (node);
  664. return 0;
  665. }
  666. }
  667. idx = grub_be_to_cpu32 (node->node.next);
  668. } while (idx && this);
  669. grub_free (node);
  670. return 0;
  671. }
  672. struct grub_hfs_find_node_node_found_ctx
  673. {
  674. int found;
  675. int isleaf;
  676. int done;
  677. int type;
  678. const char *key;
  679. char *datar;
  680. grub_size_t datalen;
  681. };
  682. static int
  683. grub_hfs_find_node_node_found (struct grub_hfs_node *hnd, struct grub_hfs_record *rec,
  684. void *hook_arg)
  685. {
  686. struct grub_hfs_find_node_node_found_ctx *ctx = hook_arg;
  687. int cmp = 1;
  688. if (ctx->type == 0)
  689. cmp = grub_hfs_cmp_catkeys (rec->key, (const void *) ctx->key);
  690. else
  691. cmp = grub_hfs_cmp_extkeys (rec->key, (const void *) ctx->key);
  692. /* If the key is smaller or equal to the current node, mark the
  693. entry. In case of a non-leaf mode it will be used to lookup
  694. the rest of the tree. */
  695. if (cmp <= 0)
  696. ctx->found = grub_be_to_cpu32 (grub_get_unaligned32 (rec->data));
  697. else /* The key can not be found in the tree. */
  698. return 1;
  699. /* Check if this node is a leaf node. */
  700. if (hnd->type == GRUB_HFS_NODE_LEAF)
  701. {
  702. ctx->isleaf = 1;
  703. /* Found it!!!! */
  704. if (cmp == 0)
  705. {
  706. ctx->done = 1;
  707. grub_memcpy (ctx->datar, rec->data,
  708. rec->datalen < ctx->datalen ? rec->datalen : ctx->datalen);
  709. return 1;
  710. }
  711. }
  712. return 0;
  713. }
  714. /* Lookup a record in the mounted filesystem DATA using the key KEY.
  715. The index of the node on top of the tree is IDX. The tree is of
  716. the type TYPE (0 = catalog node, 1 = extent overflow node). Return
  717. the data in DATAR with a maximum length of DATALEN. */
  718. static int
  719. grub_hfs_find_node (struct grub_hfs_data *data, char *key,
  720. grub_uint32_t idx, int type, char *datar, grub_size_t datalen)
  721. {
  722. struct grub_hfs_find_node_node_found_ctx ctx =
  723. {
  724. .found = -1,
  725. .isleaf = 0,
  726. .done = 0,
  727. .type = type,
  728. .key = key,
  729. .datar = datar,
  730. .datalen = datalen
  731. };
  732. do
  733. {
  734. ctx.found = -1;
  735. if (grub_hfs_iterate_records (data, type, idx, 0, grub_hfs_find_node_node_found, &ctx))
  736. return 0;
  737. if (ctx.found == -1)
  738. return 0;
  739. idx = ctx.found;
  740. } while (! ctx.isleaf);
  741. return ctx.done;
  742. }
  743. struct grub_hfs_iterate_dir_node_found_ctx
  744. {
  745. grub_uint32_t dir_be;
  746. int found;
  747. int isleaf;
  748. grub_uint32_t next;
  749. int (*hook) (struct grub_hfs_record *, void *hook_arg);
  750. void *hook_arg;
  751. };
  752. static int
  753. grub_hfs_iterate_dir_node_found (struct grub_hfs_node *hnd, struct grub_hfs_record *rec,
  754. void *hook_arg)
  755. {
  756. struct grub_hfs_iterate_dir_node_found_ctx *ctx = hook_arg;
  757. struct grub_hfs_catalog_key *ckey = rec->key;
  758. /* The lowest key possible with DIR as root directory. */
  759. const struct grub_hfs_catalog_key key = {0, ctx->dir_be, 0, ""};
  760. if (grub_hfs_cmp_catkeys (rec->key, &key) <= 0)
  761. ctx->found = grub_be_to_cpu32 (grub_get_unaligned32 (rec->data));
  762. if (hnd->type == 0xFF && ckey->strlen > 0)
  763. {
  764. ctx->isleaf = 1;
  765. ctx->next = grub_be_to_cpu32 (hnd->next);
  766. /* An entry was found. */
  767. if (ckey->parent_dir == ctx->dir_be)
  768. return ctx->hook (rec, ctx->hook_arg);
  769. }
  770. return 0;
  771. }
  772. static int
  773. grub_hfs_iterate_dir_it_dir (struct grub_hfs_node *hnd __attribute ((unused)),
  774. struct grub_hfs_record *rec,
  775. void *hook_arg)
  776. {
  777. struct grub_hfs_catalog_key *ckey = rec->key;
  778. struct grub_hfs_iterate_dir_node_found_ctx *ctx = hook_arg;
  779. /* Stop when the entries do not match anymore. */
  780. if (ckey->parent_dir != ctx->dir_be)
  781. return 1;
  782. return ctx->hook (rec, ctx->hook_arg);
  783. }
  784. /* Iterate over the directory with the id DIR. The tree is searched
  785. starting with the node ROOT_IDX. For every entry in this directory
  786. call HOOK. */
  787. static grub_err_t
  788. grub_hfs_iterate_dir (struct grub_hfs_data *data, grub_uint32_t root_idx,
  789. grub_uint32_t dir, int (*hook) (struct grub_hfs_record *, void *hook_arg),
  790. void *hook_arg)
  791. {
  792. struct grub_hfs_iterate_dir_node_found_ctx ctx =
  793. {
  794. .dir_be = grub_cpu_to_be32 (dir),
  795. .found = -1,
  796. .isleaf = 0,
  797. .next = 0,
  798. .hook = hook,
  799. .hook_arg = hook_arg
  800. };
  801. do
  802. {
  803. ctx.found = -1;
  804. if (grub_hfs_iterate_records (data, 0, root_idx, 0, grub_hfs_iterate_dir_node_found, &ctx))
  805. return grub_errno;
  806. if (ctx.found == -1)
  807. return 0;
  808. root_idx = ctx.found;
  809. } while (! ctx.isleaf);
  810. /* If there was a matching record in this leaf node, continue the
  811. iteration until the last record was found. */
  812. grub_hfs_iterate_records (data, 0, ctx.next, 1, grub_hfs_iterate_dir_it_dir, &ctx);
  813. return grub_errno;
  814. }
  815. #define MAX_UTF8_PER_MAC_ROMAN 3
  816. static const char macroman[0x80][MAX_UTF8_PER_MAC_ROMAN + 1] =
  817. {
  818. /* 80 */ "\xc3\x84",
  819. /* 81 */ "\xc3\x85",
  820. /* 82 */ "\xc3\x87",
  821. /* 83 */ "\xc3\x89",
  822. /* 84 */ "\xc3\x91",
  823. /* 85 */ "\xc3\x96",
  824. /* 86 */ "\xc3\x9c",
  825. /* 87 */ "\xc3\xa1",
  826. /* 88 */ "\xc3\xa0",
  827. /* 89 */ "\xc3\xa2",
  828. /* 8A */ "\xc3\xa4",
  829. /* 8B */ "\xc3\xa3",
  830. /* 8C */ "\xc3\xa5",
  831. /* 8D */ "\xc3\xa7",
  832. /* 8E */ "\xc3\xa9",
  833. /* 8F */ "\xc3\xa8",
  834. /* 90 */ "\xc3\xaa",
  835. /* 91 */ "\xc3\xab",
  836. /* 92 */ "\xc3\xad",
  837. /* 93 */ "\xc3\xac",
  838. /* 94 */ "\xc3\xae",
  839. /* 95 */ "\xc3\xaf",
  840. /* 96 */ "\xc3\xb1",
  841. /* 97 */ "\xc3\xb3",
  842. /* 98 */ "\xc3\xb2",
  843. /* 99 */ "\xc3\xb4",
  844. /* 9A */ "\xc3\xb6",
  845. /* 9B */ "\xc3\xb5",
  846. /* 9C */ "\xc3\xba",
  847. /* 9D */ "\xc3\xb9",
  848. /* 9E */ "\xc3\xbb",
  849. /* 9F */ "\xc3\xbc",
  850. /* A0 */ "\xe2\x80\xa0",
  851. /* A1 */ "\xc2\xb0",
  852. /* A2 */ "\xc2\xa2",
  853. /* A3 */ "\xc2\xa3",
  854. /* A4 */ "\xc2\xa7",
  855. /* A5 */ "\xe2\x80\xa2",
  856. /* A6 */ "\xc2\xb6",
  857. /* A7 */ "\xc3\x9f",
  858. /* A8 */ "\xc2\xae",
  859. /* A9 */ "\xc2\xa9",
  860. /* AA */ "\xe2\x84\xa2",
  861. /* AB */ "\xc2\xb4",
  862. /* AC */ "\xc2\xa8",
  863. /* AD */ "\xe2\x89\xa0",
  864. /* AE */ "\xc3\x86",
  865. /* AF */ "\xc3\x98",
  866. /* B0 */ "\xe2\x88\x9e",
  867. /* B1 */ "\xc2\xb1",
  868. /* B2 */ "\xe2\x89\xa4",
  869. /* B3 */ "\xe2\x89\xa5",
  870. /* B4 */ "\xc2\xa5",
  871. /* B5 */ "\xc2\xb5",
  872. /* B6 */ "\xe2\x88\x82",
  873. /* B7 */ "\xe2\x88\x91",
  874. /* B8 */ "\xe2\x88\x8f",
  875. /* B9 */ "\xcf\x80",
  876. /* BA */ "\xe2\x88\xab",
  877. /* BB */ "\xc2\xaa",
  878. /* BC */ "\xc2\xba",
  879. /* BD */ "\xce\xa9",
  880. /* BE */ "\xc3\xa6",
  881. /* BF */ "\xc3\xb8",
  882. /* C0 */ "\xc2\xbf",
  883. /* C1 */ "\xc2\xa1",
  884. /* C2 */ "\xc2\xac",
  885. /* C3 */ "\xe2\x88\x9a",
  886. /* C4 */ "\xc6\x92",
  887. /* C5 */ "\xe2\x89\x88",
  888. /* C6 */ "\xe2\x88\x86",
  889. /* C7 */ "\xc2\xab",
  890. /* C8 */ "\xc2\xbb",
  891. /* C9 */ "\xe2\x80\xa6",
  892. /* CA */ "\xc2\xa0",
  893. /* CB */ "\xc3\x80",
  894. /* CC */ "\xc3\x83",
  895. /* CD */ "\xc3\x95",
  896. /* CE */ "\xc5\x92",
  897. /* CF */ "\xc5\x93",
  898. /* D0 */ "\xe2\x80\x93",
  899. /* D1 */ "\xe2\x80\x94",
  900. /* D2 */ "\xe2\x80\x9c",
  901. /* D3 */ "\xe2\x80\x9d",
  902. /* D4 */ "\xe2\x80\x98",
  903. /* D5 */ "\xe2\x80\x99",
  904. /* D6 */ "\xc3\xb7",
  905. /* D7 */ "\xe2\x97\x8a",
  906. /* D8 */ "\xc3\xbf",
  907. /* D9 */ "\xc5\xb8",
  908. /* DA */ "\xe2\x81\x84",
  909. /* DB */ "\xe2\x82\xac",
  910. /* DC */ "\xe2\x80\xb9",
  911. /* DD */ "\xe2\x80\xba",
  912. /* DE */ "\xef\xac\x81",
  913. /* DF */ "\xef\xac\x82",
  914. /* E0 */ "\xe2\x80\xa1",
  915. /* E1 */ "\xc2\xb7",
  916. /* E2 */ "\xe2\x80\x9a",
  917. /* E3 */ "\xe2\x80\x9e",
  918. /* E4 */ "\xe2\x80\xb0",
  919. /* E5 */ "\xc3\x82",
  920. /* E6 */ "\xc3\x8a",
  921. /* E7 */ "\xc3\x81",
  922. /* E8 */ "\xc3\x8b",
  923. /* E9 */ "\xc3\x88",
  924. /* EA */ "\xc3\x8d",
  925. /* EB */ "\xc3\x8e",
  926. /* EC */ "\xc3\x8f",
  927. /* ED */ "\xc3\x8c",
  928. /* EE */ "\xc3\x93",
  929. /* EF */ "\xc3\x94",
  930. /* F0 */ "\xef\xa3\xbf",
  931. /* F1 */ "\xc3\x92",
  932. /* F2 */ "\xc3\x9a",
  933. /* F3 */ "\xc3\x9b",
  934. /* F4 */ "\xc3\x99",
  935. /* F5 */ "\xc4\xb1",
  936. /* F6 */ "\xcb\x86",
  937. /* F7 */ "\xcb\x9c",
  938. /* F8 */ "\xc2\xaf",
  939. /* F9 */ "\xcb\x98",
  940. /* FA */ "\xcb\x99",
  941. /* FB */ "\xcb\x9a",
  942. /* FC */ "\xc2\xb8",
  943. /* FD */ "\xcb\x9d",
  944. /* FE */ "\xcb\x9b",
  945. /* FF */ "\xcb\x87",
  946. };
  947. static void
  948. macroman_to_utf8 (char *to, const grub_uint8_t *from, grub_size_t len,
  949. int translate_slash)
  950. {
  951. char *optr = to;
  952. const grub_uint8_t *iptr;
  953. for (iptr = from; iptr < from + len && *iptr; iptr++)
  954. {
  955. /* Translate '/' to ':' as per HFS spec. */
  956. if (*iptr == '/' && translate_slash)
  957. {
  958. *optr++ = ':';
  959. continue;
  960. }
  961. if (!(*iptr & 0x80))
  962. {
  963. *optr++ = *iptr;
  964. continue;
  965. }
  966. optr = grub_stpcpy (optr, macroman[*iptr & 0x7f]);
  967. }
  968. *optr = 0;
  969. }
  970. static grub_ssize_t
  971. utf8_to_macroman (grub_uint8_t *to, const char *from)
  972. {
  973. grub_uint8_t *end = to + 31;
  974. grub_uint8_t *optr = to;
  975. const char *iptr = from;
  976. while (*iptr && optr < end)
  977. {
  978. int i, clen;
  979. /* Translate ':' to '/' as per HFS spec. */
  980. if (*iptr == ':')
  981. {
  982. *optr++ = '/';
  983. iptr++;
  984. continue;
  985. }
  986. if (!(*iptr & 0x80))
  987. {
  988. *optr++ = *iptr++;
  989. continue;
  990. }
  991. clen = 2;
  992. if ((*iptr & 0xf0) == 0xe0)
  993. clen++;
  994. for (i = 0; i < 0x80; i++)
  995. if (grub_memcmp (macroman[i], iptr, clen) == 0)
  996. break;
  997. if (i == 0x80)
  998. break;
  999. *optr++ = i | 0x80;
  1000. iptr += clen;
  1001. }
  1002. /* Too long or not encodable. */
  1003. if (*iptr)
  1004. return -1;
  1005. return optr - to;
  1006. }
  1007. union grub_hfs_anyrec {
  1008. struct grub_hfs_filerec frec;
  1009. struct grub_hfs_dirrec dir;
  1010. };
  1011. struct grub_fshelp_node
  1012. {
  1013. struct grub_hfs_data *data;
  1014. union grub_hfs_anyrec fdrec;
  1015. grub_uint32_t inode;
  1016. };
  1017. static grub_err_t
  1018. lookup_file (grub_fshelp_node_t dir,
  1019. const char *name,
  1020. grub_fshelp_node_t *foundnode,
  1021. enum grub_fshelp_filetype *foundtype)
  1022. {
  1023. struct grub_hfs_catalog_key key;
  1024. grub_ssize_t slen;
  1025. union grub_hfs_anyrec fdrec;
  1026. key.parent_dir = grub_cpu_to_be32 (dir->inode);
  1027. slen = utf8_to_macroman (key.str, name);
  1028. if (slen < 0)
  1029. /* Not found */
  1030. return GRUB_ERR_NONE;
  1031. key.strlen = slen;
  1032. /* Lookup this node. */
  1033. if (! grub_hfs_find_node (dir->data, (char *) &key, dir->data->cat_root,
  1034. 0, (char *) &fdrec.frec, sizeof (fdrec.frec)))
  1035. /* Not found */
  1036. return GRUB_ERR_NONE;
  1037. *foundnode = grub_malloc (sizeof (struct grub_fshelp_node));
  1038. if (!*foundnode)
  1039. return grub_errno;
  1040. (*foundnode)->inode = grub_be_to_cpu32 (fdrec.dir.dirid);
  1041. (*foundnode)->fdrec = fdrec;
  1042. (*foundnode)->data = dir->data;
  1043. *foundtype = (fdrec.frec.type == GRUB_HFS_FILETYPE_DIR) ? GRUB_FSHELP_DIR : GRUB_FSHELP_REG;
  1044. return GRUB_ERR_NONE;
  1045. }
  1046. /* Find a file or directory with the pathname PATH in the filesystem
  1047. DATA. Return the file record in RETDATA when it is non-zero.
  1048. Return the directory number in RETINODE when it is non-zero. */
  1049. static grub_err_t
  1050. grub_hfs_find_dir (struct grub_hfs_data *data, const char *path,
  1051. grub_fshelp_node_t *found,
  1052. enum grub_fshelp_filetype exptype)
  1053. {
  1054. struct grub_fshelp_node root = {
  1055. .data = data,
  1056. .inode = data->rootdir,
  1057. .fdrec = {
  1058. .frec = {
  1059. .type = GRUB_HFS_FILETYPE_DIR
  1060. }
  1061. }
  1062. };
  1063. grub_err_t err;
  1064. err = grub_fshelp_find_file_lookup (path, &root, found, lookup_file, NULL, exptype);
  1065. if (&root == *found)
  1066. {
  1067. *found = grub_malloc (sizeof (root));
  1068. if (!*found)
  1069. return grub_errno;
  1070. grub_memcpy (*found, &root, sizeof (root));
  1071. }
  1072. return err;
  1073. }
  1074. struct grub_hfs_dir_hook_ctx
  1075. {
  1076. grub_fs_dir_hook_t hook;
  1077. void *hook_data;
  1078. };
  1079. static int
  1080. grub_hfs_dir_hook (struct grub_hfs_record *rec, void *hook_arg)
  1081. {
  1082. struct grub_hfs_dir_hook_ctx *ctx = hook_arg;
  1083. struct grub_hfs_dirrec *drec = rec->data;
  1084. struct grub_hfs_filerec *frec = rec->data;
  1085. struct grub_hfs_catalog_key *ckey = rec->key;
  1086. char fname[sizeof (ckey->str) * MAX_UTF8_PER_MAC_ROMAN + 1];
  1087. struct grub_dirhook_info info;
  1088. grub_size_t len;
  1089. grub_memset (fname, 0, sizeof (fname));
  1090. grub_memset (&info, 0, sizeof (info));
  1091. len = ckey->strlen;
  1092. if (len > sizeof (ckey->str))
  1093. len = sizeof (ckey->str);
  1094. macroman_to_utf8 (fname, ckey->str, len, 1);
  1095. info.case_insensitive = 1;
  1096. if (drec->type == GRUB_HFS_FILETYPE_DIR)
  1097. {
  1098. info.dir = 1;
  1099. info.mtimeset = 1;
  1100. info.inodeset = 1;
  1101. info.mtime = grub_be_to_cpu32 (drec->mtime) - 2082844800;
  1102. info.inode = grub_be_to_cpu32 (drec->dirid);
  1103. return ctx->hook (fname, &info, ctx->hook_data);
  1104. }
  1105. if (frec->type == GRUB_HFS_FILETYPE_FILE)
  1106. {
  1107. info.dir = 0;
  1108. info.mtimeset = 1;
  1109. info.inodeset = 1;
  1110. info.mtime = grub_be_to_cpu32 (frec->mtime) - 2082844800;
  1111. info.inode = grub_be_to_cpu32 (frec->fileid);
  1112. return ctx->hook (fname, &info, ctx->hook_data);
  1113. }
  1114. return 0;
  1115. }
  1116. static grub_err_t
  1117. grub_hfs_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
  1118. void *hook_data)
  1119. {
  1120. struct grub_hfs_data *data;
  1121. struct grub_hfs_dir_hook_ctx ctx =
  1122. {
  1123. .hook = hook,
  1124. .hook_data = hook_data
  1125. };
  1126. grub_fshelp_node_t found = NULL;
  1127. grub_dl_ref (my_mod);
  1128. data = grub_hfs_mount (device->disk);
  1129. if (!data)
  1130. goto fail;
  1131. /* First the directory ID for the directory. */
  1132. if (grub_hfs_find_dir (data, path, &found, GRUB_FSHELP_DIR))
  1133. goto fail;
  1134. grub_hfs_iterate_dir (data, data->cat_root, found->inode, grub_hfs_dir_hook, &ctx);
  1135. fail:
  1136. grub_free (found);
  1137. grub_free (data);
  1138. grub_dl_unref (my_mod);
  1139. return grub_errno;
  1140. }
  1141. /* Open a file named NAME and initialize FILE. */
  1142. static grub_err_t
  1143. grub_hfs_open (struct grub_file *file, const char *name)
  1144. {
  1145. struct grub_hfs_data *data;
  1146. grub_fshelp_node_t found = NULL;
  1147. grub_dl_ref (my_mod);
  1148. data = grub_hfs_mount (file->device->disk);
  1149. if (!data)
  1150. {
  1151. grub_dl_unref (my_mod);
  1152. return grub_errno;
  1153. }
  1154. if (grub_hfs_find_dir (data, name, &found, GRUB_FSHELP_REG))
  1155. {
  1156. grub_free (data);
  1157. grub_free (found);
  1158. grub_dl_unref (my_mod);
  1159. return grub_errno;
  1160. }
  1161. grub_memcpy (data->extents, found->fdrec.frec.extents, sizeof (grub_hfs_datarecord_t));
  1162. file->size = grub_be_to_cpu32 (found->fdrec.frec.size);
  1163. data->size = grub_be_to_cpu32 (found->fdrec.frec.size);
  1164. data->fileid = grub_be_to_cpu32 (found->fdrec.frec.fileid);
  1165. file->offset = 0;
  1166. file->data = data;
  1167. grub_free (found);
  1168. return 0;
  1169. }
  1170. static grub_ssize_t
  1171. grub_hfs_read (grub_file_t file, char *buf, grub_size_t len)
  1172. {
  1173. struct grub_hfs_data *data =
  1174. (struct grub_hfs_data *) file->data;
  1175. return grub_hfs_read_file (data, file->read_hook, file->read_hook_data,
  1176. file->offset, len, buf);
  1177. }
  1178. static grub_err_t
  1179. grub_hfs_close (grub_file_t file)
  1180. {
  1181. grub_free (file->data);
  1182. grub_dl_unref (my_mod);
  1183. return 0;
  1184. }
  1185. static grub_err_t
  1186. grub_hfs_label (grub_device_t device, char **label)
  1187. {
  1188. struct grub_hfs_data *data;
  1189. data = grub_hfs_mount (device->disk);
  1190. if (data)
  1191. {
  1192. grub_size_t len = data->sblock.volname[0];
  1193. if (len > sizeof (data->sblock.volname) - 1)
  1194. len = sizeof (data->sblock.volname) - 1;
  1195. *label = grub_calloc (MAX_UTF8_PER_MAC_ROMAN + 1, len);
  1196. if (*label)
  1197. macroman_to_utf8 (*label, data->sblock.volname + 1,
  1198. len + 1, 0);
  1199. }
  1200. else
  1201. *label = 0;
  1202. grub_free (data);
  1203. return grub_errno;
  1204. }
  1205. static grub_err_t
  1206. grub_hfs_mtime (grub_device_t device, grub_int64_t *tm)
  1207. {
  1208. struct grub_hfs_data *data;
  1209. data = grub_hfs_mount (device->disk);
  1210. if (data)
  1211. *tm = grub_be_to_cpu32 (data->sblock.mtime) - 2082844800;
  1212. else
  1213. *tm = 0;
  1214. grub_free (data);
  1215. return grub_errno;
  1216. }
  1217. static grub_err_t
  1218. grub_hfs_uuid (grub_device_t device, char **uuid)
  1219. {
  1220. struct grub_hfs_data *data;
  1221. grub_dl_ref (my_mod);
  1222. data = grub_hfs_mount (device->disk);
  1223. if (data && data->sblock.num_serial != 0)
  1224. {
  1225. *uuid = grub_xasprintf ("%016llx",
  1226. (unsigned long long)
  1227. grub_be_to_cpu64 (data->sblock.num_serial));
  1228. }
  1229. else
  1230. *uuid = NULL;
  1231. grub_dl_unref (my_mod);
  1232. grub_free (data);
  1233. return grub_errno;
  1234. }
  1235. static struct grub_fs grub_hfs_fs =
  1236. {
  1237. .name = "hfs",
  1238. .fs_dir = grub_hfs_dir,
  1239. .fs_open = grub_hfs_open,
  1240. .fs_read = grub_hfs_read,
  1241. .fs_close = grub_hfs_close,
  1242. .fs_label = grub_hfs_label,
  1243. .fs_uuid = grub_hfs_uuid,
  1244. .fs_mtime = grub_hfs_mtime,
  1245. #ifdef GRUB_UTIL
  1246. .reserved_first_sector = 1,
  1247. .blocklist_install = 1,
  1248. #endif
  1249. .next = 0
  1250. };
  1251. GRUB_MOD_INIT(hfs)
  1252. {
  1253. if (!grub_is_lockdown ())
  1254. grub_fs_register (&grub_hfs_fs);
  1255. my_mod = mod;
  1256. }
  1257. GRUB_MOD_FINI(hfs)
  1258. {
  1259. if (!grub_is_lockdown())
  1260. grub_fs_unregister (&grub_hfs_fs);
  1261. }