bfs.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  1. /* bfs.c - The Bee File System. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2010,2011 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. /*
  20. Based on the book "Practical File System Design by Dominic Giampaolo
  21. with corrections and completitions based on Haiku code.
  22. */
  23. #include <grub/err.h>
  24. #include <grub/file.h>
  25. #include <grub/mm.h>
  26. #include <grub/misc.h>
  27. #include <grub/disk.h>
  28. #include <grub/dl.h>
  29. #include <grub/types.h>
  30. #include <grub/i18n.h>
  31. #include <grub/fshelp.h>
  32. #include <grub/lockdown.h>
  33. GRUB_MOD_LICENSE ("GPLv3+");
  34. #ifdef MODE_AFS
  35. #define BTREE_ALIGN 4
  36. #define SUPERBLOCK 2
  37. #else
  38. #define BTREE_ALIGN 8
  39. #define SUPERBLOCK 1
  40. #endif
  41. #define grub_bfs_to_cpu16 grub_le_to_cpu16
  42. #define grub_bfs_to_cpu32 grub_le_to_cpu32
  43. #define grub_bfs_to_cpu64 grub_le_to_cpu64
  44. #define grub_cpu_to_bfs32_compile_time grub_cpu_to_le32_compile_time
  45. #ifdef MODE_AFS
  46. #define grub_bfs_to_cpu_treehead grub_bfs_to_cpu32
  47. #else
  48. #define grub_bfs_to_cpu_treehead grub_bfs_to_cpu16
  49. #endif
  50. #ifdef MODE_AFS
  51. #define SUPER_BLOCK_MAGIC1 0x41465331
  52. #else
  53. #define SUPER_BLOCK_MAGIC1 0x42465331
  54. #endif
  55. #define SUPER_BLOCK_MAGIC2 0xdd121031
  56. #define SUPER_BLOCK_MAGIC3 0x15b6830e
  57. #define POINTER_INVALID 0xffffffffffffffffULL
  58. #define ATTR_TYPE 0160000
  59. #define ATTR_REG 0100000
  60. #define ATTR_DIR 0040000
  61. #define ATTR_LNK 0120000
  62. #define DOUBLE_INDIRECT_SHIFT 2
  63. #define LOG_EXTENT_SIZE 3
  64. struct grub_bfs_extent
  65. {
  66. grub_uint32_t ag;
  67. grub_uint16_t start;
  68. grub_uint16_t len;
  69. } GRUB_PACKED;
  70. struct grub_bfs_superblock
  71. {
  72. char label[32];
  73. grub_uint32_t magic1;
  74. grub_uint32_t unused1;
  75. grub_uint32_t bsize;
  76. grub_uint32_t log2_bsize;
  77. grub_uint8_t unused[20];
  78. grub_uint32_t magic2;
  79. grub_uint32_t unused2;
  80. grub_uint32_t log2_ag_size;
  81. grub_uint8_t unused3[32];
  82. grub_uint32_t magic3;
  83. struct grub_bfs_extent root_dir;
  84. } GRUB_PACKED;
  85. struct grub_bfs_inode
  86. {
  87. grub_uint8_t unused[20];
  88. grub_uint32_t mode;
  89. grub_uint32_t flags;
  90. #ifdef MODE_AFS
  91. grub_uint8_t unused2[12];
  92. #else
  93. grub_uint8_t unused2[8];
  94. #endif
  95. grub_uint64_t mtime;
  96. grub_uint8_t unused3[8];
  97. struct grub_bfs_extent attr;
  98. grub_uint8_t unused4[12];
  99. union
  100. {
  101. struct
  102. {
  103. struct grub_bfs_extent direct[12];
  104. grub_uint64_t max_direct_range;
  105. struct grub_bfs_extent indirect;
  106. grub_uint64_t max_indirect_range;
  107. struct grub_bfs_extent double_indirect;
  108. grub_uint64_t max_double_indirect_range;
  109. grub_uint64_t size;
  110. grub_uint32_t pad[4];
  111. } GRUB_PACKED;
  112. char inplace_link[144];
  113. } GRUB_PACKED;
  114. grub_uint8_t small_data[0];
  115. } GRUB_PACKED;
  116. enum
  117. {
  118. LONG_SYMLINK = 0x40
  119. };
  120. struct grub_bfs_small_data_element_header
  121. {
  122. grub_uint32_t type;
  123. grub_uint16_t name_len;
  124. grub_uint16_t value_len;
  125. } GRUB_PACKED;
  126. struct grub_bfs_btree_header
  127. {
  128. grub_uint32_t magic;
  129. #ifdef MODE_AFS
  130. grub_uint64_t root;
  131. grub_uint32_t level;
  132. grub_uint32_t node_size;
  133. grub_uint32_t unused;
  134. #else
  135. grub_uint32_t node_size;
  136. grub_uint32_t level;
  137. grub_uint32_t unused;
  138. grub_uint64_t root;
  139. #endif
  140. grub_uint32_t unused2[2];
  141. } GRUB_PACKED;
  142. struct grub_bfs_btree_node
  143. {
  144. grub_uint64_t unused;
  145. grub_uint64_t right;
  146. grub_uint64_t overflow;
  147. #ifdef MODE_AFS
  148. grub_uint32_t count_keys;
  149. grub_uint32_t total_key_len;
  150. #else
  151. grub_uint16_t count_keys;
  152. grub_uint16_t total_key_len;
  153. #endif
  154. } GRUB_PACKED;
  155. struct grub_bfs_data
  156. {
  157. struct grub_bfs_superblock sb;
  158. struct grub_bfs_inode ino;
  159. };
  160. /* Context for grub_bfs_dir. */
  161. struct grub_bfs_dir_ctx
  162. {
  163. grub_device_t device;
  164. grub_fs_dir_hook_t hook;
  165. void *hook_data;
  166. struct grub_bfs_superblock sb;
  167. };
  168. static grub_err_t
  169. read_extent (grub_disk_t disk,
  170. const struct grub_bfs_superblock *sb,
  171. const struct grub_bfs_extent *in,
  172. grub_off_t off, grub_off_t byteoff, void *buf, grub_size_t len)
  173. {
  174. #ifdef MODE_AFS
  175. return grub_disk_read (disk, ((grub_bfs_to_cpu32 (in->ag)
  176. << (grub_bfs_to_cpu32 (sb->log2_ag_size)
  177. - GRUB_DISK_SECTOR_BITS))
  178. + ((grub_bfs_to_cpu16 (in->start) + off)
  179. << (grub_bfs_to_cpu32 (sb->log2_bsize)
  180. - GRUB_DISK_SECTOR_BITS))),
  181. byteoff, len, buf);
  182. #else
  183. return grub_disk_read (disk, (((grub_bfs_to_cpu32 (in->ag)
  184. << grub_bfs_to_cpu32 (sb->log2_ag_size))
  185. + grub_bfs_to_cpu16 (in->start) + off)
  186. << (grub_bfs_to_cpu32 (sb->log2_bsize)
  187. - GRUB_DISK_SECTOR_BITS)),
  188. byteoff, len, buf);
  189. #endif
  190. }
  191. #ifdef MODE_AFS
  192. #define RANGE_SHIFT grub_bfs_to_cpu32 (sb->log2_bsize)
  193. #else
  194. #define RANGE_SHIFT 0
  195. #endif
  196. static grub_err_t
  197. read_bfs_file (grub_disk_t disk,
  198. const struct grub_bfs_superblock *sb,
  199. const struct grub_bfs_inode *ino,
  200. grub_off_t off, void *buf, grub_size_t len,
  201. grub_disk_read_hook_t read_hook, void *read_hook_data)
  202. {
  203. if (len == 0)
  204. return GRUB_ERR_NONE;
  205. if (off + len > grub_bfs_to_cpu64 (ino->size))
  206. return grub_error (GRUB_ERR_OUT_OF_RANGE,
  207. N_("attempt to read past the end of file"));
  208. if (off < (grub_bfs_to_cpu64 (ino->max_direct_range) << RANGE_SHIFT))
  209. {
  210. unsigned i;
  211. grub_uint64_t pos = 0;
  212. for (i = 0; i < ARRAY_SIZE (ino->direct); i++)
  213. {
  214. grub_uint64_t newpos;
  215. newpos = pos + (((grub_uint64_t) grub_bfs_to_cpu16 (ino->direct[i].len))
  216. << grub_bfs_to_cpu32 (sb->log2_bsize));
  217. if (newpos > off)
  218. {
  219. grub_size_t read_size;
  220. grub_err_t err;
  221. read_size = newpos - off;
  222. if (read_size > len)
  223. read_size = len;
  224. disk->read_hook = read_hook;
  225. disk->read_hook_data = read_hook_data;
  226. err = read_extent (disk, sb, &ino->direct[i], 0, off - pos,
  227. buf, read_size);
  228. disk->read_hook = 0;
  229. if (err)
  230. return err;
  231. off += read_size;
  232. len -= read_size;
  233. buf = (char *) buf + read_size;
  234. if (len == 0)
  235. return GRUB_ERR_NONE;
  236. }
  237. pos = newpos;
  238. }
  239. }
  240. if (off < (grub_bfs_to_cpu64 (ino->max_direct_range) << RANGE_SHIFT))
  241. return grub_error (GRUB_ERR_BAD_FS, "incorrect direct blocks");
  242. if (off < (grub_bfs_to_cpu64 (ino->max_indirect_range) << RANGE_SHIFT))
  243. {
  244. unsigned i;
  245. struct grub_bfs_extent *entries;
  246. grub_size_t nentries;
  247. grub_err_t err;
  248. grub_uint64_t pos = (grub_bfs_to_cpu64 (ino->max_direct_range)
  249. << RANGE_SHIFT);
  250. nentries = (((grub_size_t) grub_bfs_to_cpu16 (ino->indirect.len))
  251. << (grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE));
  252. entries = grub_malloc (nentries << LOG_EXTENT_SIZE);
  253. if (!entries)
  254. return grub_errno;
  255. err = read_extent (disk, sb, &ino->indirect, 0, 0,
  256. entries, nentries << LOG_EXTENT_SIZE);
  257. for (i = 0; i < nentries; i++)
  258. {
  259. grub_uint64_t newpos;
  260. newpos = pos + (((grub_uint64_t) grub_bfs_to_cpu16 (entries[i].len))
  261. << grub_bfs_to_cpu32 (sb->log2_bsize));
  262. if (newpos > off)
  263. {
  264. grub_size_t read_size;
  265. read_size = newpos - off;
  266. if (read_size > len)
  267. read_size = len;
  268. disk->read_hook = read_hook;
  269. disk->read_hook_data = read_hook_data;
  270. err = read_extent (disk, sb, &entries[i], 0, off - pos,
  271. buf, read_size);
  272. disk->read_hook = 0;
  273. if (err)
  274. {
  275. grub_free (entries);
  276. return err;
  277. }
  278. off += read_size;
  279. len -= read_size;
  280. buf = (char *) buf + read_size;
  281. if (len == 0)
  282. {
  283. grub_free (entries);
  284. return GRUB_ERR_NONE;
  285. }
  286. }
  287. pos = newpos;
  288. }
  289. grub_free (entries);
  290. }
  291. if (off < (grub_bfs_to_cpu64 (ino->max_indirect_range) << RANGE_SHIFT))
  292. return grub_error (GRUB_ERR_BAD_FS, "incorrect indirect blocks");
  293. {
  294. struct grub_bfs_extent *l1_entries, *l2_entries;
  295. grub_size_t nl1_entries, nl2_entries;
  296. grub_off_t last_l1n = ~0ULL;
  297. grub_err_t err;
  298. nl1_entries = (((grub_uint64_t) grub_bfs_to_cpu16 (ino->double_indirect.len))
  299. << (grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE));
  300. l1_entries = grub_malloc (nl1_entries << LOG_EXTENT_SIZE);
  301. if (!l1_entries)
  302. return grub_errno;
  303. nl2_entries = 0;
  304. l2_entries = grub_malloc (1 << (DOUBLE_INDIRECT_SHIFT
  305. + grub_bfs_to_cpu32 (sb->log2_bsize)));
  306. if (!l2_entries)
  307. {
  308. grub_free (l1_entries);
  309. return grub_errno;
  310. }
  311. err = read_extent (disk, sb, &ino->double_indirect, 0, 0,
  312. l1_entries, nl1_entries << LOG_EXTENT_SIZE);
  313. if (err)
  314. {
  315. grub_free (l1_entries);
  316. grub_free (l2_entries);
  317. return err;
  318. }
  319. while (len > 0)
  320. {
  321. grub_off_t boff, l2n, l1n;
  322. grub_size_t read_size;
  323. grub_off_t double_indirect_offset;
  324. double_indirect_offset = off
  325. - grub_bfs_to_cpu64 (ino->max_indirect_range);
  326. boff = (double_indirect_offset
  327. & ((1 << (grub_bfs_to_cpu32 (sb->log2_bsize)
  328. + DOUBLE_INDIRECT_SHIFT)) - 1));
  329. l2n = ((double_indirect_offset >> (grub_bfs_to_cpu32 (sb->log2_bsize)
  330. + DOUBLE_INDIRECT_SHIFT))
  331. & ((1 << (grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE
  332. + DOUBLE_INDIRECT_SHIFT)) - 1));
  333. l1n =
  334. (double_indirect_offset >>
  335. (2 * grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE +
  336. 2 * DOUBLE_INDIRECT_SHIFT));
  337. if (l1n > nl1_entries)
  338. {
  339. grub_free (l1_entries);
  340. grub_free (l2_entries);
  341. return grub_error (GRUB_ERR_BAD_FS,
  342. "incorrect double-indirect block");
  343. }
  344. if (l1n != last_l1n)
  345. {
  346. nl2_entries = (((grub_uint64_t) grub_bfs_to_cpu16 (l1_entries[l1n].len))
  347. << (grub_bfs_to_cpu32 (sb->log2_bsize)
  348. - LOG_EXTENT_SIZE));
  349. if (nl2_entries > (1U << (grub_bfs_to_cpu32 (sb->log2_bsize)
  350. - LOG_EXTENT_SIZE
  351. + DOUBLE_INDIRECT_SHIFT)))
  352. nl2_entries = (1 << (grub_bfs_to_cpu32 (sb->log2_bsize)
  353. - LOG_EXTENT_SIZE
  354. + DOUBLE_INDIRECT_SHIFT));
  355. err = read_extent (disk, sb, &l1_entries[l1n], 0, 0,
  356. l2_entries, nl2_entries << LOG_EXTENT_SIZE);
  357. if (err)
  358. {
  359. grub_free (l1_entries);
  360. grub_free (l2_entries);
  361. return err;
  362. }
  363. last_l1n = l1n;
  364. }
  365. if (l2n > nl2_entries)
  366. {
  367. grub_free (l1_entries);
  368. grub_free (l2_entries);
  369. return grub_error (GRUB_ERR_BAD_FS,
  370. "incorrect double-indirect block");
  371. }
  372. read_size = (1 << (grub_bfs_to_cpu32 (sb->log2_bsize)
  373. + DOUBLE_INDIRECT_SHIFT)) - boff;
  374. if (read_size > len)
  375. read_size = len;
  376. disk->read_hook = read_hook;
  377. disk->read_hook_data = read_hook_data;
  378. err = read_extent (disk, sb, &l2_entries[l2n], 0, boff,
  379. buf, read_size);
  380. disk->read_hook = 0;
  381. if (err)
  382. {
  383. grub_free (l1_entries);
  384. grub_free (l2_entries);
  385. return err;
  386. }
  387. off += read_size;
  388. len -= read_size;
  389. buf = (char *) buf + read_size;
  390. }
  391. grub_free (l1_entries);
  392. grub_free (l2_entries);
  393. return GRUB_ERR_NONE;
  394. }
  395. }
  396. static grub_err_t
  397. read_b_node (grub_disk_t disk,
  398. const struct grub_bfs_superblock *sb,
  399. const struct grub_bfs_inode *ino,
  400. grub_uint64_t node_off,
  401. struct grub_bfs_btree_node **node,
  402. char **key_data, grub_uint16_t **keylen_idx,
  403. grub_unaligned_uint64_t **key_values)
  404. {
  405. void *ret;
  406. struct grub_bfs_btree_node node_head;
  407. grub_size_t total_size;
  408. grub_err_t err;
  409. *node = NULL;
  410. *key_data = NULL;
  411. *keylen_idx = NULL;
  412. *key_values = NULL;
  413. err = read_bfs_file (disk, sb, ino, node_off, &node_head, sizeof (node_head),
  414. 0, 0);
  415. if (err)
  416. return err;
  417. total_size = ALIGN_UP (sizeof (node_head) +
  418. grub_bfs_to_cpu_treehead
  419. (node_head.total_key_len),
  420. BTREE_ALIGN) +
  421. grub_bfs_to_cpu_treehead (node_head.count_keys) *
  422. sizeof (grub_uint16_t)
  423. + grub_bfs_to_cpu_treehead (node_head.count_keys) *
  424. sizeof (grub_uint64_t);
  425. ret = grub_malloc (total_size);
  426. if (!ret)
  427. return grub_errno;
  428. err = read_bfs_file (disk, sb, ino, node_off, ret, total_size, 0, 0);
  429. if (err)
  430. {
  431. grub_free (ret);
  432. return err;
  433. }
  434. *node = ret;
  435. *key_data = (char *) ret + sizeof (node_head);
  436. *keylen_idx = (grub_uint16_t *) ret
  437. + ALIGN_UP (sizeof (node_head) +
  438. grub_bfs_to_cpu_treehead (node_head.total_key_len),
  439. BTREE_ALIGN) / 2;
  440. *key_values = (grub_unaligned_uint64_t *)
  441. (*keylen_idx +
  442. grub_bfs_to_cpu_treehead (node_head.count_keys));
  443. return GRUB_ERR_NONE;
  444. }
  445. static int
  446. iterate_in_b_tree (grub_disk_t disk,
  447. const struct grub_bfs_superblock *sb,
  448. const struct grub_bfs_inode *ino,
  449. int (*hook) (const char *name, grub_uint64_t value,
  450. struct grub_bfs_dir_ctx *ctx),
  451. struct grub_bfs_dir_ctx *ctx)
  452. {
  453. struct grub_bfs_btree_header head;
  454. grub_err_t err;
  455. int level;
  456. grub_uint64_t node_off;
  457. err = read_bfs_file (disk, sb, ino, 0, &head, sizeof (head), 0, 0);
  458. if (err)
  459. return 0;
  460. node_off = grub_bfs_to_cpu64 (head.root);
  461. level = grub_bfs_to_cpu32 (head.level) - 1;
  462. while (level--)
  463. {
  464. struct grub_bfs_btree_node node;
  465. grub_uint64_t key_value;
  466. err = read_bfs_file (disk, sb, ino, node_off, &node, sizeof (node),
  467. 0, 0);
  468. if (err)
  469. return 0;
  470. err = read_bfs_file (disk, sb, ino, node_off
  471. + ALIGN_UP (sizeof (node) +
  472. grub_bfs_to_cpu_treehead (node.
  473. total_key_len),
  474. BTREE_ALIGN) +
  475. grub_bfs_to_cpu_treehead (node.count_keys) *
  476. sizeof (grub_uint16_t), &key_value,
  477. sizeof (grub_uint64_t), 0, 0);
  478. if (err)
  479. return 0;
  480. node_off = grub_bfs_to_cpu64 (key_value);
  481. }
  482. while (1)
  483. {
  484. struct grub_bfs_btree_node *node;
  485. char *key_data;
  486. grub_uint16_t *keylen_idx;
  487. grub_unaligned_uint64_t *key_values;
  488. unsigned i;
  489. grub_uint16_t start = 0, end = 0;
  490. err = read_b_node (disk, sb, ino,
  491. node_off,
  492. &node,
  493. &key_data,
  494. &keylen_idx,
  495. &key_values);
  496. if (err)
  497. return 0;
  498. for (i = 0; i < grub_bfs_to_cpu_treehead (node->count_keys); i++)
  499. {
  500. char c;
  501. start = end;
  502. end = grub_bfs_to_cpu16 (keylen_idx[i]);
  503. if (grub_bfs_to_cpu_treehead (node->total_key_len) <= end)
  504. end = grub_bfs_to_cpu_treehead (node->total_key_len);
  505. c = key_data[end];
  506. key_data[end] = 0;
  507. if (hook (key_data + start, grub_bfs_to_cpu64 (key_values[i].val),
  508. ctx))
  509. {
  510. grub_free (node);
  511. return 1;
  512. }
  513. key_data[end] = c;
  514. }
  515. node_off = grub_bfs_to_cpu64 (node->right);
  516. grub_free (node);
  517. if (node_off == POINTER_INVALID)
  518. return 0;
  519. }
  520. }
  521. static int
  522. bfs_strcmp (const char *a, const char *b, grub_size_t alen)
  523. {
  524. char ac, bc;
  525. while (*b && alen)
  526. {
  527. if (*a != *b)
  528. break;
  529. a++;
  530. b++;
  531. alen--;
  532. }
  533. ac = alen ? *a : 0;
  534. bc = *b;
  535. #ifdef MODE_AFS
  536. return (int) (grub_int8_t) ac - (int) (grub_int8_t) bc;
  537. #else
  538. return (int) (grub_uint8_t) ac - (int) (grub_uint8_t) bc;
  539. #endif
  540. }
  541. static grub_err_t
  542. find_in_b_tree (grub_disk_t disk,
  543. const struct grub_bfs_superblock *sb,
  544. const struct grub_bfs_inode *ino, const char *name,
  545. grub_uint64_t * res)
  546. {
  547. struct grub_bfs_btree_header head;
  548. grub_err_t err;
  549. int level;
  550. grub_uint64_t node_off;
  551. err = read_bfs_file (disk, sb, ino, 0, &head, sizeof (head), 0, 0);
  552. if (err)
  553. return err;
  554. node_off = grub_bfs_to_cpu64 (head.root);
  555. level = grub_bfs_to_cpu32 (head.level) - 1;
  556. while (1)
  557. {
  558. struct grub_bfs_btree_node *node;
  559. char *key_data;
  560. grub_uint16_t *keylen_idx;
  561. grub_unaligned_uint64_t *key_values;
  562. int lg, j;
  563. unsigned i;
  564. err = read_b_node (disk, sb, ino, node_off, &node, &key_data, &keylen_idx, &key_values);
  565. if (err)
  566. return err;
  567. if (node->count_keys == 0)
  568. {
  569. grub_free (node);
  570. return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"),
  571. name);
  572. }
  573. for (lg = 0; grub_bfs_to_cpu_treehead (node->count_keys) >> lg; lg++);
  574. i = 0;
  575. for (j = lg - 1; j >= 0; j--)
  576. {
  577. int cmp;
  578. grub_uint16_t start = 0, end = 0;
  579. if ((i | (1 << j)) >= grub_bfs_to_cpu_treehead (node->count_keys))
  580. continue;
  581. start = grub_bfs_to_cpu16 (keylen_idx[(i | (1 << j)) - 1]);
  582. end = grub_bfs_to_cpu16 (keylen_idx[(i | (1 << j))]);
  583. if (grub_bfs_to_cpu_treehead (node->total_key_len) <= end)
  584. end = grub_bfs_to_cpu_treehead (node->total_key_len);
  585. cmp = bfs_strcmp (key_data + start, name, end - start);
  586. if (cmp == 0 && level == 0)
  587. {
  588. *res = grub_bfs_to_cpu64 (key_values[i | (1 << j)].val);
  589. grub_free (node);
  590. return GRUB_ERR_NONE;
  591. }
  592. #ifdef MODE_AFS
  593. if (cmp <= 0)
  594. #else
  595. if (cmp < 0)
  596. #endif
  597. i |= (1 << j);
  598. }
  599. if (i == 0)
  600. {
  601. grub_uint16_t end = 0;
  602. int cmp;
  603. end = grub_bfs_to_cpu16 (keylen_idx[0]);
  604. if (grub_bfs_to_cpu_treehead (node->total_key_len) <= end)
  605. end = grub_bfs_to_cpu_treehead (node->total_key_len);
  606. cmp = bfs_strcmp (key_data, name, end);
  607. if (cmp == 0 && level == 0)
  608. {
  609. *res = grub_bfs_to_cpu64 (key_values[0].val);
  610. grub_free (node);
  611. return GRUB_ERR_NONE;
  612. }
  613. #ifdef MODE_AFS
  614. if (cmp > 0 && level != 0)
  615. #else
  616. if (cmp >= 0 && level != 0)
  617. #endif
  618. {
  619. node_off = grub_bfs_to_cpu64 (key_values[0].val);
  620. level--;
  621. grub_free (node);
  622. continue;
  623. }
  624. else if (level != 0
  625. && grub_bfs_to_cpu_treehead (node->count_keys) >= 2)
  626. {
  627. node_off = grub_bfs_to_cpu64 (key_values[1].val);
  628. level--;
  629. grub_free (node);
  630. continue;
  631. }
  632. }
  633. else if (level != 0
  634. && i + 1 < grub_bfs_to_cpu_treehead (node->count_keys))
  635. {
  636. node_off = grub_bfs_to_cpu64 (key_values[i + 1].val);
  637. level--;
  638. grub_free (node);
  639. continue;
  640. }
  641. if (node->overflow != POINTER_INVALID)
  642. {
  643. node_off = grub_bfs_to_cpu64 (node->overflow);
  644. /* This level-- isn't specified but is needed. */
  645. level--;
  646. grub_free (node);
  647. continue;
  648. }
  649. grub_free (node);
  650. return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"),
  651. name);
  652. }
  653. }
  654. struct grub_fshelp_node
  655. {
  656. grub_disk_t disk;
  657. const struct grub_bfs_superblock *sb;
  658. struct grub_bfs_inode ino;
  659. };
  660. static grub_err_t
  661. lookup_file (grub_fshelp_node_t dir,
  662. const char *name,
  663. grub_fshelp_node_t *foundnode,
  664. enum grub_fshelp_filetype *foundtype)
  665. {
  666. grub_err_t err;
  667. struct grub_bfs_inode *new_ino;
  668. grub_uint64_t res = 0;
  669. err = find_in_b_tree (dir->disk, dir->sb, &dir->ino, name, &res);
  670. if (err)
  671. return err;
  672. *foundnode = grub_malloc (sizeof (struct grub_fshelp_node));
  673. if (!*foundnode)
  674. return grub_errno;
  675. (*foundnode)->disk = dir->disk;
  676. (*foundnode)->sb = dir->sb;
  677. new_ino = &(*foundnode)->ino;
  678. if (grub_disk_read (dir->disk, res
  679. << (grub_bfs_to_cpu32 (dir->sb->log2_bsize)
  680. - GRUB_DISK_SECTOR_BITS), 0,
  681. sizeof (*new_ino), (char *) new_ino))
  682. {
  683. grub_free (*foundnode);
  684. return grub_errno;
  685. }
  686. switch (grub_bfs_to_cpu32 (new_ino->mode) & ATTR_TYPE)
  687. {
  688. default:
  689. case ATTR_REG:
  690. *foundtype = GRUB_FSHELP_REG;
  691. break;
  692. case ATTR_DIR:
  693. *foundtype = GRUB_FSHELP_DIR;
  694. break;
  695. case ATTR_LNK:
  696. *foundtype = GRUB_FSHELP_SYMLINK;
  697. break;
  698. }
  699. return GRUB_ERR_NONE;
  700. }
  701. static char *
  702. read_symlink (grub_fshelp_node_t node)
  703. {
  704. char *alloc = NULL;
  705. grub_err_t err;
  706. #ifndef MODE_AFS
  707. if (!(grub_bfs_to_cpu32 (node->ino.flags) & LONG_SYMLINK))
  708. {
  709. alloc = grub_malloc (sizeof (node->ino.inplace_link) + 1);
  710. if (!alloc)
  711. {
  712. return NULL;
  713. }
  714. grub_memcpy (alloc, node->ino.inplace_link,
  715. sizeof (node->ino.inplace_link));
  716. alloc[sizeof (node->ino.inplace_link)] = 0;
  717. }
  718. else
  719. #endif
  720. {
  721. grub_size_t symsize = grub_bfs_to_cpu64 (node->ino.size);
  722. alloc = grub_malloc (symsize + 1);
  723. if (!alloc)
  724. return NULL;
  725. err = read_bfs_file (node->disk, node->sb, &node->ino, 0, alloc, symsize, 0, 0);
  726. if (err)
  727. {
  728. grub_free (alloc);
  729. return NULL;
  730. }
  731. alloc[symsize] = 0;
  732. }
  733. return alloc;
  734. }
  735. static grub_err_t
  736. find_file (const char *path, grub_disk_t disk,
  737. const struct grub_bfs_superblock *sb, struct grub_bfs_inode *ino,
  738. enum grub_fshelp_filetype exptype)
  739. {
  740. grub_err_t err;
  741. struct grub_fshelp_node root = {
  742. .disk = disk,
  743. .sb = sb,
  744. };
  745. struct grub_fshelp_node *found = NULL;
  746. err = read_extent (disk, sb, &sb->root_dir, 0, 0, &root.ino,
  747. sizeof (root.ino));
  748. if (err)
  749. return err;
  750. err = grub_fshelp_find_file_lookup (path, &root, &found, lookup_file, read_symlink, exptype);
  751. if (!err)
  752. grub_memcpy (ino, &found->ino, sizeof (*ino));
  753. if (&root != found)
  754. grub_free (found);
  755. return err;
  756. }
  757. static grub_err_t
  758. mount (grub_disk_t disk, struct grub_bfs_superblock *sb)
  759. {
  760. grub_err_t err;
  761. err = grub_disk_read (disk, SUPERBLOCK, 0, sizeof (*sb), sb);
  762. if (err == GRUB_ERR_OUT_OF_RANGE)
  763. return grub_error (GRUB_ERR_BAD_FS,
  764. #ifdef MODE_AFS
  765. "not an AFS filesystem"
  766. #else
  767. "not a BFS filesystem"
  768. #endif
  769. );
  770. if (err)
  771. return err;
  772. if (sb->magic1 != grub_cpu_to_bfs32_compile_time (SUPER_BLOCK_MAGIC1)
  773. || sb->magic2 != grub_cpu_to_bfs32_compile_time (SUPER_BLOCK_MAGIC2)
  774. || sb->magic3 != grub_cpu_to_bfs32_compile_time (SUPER_BLOCK_MAGIC3)
  775. || sb->bsize == 0
  776. || (grub_bfs_to_cpu32 (sb->bsize)
  777. != (1U << grub_bfs_to_cpu32 (sb->log2_bsize)))
  778. || grub_bfs_to_cpu32 (sb->log2_bsize) < GRUB_DISK_SECTOR_BITS)
  779. return grub_error (GRUB_ERR_BAD_FS,
  780. #ifdef MODE_AFS
  781. "not an AFS filesystem"
  782. #else
  783. "not a BFS filesystem"
  784. #endif
  785. );
  786. return GRUB_ERR_NONE;
  787. }
  788. /* Helper for grub_bfs_dir. */
  789. static int
  790. grub_bfs_dir_iter (const char *name, grub_uint64_t value,
  791. struct grub_bfs_dir_ctx *ctx)
  792. {
  793. grub_err_t err2;
  794. struct grub_bfs_inode ino;
  795. struct grub_dirhook_info info;
  796. err2 = grub_disk_read (ctx->device->disk, value
  797. << (grub_bfs_to_cpu32 (ctx->sb.log2_bsize)
  798. - GRUB_DISK_SECTOR_BITS), 0,
  799. sizeof (ino), (char *) &ino);
  800. if (err2)
  801. {
  802. grub_print_error ();
  803. return 0;
  804. }
  805. info.mtimeset = 1;
  806. #ifdef MODE_AFS
  807. info.mtime =
  808. grub_divmod64 (grub_bfs_to_cpu64 (ino.mtime), 1000000, 0);
  809. #else
  810. info.mtime = grub_bfs_to_cpu64 (ino.mtime) >> 16;
  811. #endif
  812. info.dir = ((grub_bfs_to_cpu32 (ino.mode) & ATTR_TYPE) == ATTR_DIR);
  813. return ctx->hook (name, &info, ctx->hook_data);
  814. }
  815. static grub_err_t
  816. grub_bfs_dir (grub_device_t device, const char *path,
  817. grub_fs_dir_hook_t hook, void *hook_data)
  818. {
  819. struct grub_bfs_dir_ctx ctx = {
  820. .device = device,
  821. .hook = hook,
  822. .hook_data = hook_data
  823. };
  824. grub_err_t err;
  825. err = mount (device->disk, &ctx.sb);
  826. if (err)
  827. return err;
  828. {
  829. struct grub_bfs_inode ino;
  830. err = find_file (path, device->disk, &ctx.sb, &ino, GRUB_FSHELP_DIR);
  831. if (err)
  832. return err;
  833. iterate_in_b_tree (device->disk, &ctx.sb, &ino, grub_bfs_dir_iter,
  834. &ctx);
  835. }
  836. return grub_errno;
  837. }
  838. static grub_err_t
  839. grub_bfs_open (struct grub_file *file, const char *name)
  840. {
  841. struct grub_bfs_superblock sb;
  842. grub_err_t err;
  843. err = mount (file->device->disk, &sb);
  844. if (err)
  845. return err;
  846. {
  847. struct grub_bfs_inode ino;
  848. struct grub_bfs_data *data;
  849. err = find_file (name, file->device->disk, &sb, &ino, GRUB_FSHELP_REG);
  850. if (err)
  851. return err;
  852. data = grub_zalloc (sizeof (struct grub_bfs_data));
  853. if (!data)
  854. return grub_errno;
  855. data->sb = sb;
  856. grub_memcpy (&data->ino, &ino, sizeof (data->ino));
  857. file->data = data;
  858. file->size = grub_bfs_to_cpu64 (ino.size);
  859. }
  860. return GRUB_ERR_NONE;
  861. }
  862. static grub_err_t
  863. grub_bfs_close (grub_file_t file)
  864. {
  865. grub_free (file->data);
  866. return GRUB_ERR_NONE;
  867. }
  868. static grub_ssize_t
  869. grub_bfs_read (grub_file_t file, char *buf, grub_size_t len)
  870. {
  871. grub_err_t err;
  872. struct grub_bfs_data *data = file->data;
  873. err = read_bfs_file (file->device->disk, &data->sb,
  874. &data->ino, file->offset, buf, len,
  875. file->read_hook, file->read_hook_data);
  876. if (err)
  877. return -1;
  878. return len;
  879. }
  880. static grub_err_t
  881. grub_bfs_label (grub_device_t device, char **label)
  882. {
  883. struct grub_bfs_superblock sb;
  884. grub_err_t err;
  885. *label = 0;
  886. err = mount (device->disk, &sb);
  887. if (err)
  888. return err;
  889. *label = grub_strndup (sb.label, sizeof (sb.label));
  890. return GRUB_ERR_NONE;
  891. }
  892. #ifndef MODE_AFS
  893. static grub_ssize_t
  894. read_bfs_attr (grub_disk_t disk,
  895. const struct grub_bfs_superblock *sb,
  896. struct grub_bfs_inode *ino,
  897. const char *name, void *buf, grub_size_t len)
  898. {
  899. grub_uint8_t *ptr = (grub_uint8_t *) ino->small_data;
  900. grub_uint8_t *end = ((grub_uint8_t *) ino + grub_bfs_to_cpu32 (sb->bsize));
  901. while (ptr + sizeof (struct grub_bfs_small_data_element_header) < end)
  902. {
  903. struct grub_bfs_small_data_element_header *el;
  904. char *el_name;
  905. grub_uint8_t *data;
  906. el = (struct grub_bfs_small_data_element_header *) ptr;
  907. if (el->name_len == 0)
  908. break;
  909. el_name = (char *) (el + 1);
  910. data = (grub_uint8_t *) el_name + grub_bfs_to_cpu16 (el->name_len) + 3;
  911. ptr = data + grub_bfs_to_cpu16 (el->value_len) + 1;
  912. if (grub_memcmp (name, el_name, grub_bfs_to_cpu16 (el->name_len)) == 0
  913. && name[el->name_len] == 0)
  914. {
  915. grub_size_t copy;
  916. copy = len;
  917. if (grub_bfs_to_cpu16 (el->value_len) > copy)
  918. copy = grub_bfs_to_cpu16 (el->value_len);
  919. grub_memcpy (buf, data, copy);
  920. return copy;
  921. }
  922. }
  923. if (ino->attr.len != 0)
  924. {
  925. grub_size_t read;
  926. grub_err_t err;
  927. grub_uint64_t res;
  928. err = read_extent (disk, sb, &ino->attr, 0, 0, ino,
  929. grub_bfs_to_cpu32 (sb->bsize));
  930. if (err)
  931. return -1;
  932. err = find_in_b_tree (disk, sb, ino, name, &res);
  933. if (err)
  934. return -1;
  935. grub_disk_read (disk, res
  936. << (grub_bfs_to_cpu32 (sb->log2_bsize)
  937. - GRUB_DISK_SECTOR_BITS), 0,
  938. grub_bfs_to_cpu32 (sb->bsize), (char *) ino);
  939. read = grub_bfs_to_cpu64 (ino->size);
  940. if (read > len)
  941. read = len;
  942. err = read_bfs_file (disk, sb, ino, 0, buf, read, 0, 0);
  943. if (err)
  944. return -1;
  945. return read;
  946. }
  947. return -1;
  948. }
  949. static grub_err_t
  950. grub_bfs_uuid (grub_device_t device, char **uuid)
  951. {
  952. struct grub_bfs_superblock sb;
  953. grub_err_t err;
  954. struct grub_bfs_inode *ino;
  955. grub_uint64_t vid;
  956. *uuid = 0;
  957. err = mount (device->disk, &sb);
  958. if (err)
  959. return err;
  960. ino = grub_malloc (grub_bfs_to_cpu32 (sb.bsize));
  961. if (!ino)
  962. return grub_errno;
  963. err = read_extent (device->disk, &sb, &sb.root_dir, 0, 0,
  964. ino, grub_bfs_to_cpu32 (sb.bsize));
  965. if (err)
  966. {
  967. grub_free (ino);
  968. return err;
  969. }
  970. if (read_bfs_attr (device->disk, &sb, ino, "be:volume_id",
  971. &vid, sizeof (vid)) == sizeof (vid))
  972. *uuid =
  973. grub_xasprintf ("%016" PRIxGRUB_UINT64_T, grub_bfs_to_cpu64 (vid));
  974. grub_free (ino);
  975. return GRUB_ERR_NONE;
  976. }
  977. #endif
  978. static struct grub_fs grub_bfs_fs = {
  979. #ifdef MODE_AFS
  980. .name = "afs",
  981. #else
  982. .name = "bfs",
  983. #endif
  984. .fs_dir = grub_bfs_dir,
  985. .fs_open = grub_bfs_open,
  986. .fs_read = grub_bfs_read,
  987. .fs_close = grub_bfs_close,
  988. .fs_label = grub_bfs_label,
  989. #ifndef MODE_AFS
  990. .fs_uuid = grub_bfs_uuid,
  991. #endif
  992. #ifdef GRUB_UTIL
  993. .reserved_first_sector = 1,
  994. .blocklist_install = 1,
  995. #endif
  996. };
  997. #ifdef MODE_AFS
  998. GRUB_MOD_INIT (afs)
  999. #else
  1000. GRUB_MOD_INIT (bfs)
  1001. #endif
  1002. {
  1003. COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE ==
  1004. sizeof (struct grub_bfs_extent));
  1005. if (!grub_is_lockdown ())
  1006. {
  1007. grub_bfs_fs.mod = mod;
  1008. grub_fs_register (&grub_bfs_fs);
  1009. }
  1010. }
  1011. #ifdef MODE_AFS
  1012. GRUB_MOD_FINI (afs)
  1013. #else
  1014. GRUB_MOD_FINI (bfs)
  1015. #endif
  1016. {
  1017. if (!grub_is_lockdown ())
  1018. grub_fs_unregister (&grub_bfs_fs);
  1019. }