bfs.c 27 KB

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