afs.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. /* afs.c - The native AtheOS file-system. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 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. #include <grub/err.h>
  20. #include <grub/file.h>
  21. #include <grub/mm.h>
  22. #include <grub/misc.h>
  23. #include <grub/disk.h>
  24. #include <grub/dl.h>
  25. #include <grub/types.h>
  26. #include <grub/fshelp.h>
  27. #ifdef MODE_BIGENDIAN
  28. #define GRUB_AFS_FSNAME_SUFFIX "_be"
  29. #else
  30. #define GRUB_AFS_FSNAME_SUFFIX ""
  31. #endif
  32. #ifdef MODE_BFS
  33. #define GRUB_AFS_FSNAME "befs" GRUB_AFS_FSNAME_SUFFIX
  34. #else
  35. #define GRUB_AFS_FSNAME "afs" GRUB_AFS_FSNAME_SUFFIX
  36. #endif
  37. #define GRUB_AFS_DIRECT_BLOCK_COUNT 12
  38. #define GRUB_AFS_BLOCKS_PER_DI_RUN 4
  39. #ifdef MODE_BFS
  40. #define GRUB_AFS_SBLOCK_SECTOR 1
  41. #define GRUB_AFS_SBLOCK_MAGIC1 0x42465331 /* BFS1. */
  42. #else
  43. #define GRUB_AFS_SBLOCK_SECTOR 2
  44. #define GRUB_AFS_SBLOCK_MAGIC1 0x41465331 /* AFS1. */
  45. #endif
  46. #define GRUB_AFS_SBLOCK_MAGIC2 0xdd121031
  47. #define GRUB_AFS_SBLOCK_MAGIC3 0x15b6830e
  48. #define GRUB_AFS_INODE_MAGIC 0x64358428
  49. #ifdef MODE_BFS
  50. #define GRUB_AFS_BTREE_MAGIC 0x69f6c2e8
  51. #else
  52. #define GRUB_AFS_BTREE_MAGIC 0x65768995
  53. #endif
  54. #define GRUB_AFS_BNODE_SIZE 1024
  55. #define GRUB_AFS_S_IFMT 00170000
  56. #define GRUB_AFS_S_IFLNK 0120000
  57. #define GRUB_AFS_S_IFREG 0100000
  58. #define GRUB_AFS_S_IFDIR 0040000
  59. #define GRUB_AFS_S_IFIFO 0010000
  60. #define GRUB_AFS_NULL_VAL ((grub_afs_bvalue_t)-1)
  61. #ifdef MODE_BIGENDIAN
  62. #define grub_afs_to_cpu16(x) grub_be_to_cpu16 (x)
  63. #define grub_afs_to_cpu32(x) grub_be_to_cpu32 (x)
  64. #define grub_afs_to_cpu64(x) grub_be_to_cpu64 (x)
  65. #else
  66. #define grub_afs_to_cpu16(x) grub_le_to_cpu16 (x)
  67. #define grub_afs_to_cpu32(x) grub_le_to_cpu32 (x)
  68. #define grub_afs_to_cpu64(x) grub_le_to_cpu64 (x)
  69. #endif
  70. #ifdef MODE_BFS
  71. #define B_KEY_INDEX_ALIGN 8
  72. #else
  73. #define B_KEY_INDEX_ALIGN 4
  74. #endif
  75. #define B_KEY_INDEX_OFFSET(node) ((grub_uint16_t *) \
  76. ((char *) (node) \
  77. + ALIGN_UP (sizeof (struct grub_afs_bnode) \
  78. + node->key_size, \
  79. B_KEY_INDEX_ALIGN)))
  80. #define B_KEY_VALUE_OFFSET(node) ((grub_afs_bvalue_t *) \
  81. ((char *) B_KEY_INDEX_OFFSET (node) + \
  82. node->key_count * 2))
  83. typedef grub_uint64_t grub_afs_off_t;
  84. typedef grub_uint64_t grub_afs_bigtime;
  85. typedef grub_uint64_t grub_afs_bvalue_t;
  86. struct grub_afs_blockrun
  87. {
  88. grub_uint32_t group;
  89. grub_uint16_t start;
  90. grub_uint16_t len;
  91. } __attribute__ ((packed));
  92. struct grub_afs_datastream
  93. {
  94. struct grub_afs_blockrun direct[GRUB_AFS_DIRECT_BLOCK_COUNT];
  95. grub_afs_off_t max_direct_range;
  96. struct grub_afs_blockrun indirect;
  97. grub_afs_off_t max_indirect_range;
  98. struct grub_afs_blockrun double_indirect;
  99. grub_afs_off_t max_double_indirect_range;
  100. grub_afs_off_t size;
  101. } __attribute__ ((packed));
  102. struct grub_afs_bnode
  103. {
  104. grub_afs_bvalue_t left;
  105. grub_afs_bvalue_t right;
  106. grub_afs_bvalue_t overflow;
  107. #ifdef MODE_BFS
  108. grub_uint16_t key_count;
  109. grub_uint16_t key_size;
  110. #else
  111. grub_uint32_t key_count;
  112. grub_uint32_t key_size;
  113. #endif
  114. char key_data[0];
  115. } __attribute__ ((packed));
  116. #ifdef MODE_BFS
  117. struct grub_afs_btree
  118. {
  119. grub_uint32_t magic;
  120. grub_uint32_t unused1;
  121. grub_uint32_t tree_depth;
  122. grub_uint32_t unused2;
  123. grub_afs_bvalue_t root;
  124. grub_uint32_t unused3[4];
  125. } __attribute__ ((packed));
  126. #else
  127. struct grub_afs_btree
  128. {
  129. grub_uint32_t magic;
  130. grub_afs_bvalue_t root;
  131. grub_uint32_t tree_depth;
  132. grub_afs_bvalue_t last_node;
  133. grub_afs_bvalue_t first_free;
  134. } __attribute__ ((packed));
  135. #endif
  136. /* Beware that following structure describes AtheFS and if you write code
  137. which uses currently unused fields check it with both AtheFS and BeFS.
  138. */
  139. struct grub_afs_sblock
  140. {
  141. char name[32];
  142. grub_uint32_t magic1;
  143. grub_uint32_t byte_order;
  144. grub_uint32_t block_size;
  145. grub_uint32_t block_shift;
  146. grub_afs_off_t num_blocks;
  147. grub_afs_off_t used_blocks;
  148. grub_uint32_t inode_size;
  149. grub_uint32_t magic2;
  150. grub_uint32_t block_per_group; /* Number of blocks per allocation
  151. group. (Max 65536) */
  152. grub_uint32_t alloc_group_shift; /* Number of bits to shift a group
  153. number to get a byte address. */
  154. grub_uint32_t alloc_group_count;
  155. grub_uint32_t flags;
  156. struct grub_afs_blockrun log_block;
  157. grub_afs_off_t log_start;
  158. grub_uint32_t valid_log_blocks;
  159. grub_uint32_t log_size;
  160. grub_uint32_t magic3;
  161. struct grub_afs_blockrun root_dir; /* Root dir inode. */
  162. struct grub_afs_blockrun deleted_files; /* Directory containing files
  163. scheduled for deletion. */
  164. struct grub_afs_blockrun index_dir; /* Directory of index files. */
  165. grub_uint32_t boot_loader_size;
  166. grub_uint32_t pad[7];
  167. } __attribute__ ((packed));
  168. struct grub_afs_inode
  169. {
  170. grub_uint32_t magic1;
  171. struct grub_afs_blockrun inode_num;
  172. grub_uint32_t uid;
  173. grub_uint32_t gid;
  174. grub_uint32_t mode;
  175. grub_uint32_t flags;
  176. #ifndef MODE_BFS
  177. grub_uint32_t link_count;
  178. #endif
  179. grub_afs_bigtime create_time;
  180. grub_afs_bigtime modified_time;
  181. struct grub_afs_blockrun parent;
  182. struct grub_afs_blockrun attrib_dir;
  183. grub_uint32_t index_type; /* Key data-key only used for index files. */
  184. grub_uint32_t inode_size;
  185. grub_uint32_t unused;
  186. struct grub_afs_datastream stream;
  187. grub_uint32_t pad[4];
  188. grub_uint32_t small_data[1];
  189. } __attribute__ ((packed));
  190. struct grub_fshelp_node
  191. {
  192. struct grub_afs_data *data;
  193. struct grub_afs_inode inode;
  194. };
  195. struct grub_afs_data
  196. {
  197. grub_disk_t disk;
  198. struct grub_afs_sblock sblock;
  199. struct grub_afs_inode *inode;
  200. struct grub_fshelp_node diropen;
  201. };
  202. static grub_dl_t my_mod;
  203. static grub_afs_off_t
  204. grub_afs_run_to_num (struct grub_afs_sblock *sb,
  205. struct grub_afs_blockrun *run)
  206. {
  207. return ((grub_afs_off_t) grub_afs_to_cpu32 (run->group)
  208. * sb->block_per_group + grub_afs_to_cpu16 (run->start));
  209. }
  210. static grub_err_t
  211. grub_afs_read_inode (struct grub_afs_data *data,
  212. grub_uint32_t ino, struct grub_afs_inode *inode)
  213. {
  214. return grub_disk_read (data->disk,
  215. ino *
  216. (data->sblock.block_size >> GRUB_DISK_SECTOR_BITS),
  217. 0, sizeof (struct grub_afs_inode),
  218. inode);
  219. }
  220. static grub_disk_addr_t
  221. grub_afs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
  222. {
  223. struct grub_afs_sblock *sb = &node->data->sblock;
  224. struct grub_afs_datastream *ds = &node->inode.stream;
  225. if (fileblock < grub_afs_to_cpu64 (ds->max_direct_range))
  226. {
  227. int i;
  228. for (i = 0; i < GRUB_AFS_DIRECT_BLOCK_COUNT; i++)
  229. {
  230. if (fileblock < grub_afs_to_cpu16 (ds->direct[i].len))
  231. return grub_afs_run_to_num (sb, &ds->direct[i]) + fileblock;
  232. fileblock -= grub_afs_to_cpu16 (ds->direct[i].len);
  233. }
  234. }
  235. else if (fileblock < grub_afs_to_cpu64 (ds->max_indirect_range))
  236. {
  237. int ptrs_per_blk = sb->block_size / sizeof (struct grub_afs_blockrun);
  238. struct grub_afs_blockrun indir[ptrs_per_blk];
  239. grub_afs_off_t blk = grub_afs_run_to_num (sb, &ds->indirect);
  240. int i;
  241. fileblock -= grub_afs_to_cpu64 (ds->max_direct_range);
  242. for (i = 0; i < ds->indirect.len; i++, blk++)
  243. {
  244. int j;
  245. if (grub_disk_read (node->data->disk,
  246. blk * (sb->block_size >> GRUB_DISK_SECTOR_BITS),
  247. 0, sizeof (indir),
  248. indir))
  249. return 0;
  250. for (j = 0; j < ptrs_per_blk; j++)
  251. {
  252. if (fileblock < grub_afs_to_cpu16 (indir[j].len))
  253. return grub_afs_run_to_num (sb, &indir[j]) + fileblock;
  254. fileblock -= grub_afs_to_cpu16 (indir[j].len);
  255. }
  256. }
  257. }
  258. else
  259. {
  260. int ptrs_per_blk = sb->block_size / sizeof (struct grub_afs_blockrun);
  261. struct grub_afs_blockrun indir[ptrs_per_blk];
  262. /* ([idblk][idptr]) ([dblk][dptr]) [blk] */
  263. int cur_pos = fileblock - grub_afs_to_cpu64 (ds->max_indirect_range);
  264. int dptr_size = GRUB_AFS_BLOCKS_PER_DI_RUN;
  265. int dblk_size = dptr_size * ptrs_per_blk;
  266. int idptr_size = dblk_size * GRUB_AFS_BLOCKS_PER_DI_RUN;
  267. int idblk_size = idptr_size * ptrs_per_blk;
  268. int off = cur_pos % GRUB_AFS_BLOCKS_PER_DI_RUN;
  269. int dptr = (cur_pos / dptr_size) % ptrs_per_blk;
  270. int dblk = (cur_pos / dblk_size) % GRUB_AFS_BLOCKS_PER_DI_RUN;
  271. int idptr = (cur_pos / idptr_size) % ptrs_per_blk;
  272. int idblk = (cur_pos / idblk_size);
  273. if (grub_disk_read (node->data->disk,
  274. (grub_afs_run_to_num (sb, &ds->double_indirect)
  275. + idblk) *
  276. (sb->block_size >> GRUB_DISK_SECTOR_BITS),
  277. 0, sizeof (indir),
  278. indir))
  279. return 0;
  280. if (grub_disk_read (node->data->disk,
  281. (grub_afs_run_to_num (sb, &indir[idptr]) + dblk) *
  282. (sb->block_size >> GRUB_DISK_SECTOR_BITS),
  283. 0, sizeof (indir),
  284. indir))
  285. return 0;
  286. return grub_afs_run_to_num (sb, &indir[dptr]) + off;
  287. }
  288. return 0;
  289. }
  290. static grub_ssize_t
  291. grub_afs_read_file (grub_fshelp_node_t node,
  292. void (*read_hook) (grub_disk_addr_t sector,
  293. unsigned offset, unsigned length,
  294. void *closure),
  295. void *closure, int flags,
  296. int pos, grub_size_t len, char *buf)
  297. {
  298. return grub_fshelp_read_file (node->data->disk, node, read_hook, closure,
  299. flags, pos, len, buf, grub_afs_read_block,
  300. grub_afs_to_cpu64 (node->inode.stream.size),
  301. node->data->sblock.block_shift
  302. - GRUB_DISK_SECTOR_BITS);
  303. }
  304. static char *
  305. grub_afs_read_symlink (grub_fshelp_node_t node)
  306. {
  307. char *ret;
  308. grub_afs_off_t size = grub_afs_to_cpu64 (node->inode.stream.size);
  309. if (size == 0)
  310. {
  311. size = sizeof (node->inode.stream);
  312. ret = grub_zalloc (size + 1);
  313. if (! ret)
  314. return 0;
  315. grub_memcpy (ret, (char *) &(node->inode.stream),
  316. sizeof (node->inode.stream));
  317. return ret;
  318. }
  319. ret = grub_zalloc (size + 1);
  320. if (! ret)
  321. return 0;
  322. grub_afs_read_file (node, 0, 0, 0, 0, size, ret);
  323. return ret;
  324. }
  325. static int
  326. grub_afs_iterate_dir (grub_fshelp_node_t dir,
  327. int (*hook) (const char *filename,
  328. enum grub_fshelp_filetype filetype,
  329. grub_fshelp_node_t node, void *closure),
  330. void *closure)
  331. {
  332. struct grub_afs_btree head;
  333. char node_data [GRUB_AFS_BNODE_SIZE];
  334. struct grub_afs_bnode *node = (struct grub_afs_bnode *) node_data;
  335. int i;
  336. if ((dir->inode.stream.size == 0)
  337. || ((grub_afs_to_cpu32 (dir->inode.mode) & GRUB_AFS_S_IFMT)
  338. != GRUB_AFS_S_IFDIR))
  339. return 0;
  340. grub_afs_read_file (dir, 0, 0, 0, 0, sizeof (head), (char *) &head);
  341. if (grub_errno)
  342. return 0;
  343. grub_afs_read_file (dir, 0, 0, 0, grub_afs_to_cpu64 (head.root),
  344. GRUB_AFS_BNODE_SIZE, (char *) node);
  345. if (grub_errno)
  346. return 0;
  347. for (i = 0; i < (int) grub_afs_to_cpu32 (head.tree_depth) - 1; i++)
  348. {
  349. grub_afs_bvalue_t blk;
  350. blk = grub_afs_to_cpu64(B_KEY_VALUE_OFFSET (node) [0]);
  351. grub_afs_read_file (dir, 0, 0, 0, blk, GRUB_AFS_BNODE_SIZE, (char *) node);
  352. if (grub_errno)
  353. return 0;
  354. }
  355. if (node->key_count)
  356. {
  357. grub_uint32_t cur_key = 0;
  358. while (1)
  359. {
  360. int key_start, key_size;
  361. grub_uint16_t *index;
  362. index = B_KEY_INDEX_OFFSET (node);
  363. key_start = (cur_key > 0)
  364. ? grub_afs_to_cpu16 (index[cur_key - 1]) : 0;
  365. key_size = grub_afs_to_cpu16 (index[cur_key]) - key_start;
  366. if (key_size > 0)
  367. {
  368. char filename [key_size + 1];
  369. struct grub_fshelp_node *fdiro;
  370. int mode, type;
  371. fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
  372. if (! fdiro)
  373. return 0;
  374. fdiro->data = dir->data;
  375. if (grub_afs_read_inode (dir->data,
  376. grub_afs_to_cpu64
  377. (B_KEY_VALUE_OFFSET (node) [cur_key]),
  378. &fdiro->inode))
  379. return 0;
  380. grub_memcpy (filename, &node->key_data[key_start], key_size);
  381. filename [key_size] = 0;
  382. mode = (grub_afs_to_cpu32 (fdiro->inode.mode) & GRUB_AFS_S_IFMT);
  383. if (mode == GRUB_AFS_S_IFDIR)
  384. type = GRUB_FSHELP_DIR;
  385. else if (mode == GRUB_AFS_S_IFREG)
  386. type = GRUB_FSHELP_REG;
  387. else if (mode == GRUB_AFS_S_IFLNK)
  388. type = GRUB_FSHELP_SYMLINK;
  389. else
  390. type = GRUB_FSHELP_UNKNOWN;
  391. if (hook (filename, type, fdiro, closure))
  392. return 1;
  393. }
  394. cur_key++;
  395. if (cur_key >= grub_afs_to_cpu32 (node->key_count))
  396. {
  397. if (node->right == GRUB_AFS_NULL_VAL)
  398. break;
  399. grub_afs_read_file (dir, 0, 0, 0, grub_afs_to_cpu64 (node->right),
  400. GRUB_AFS_BNODE_SIZE, (char *) node);
  401. if (grub_errno)
  402. return 0;
  403. cur_key = 0;
  404. }
  405. }
  406. }
  407. return 0;
  408. }
  409. static int
  410. grub_afs_validate_sblock (struct grub_afs_sblock *sb)
  411. {
  412. if (grub_afs_to_cpu32 (sb->magic1) == GRUB_AFS_SBLOCK_MAGIC1)
  413. {
  414. sb->magic2 = grub_afs_to_cpu32 (sb->magic2);
  415. sb->magic3 = grub_afs_to_cpu32 (sb->magic3);
  416. sb->block_shift = grub_afs_to_cpu32 (sb->block_shift);
  417. sb->block_size = grub_afs_to_cpu32 (sb->block_size);
  418. sb->used_blocks = grub_afs_to_cpu64 (sb->used_blocks);
  419. sb->num_blocks = grub_afs_to_cpu64 (sb->num_blocks);
  420. sb->inode_size = grub_afs_to_cpu32 (sb->inode_size);
  421. sb->alloc_group_count = grub_afs_to_cpu32 (sb->alloc_group_count);
  422. sb->alloc_group_shift = grub_afs_to_cpu32 (sb->alloc_group_shift);
  423. sb->block_per_group = grub_afs_to_cpu32 (sb->block_per_group);
  424. sb->alloc_group_count = grub_afs_to_cpu32 (sb->alloc_group_count);
  425. sb->log_size = grub_afs_to_cpu32 (sb->log_size);
  426. }
  427. else
  428. return 0;
  429. if ((sb->magic2 != GRUB_AFS_SBLOCK_MAGIC2) ||
  430. (sb->magic3 != GRUB_AFS_SBLOCK_MAGIC3))
  431. return 0;
  432. #ifdef MODE_BFS
  433. sb->block_per_group = 1 << (sb->alloc_group_shift);
  434. #endif
  435. if (((grub_uint32_t) (1 << sb->block_shift) != sb->block_size)
  436. || (sb->used_blocks > sb->num_blocks )
  437. || (sb->inode_size != sb->block_size)
  438. || (0 == sb->block_size)
  439. #ifndef MODE_BFS
  440. || ((grub_uint32_t) (1 << sb->alloc_group_shift) !=
  441. sb->block_per_group * sb->block_size)
  442. || (sb->alloc_group_count * sb->block_per_group < sb->num_blocks)
  443. || (grub_afs_to_cpu16 (sb->log_block.len) != sb->log_size)
  444. || (grub_afs_to_cpu32 (sb->valid_log_blocks) > sb->log_size)
  445. #endif
  446. )
  447. return 0;
  448. return 1;
  449. }
  450. static struct grub_afs_data *
  451. grub_afs_mount (grub_disk_t disk)
  452. {
  453. struct grub_afs_data *data = 0;
  454. data = grub_malloc (sizeof (struct grub_afs_data));
  455. if (!data)
  456. return 0;
  457. /* Read the superblock. */
  458. if (grub_disk_read (disk, GRUB_AFS_SBLOCK_SECTOR, 0,
  459. sizeof (struct grub_afs_sblock), &data->sblock))
  460. goto fail;
  461. if (! grub_afs_validate_sblock (&data->sblock))
  462. goto fail;
  463. data->diropen.data = data;
  464. data->inode = &data->diropen.inode;
  465. data->disk = disk;
  466. if (grub_afs_read_inode (data,
  467. grub_afs_run_to_num (&data->sblock,
  468. &data->sblock.root_dir),
  469. data->inode))
  470. goto fail;
  471. return data;
  472. fail:
  473. grub_error (GRUB_ERR_BAD_FS, "not an " GRUB_AFS_FSNAME " filesystem");
  474. grub_free (data);
  475. return 0;
  476. }
  477. static grub_err_t
  478. grub_afs_open (struct grub_file *file, const char *name)
  479. {
  480. struct grub_afs_data *data;
  481. struct grub_fshelp_node *fdiro = 0;
  482. grub_dl_ref (my_mod);
  483. data = grub_afs_mount (file->device->disk);
  484. if (! data)
  485. goto fail;
  486. grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_afs_iterate_dir, 0,
  487. grub_afs_read_symlink, GRUB_FSHELP_REG);
  488. if (grub_errno)
  489. goto fail;
  490. grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_afs_inode));
  491. grub_free (fdiro);
  492. file->size = grub_afs_to_cpu64 (data->inode->stream.size);
  493. file->data = data;
  494. file->offset = 0;
  495. return 0;
  496. fail:
  497. grub_free (data);
  498. grub_dl_unref (my_mod);
  499. return grub_errno;
  500. }
  501. static grub_ssize_t
  502. grub_afs_read (grub_file_t file, char *buf, grub_size_t len)
  503. {
  504. struct grub_afs_data *data = (struct grub_afs_data *) file->data;
  505. return grub_afs_read_file (&data->diropen, file->read_hook, file->closure,
  506. file->flags, file->offset, len, buf);
  507. }
  508. static grub_err_t
  509. grub_afs_close (grub_file_t file)
  510. {
  511. grub_free (file->data);
  512. grub_dl_unref (my_mod);
  513. return GRUB_ERR_NONE;
  514. }
  515. struct grub_afs_dir_closure
  516. {
  517. int (*hook) (const char *filename,
  518. const struct grub_dirhook_info *info, void *closure);
  519. void *closure;
  520. };
  521. static int
  522. iterate (const char *filename,
  523. enum grub_fshelp_filetype filetype,
  524. grub_fshelp_node_t node, void *closure)
  525. {
  526. struct grub_afs_dir_closure *c = closure;
  527. struct grub_dirhook_info info;
  528. grub_memset (&info, 0, sizeof (info));
  529. info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
  530. info.mtimeset = 1;
  531. #ifdef MODE_BFS
  532. info.mtime = grub_afs_to_cpu64 (node->inode.modified_time) >> 16;
  533. #else
  534. info.mtime = grub_divmod64 (grub_afs_to_cpu64 (node->inode.modified_time),
  535. 1000000, 0);
  536. #endif
  537. grub_free (node);
  538. return c->hook (filename, &info, c->closure);
  539. }
  540. static grub_err_t
  541. grub_afs_dir (grub_device_t device, const char *path,
  542. int (*hook) (const char *filename,
  543. const struct grub_dirhook_info *info, void *closure),
  544. void *closure)
  545. {
  546. struct grub_afs_data *data = 0;
  547. struct grub_fshelp_node *fdiro = 0;
  548. struct grub_afs_dir_closure c;
  549. grub_dl_ref (my_mod);
  550. data = grub_afs_mount (device->disk);
  551. if (! data)
  552. goto fail;
  553. grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_afs_iterate_dir, 0,
  554. grub_afs_read_symlink, GRUB_FSHELP_DIR);
  555. if (grub_errno)
  556. goto fail;
  557. c.hook = hook;
  558. c.closure = closure;
  559. grub_afs_iterate_dir (fdiro, iterate, &c);
  560. if (fdiro != &data->diropen)
  561. grub_free (fdiro);
  562. fail:
  563. grub_free (data);
  564. grub_dl_unref (my_mod);
  565. return grub_errno;
  566. }
  567. static grub_err_t
  568. grub_afs_label (grub_device_t device, char **label)
  569. {
  570. struct grub_afs_data *data;
  571. grub_disk_t disk = device->disk;
  572. grub_dl_ref (my_mod);
  573. data = grub_afs_mount (disk);
  574. if (data)
  575. *label = grub_strndup (data->sblock.name, sizeof (data->sblock.name));
  576. else
  577. *label = NULL;
  578. grub_dl_unref (my_mod);
  579. grub_free (data);
  580. return grub_errno;
  581. }
  582. static struct grub_fs grub_afs_fs = {
  583. .name = GRUB_AFS_FSNAME,
  584. .dir = grub_afs_dir,
  585. .open = grub_afs_open,
  586. .read = grub_afs_read,
  587. .close = grub_afs_close,
  588. .label = grub_afs_label,
  589. .next = 0
  590. };
  591. #if defined (MODE_BIGENDIAN) && defined (MODE_BFS)
  592. GRUB_MOD_INIT (befs_be)
  593. #elif defined (MODE_BFS)
  594. GRUB_MOD_INIT (befs)
  595. #elif defined (MODE_BIGENDIAN)
  596. GRUB_MOD_INIT (afs_be)
  597. #else
  598. GRUB_MOD_INIT (afs)
  599. #endif
  600. {
  601. grub_fs_register (&grub_afs_fs);
  602. my_mod = mod;
  603. }
  604. #if defined (MODE_BIGENDIAN) && defined (MODE_BFS)
  605. GRUB_MOD_FINI (befs_be)
  606. #elif defined (MODE_BFS)
  607. GRUB_MOD_FINI (befs)
  608. #elif defined (MODE_BIGENDIAN)
  609. GRUB_MOD_FINI (afs_be)
  610. #else
  611. GRUB_MOD_FINI (afs)
  612. #endif
  613. {
  614. grub_fs_unregister (&grub_afs_fs);
  615. }