1 /* afs.c - The native AtheOS file-system. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008,2009 Free Software Foundation, Inc.
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.
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.
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/>.
21 #include <grub/file.h>
23 #include <grub/misc.h>
24 #include <grub/disk.h>
26 #include <grub/types.h>
27 #include <grub/fshelp.h>
30 #define GRUB_AFS_FSNAME_SUFFIX "_be"
32 #define GRUB_AFS_FSNAME_SUFFIX ""
36 #define GRUB_AFS_FSNAME "befs" GRUB_AFS_FSNAME_SUFFIX
38 #define GRUB_AFS_FSNAME "afs" GRUB_AFS_FSNAME_SUFFIX
41 #define GRUB_AFS_DIRECT_BLOCK_COUNT 12
42 #define GRUB_AFS_BLOCKS_PER_DI_RUN 4
45 #define GRUB_AFS_SBLOCK_SECTOR 1
46 #define GRUB_AFS_SBLOCK_MAGIC1 0x42465331 /* BFS1. */
48 #define GRUB_AFS_SBLOCK_SECTOR 2
49 #define GRUB_AFS_SBLOCK_MAGIC1 0x41465331 /* AFS1. */
52 #define GRUB_AFS_SBLOCK_MAGIC2 0xdd121031
53 #define GRUB_AFS_SBLOCK_MAGIC3 0x15b6830e
55 #define GRUB_AFS_INODE_MAGIC 0x64358428
58 #define GRUB_AFS_BTREE_MAGIC 0x69f6c2e8
60 #define GRUB_AFS_BTREE_MAGIC 0x65768995
63 #define GRUB_AFS_BNODE_SIZE 1024
65 #define GRUB_AFS_S_IFMT 00170000
66 #define GRUB_AFS_S_IFLNK 0120000
68 #define GRUB_AFS_S_IFREG 0100000
69 #define GRUB_AFS_S_IFDIR 0040000
70 #define GRUB_AFS_S_IFIFO 0010000
72 #define GRUB_AFS_NULL_VAL ((grub_afs_bvalue_t)-1)
75 #define grub_afs_to_cpu16(x) grub_be_to_cpu16 (x)
76 #define grub_afs_to_cpu32(x) grub_be_to_cpu32 (x)
77 #define grub_afs_to_cpu64(x) grub_be_to_cpu64 (x)
79 #define grub_afs_to_cpu16(x) grub_le_to_cpu16 (x)
80 #define grub_afs_to_cpu32(x) grub_le_to_cpu32 (x)
81 #define grub_afs_to_cpu64(x) grub_le_to_cpu64 (x)
85 #define B_KEY_INDEX_ALIGN 8
87 #define B_KEY_INDEX_ALIGN 4
90 #define B_KEY_INDEX_OFFSET(node) ((grub_uint16_t *) \
92 + ALIGN_UP (sizeof (struct grub_afs_bnode) \
96 #define B_KEY_VALUE_OFFSET(node) ((grub_afs_bvalue_t *) \
97 ((char *) B_KEY_INDEX_OFFSET (node) + \
100 typedef grub_uint64_t grub_afs_off_t
;
101 typedef grub_uint64_t grub_afs_bigtime
;
102 typedef grub_uint64_t grub_afs_bvalue_t
;
104 struct grub_afs_blockrun
109 } __attribute__ ((packed
));
111 struct grub_afs_datastream
113 struct grub_afs_blockrun direct
[GRUB_AFS_DIRECT_BLOCK_COUNT
];
114 grub_afs_off_t max_direct_range
;
115 struct grub_afs_blockrun indirect
;
116 grub_afs_off_t max_indirect_range
;
117 struct grub_afs_blockrun double_indirect
;
118 grub_afs_off_t max_double_indirect_range
;
120 } __attribute__ ((packed
));
122 struct grub_afs_bnode
124 grub_afs_bvalue_t left
;
125 grub_afs_bvalue_t right
;
126 grub_afs_bvalue_t overflow
;
128 grub_uint16_t key_count
;
129 grub_uint16_t key_size
;
131 grub_uint32_t key_count
;
132 grub_uint32_t key_size
;
135 } __attribute__ ((packed
));
138 struct grub_afs_btree
141 grub_uint32_t unused1
;
142 grub_uint32_t tree_depth
;
143 grub_uint32_t unused2
;
144 grub_afs_bvalue_t root
;
145 grub_uint32_t unused3
[4];
146 } __attribute__ ((packed
));
148 struct grub_afs_btree
151 grub_afs_bvalue_t root
;
152 grub_uint32_t tree_depth
;
153 grub_afs_bvalue_t last_node
;
154 grub_afs_bvalue_t first_free
;
155 } __attribute__ ((packed
));
158 /* Beware that following structure describes AtheFS and if you write code
159 which uses currently unused fields check it with both AtheFS and BeFS.
161 struct grub_afs_sblock
164 grub_uint32_t magic1
;
165 grub_uint32_t byte_order
;
166 grub_uint32_t block_size
;
167 grub_uint32_t block_shift
;
168 grub_afs_off_t num_blocks
;
169 grub_afs_off_t used_blocks
;
170 grub_uint32_t inode_size
;
171 grub_uint32_t magic2
;
172 grub_uint32_t block_per_group
; /* Number of blocks per allocation
173 group. (Max 65536) */
174 grub_uint32_t alloc_group_shift
; /* Number of bits to shift a group
175 number to get a byte address. */
176 grub_uint32_t alloc_group_count
;
178 struct grub_afs_blockrun log_block
;
179 grub_afs_off_t log_start
;
180 grub_uint32_t valid_log_blocks
;
181 grub_uint32_t log_size
;
182 grub_uint32_t magic3
;
183 struct grub_afs_blockrun root_dir
; /* Root dir inode. */
184 struct grub_afs_blockrun deleted_files
; /* Directory containing files
185 scheduled for deletion. */
186 struct grub_afs_blockrun index_dir
; /* Directory of index files. */
187 grub_uint32_t boot_loader_size
;
188 grub_uint32_t pad
[7];
189 } __attribute__ ((packed
));
191 struct grub_afs_inode
193 grub_uint32_t magic1
;
194 struct grub_afs_blockrun inode_num
;
200 grub_uint32_t link_count
;
202 grub_afs_bigtime create_time
;
203 grub_afs_bigtime modified_time
;
204 struct grub_afs_blockrun parent
;
205 struct grub_afs_blockrun attrib_dir
;
206 grub_uint32_t index_type
; /* Key data-key only used for index files. */
207 grub_uint32_t inode_size
;
208 grub_uint32_t unused
;
209 struct grub_afs_datastream stream
;
210 grub_uint32_t pad
[4];
211 grub_uint32_t small_data
[1];
212 } __attribute__ ((packed
));
214 struct grub_fshelp_node
216 struct grub_afs_data
*data
;
217 struct grub_afs_inode inode
;
223 struct grub_afs_sblock sblock
;
224 struct grub_afs_inode
*inode
;
225 struct grub_fshelp_node diropen
;
228 static grub_dl_t my_mod
;
230 static grub_afs_off_t
231 grub_afs_run_to_num (struct grub_afs_sblock
*sb
,
232 struct grub_afs_blockrun
*run
)
234 return ((grub_afs_off_t
) grub_afs_to_cpu32 (run
->group
)
235 * sb
->block_per_group
+ grub_afs_to_cpu16 (run
->start
));
239 grub_afs_read_inode (struct grub_afs_data
*data
,
240 grub_uint32_t ino
, struct grub_afs_inode
*inode
)
242 return grub_disk_read (data
->disk
,
244 (data
->sblock
.block_size
>> GRUB_DISK_SECTOR_BITS
),
245 0, sizeof (struct grub_afs_inode
),
249 static grub_disk_addr_t
250 grub_afs_read_block (grub_fshelp_node_t node
, grub_disk_addr_t fileblock
)
252 struct grub_afs_sblock
*sb
= &node
->data
->sblock
;
253 struct grub_afs_datastream
*ds
= &node
->inode
.stream
;
255 if (fileblock
< grub_afs_to_cpu64 (ds
->max_direct_range
))
259 for (i
= 0; i
< GRUB_AFS_DIRECT_BLOCK_COUNT
; i
++)
261 if (fileblock
< grub_afs_to_cpu16 (ds
->direct
[i
].len
))
262 return grub_afs_run_to_num (sb
, &ds
->direct
[i
]) + fileblock
;
263 fileblock
-= grub_afs_to_cpu16 (ds
->direct
[i
].len
);
266 else if (fileblock
< grub_afs_to_cpu64 (ds
->max_indirect_range
))
268 int ptrs_per_blk
= sb
->block_size
/ sizeof (struct grub_afs_blockrun
);
269 struct grub_afs_blockrun indir
[ptrs_per_blk
];
270 grub_afs_off_t blk
= grub_afs_run_to_num (sb
, &ds
->indirect
);
273 fileblock
-= grub_afs_to_cpu64 (ds
->max_direct_range
);
274 for (i
= 0; i
< ds
->indirect
.len
; i
++, blk
++)
278 if (grub_disk_read (node
->data
->disk
,
279 blk
* (sb
->block_size
>> GRUB_DISK_SECTOR_BITS
),
284 for (j
= 0; j
< ptrs_per_blk
; j
++)
286 if (fileblock
< grub_afs_to_cpu16 (indir
[j
].len
))
287 return grub_afs_run_to_num (sb
, &indir
[j
]) + fileblock
;
289 fileblock
-= grub_afs_to_cpu16 (indir
[j
].len
);
295 int ptrs_per_blk
= sb
->block_size
/ sizeof (struct grub_afs_blockrun
);
296 struct grub_afs_blockrun indir
[ptrs_per_blk
];
298 /* ([idblk][idptr]) ([dblk][dptr]) [blk] */
299 int cur_pos
= fileblock
- grub_afs_to_cpu64 (ds
->max_indirect_range
);
301 int dptr_size
= GRUB_AFS_BLOCKS_PER_DI_RUN
;
302 int dblk_size
= dptr_size
* ptrs_per_blk
;
303 int idptr_size
= dblk_size
* GRUB_AFS_BLOCKS_PER_DI_RUN
;
304 int idblk_size
= idptr_size
* ptrs_per_blk
;
306 int off
= cur_pos
% GRUB_AFS_BLOCKS_PER_DI_RUN
;
307 int dptr
= (cur_pos
/ dptr_size
) % ptrs_per_blk
;
308 int dblk
= (cur_pos
/ dblk_size
) % GRUB_AFS_BLOCKS_PER_DI_RUN
;
309 int idptr
= (cur_pos
/ idptr_size
) % ptrs_per_blk
;
310 int idblk
= (cur_pos
/ idblk_size
);
312 if (grub_disk_read (node
->data
->disk
,
313 (grub_afs_run_to_num (sb
, &ds
->double_indirect
)
315 (sb
->block_size
>> GRUB_DISK_SECTOR_BITS
),
320 if (grub_disk_read (node
->data
->disk
,
321 (grub_afs_run_to_num (sb
, &indir
[idptr
]) + dblk
) *
322 (sb
->block_size
>> GRUB_DISK_SECTOR_BITS
),
327 return grub_afs_run_to_num (sb
, &indir
[dptr
]) + off
;
334 grub_afs_read_file (grub_fshelp_node_t node
,
335 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
336 unsigned offset
, unsigned length
),
337 int pos
, grub_size_t len
, char *buf
)
339 return grub_fshelp_read_file (node
->data
->disk
, node
, read_hook
,
340 pos
, len
, buf
, grub_afs_read_block
,
341 grub_afs_to_cpu64 (node
->inode
.stream
.size
),
342 node
->data
->sblock
.block_shift
343 - GRUB_DISK_SECTOR_BITS
);
347 grub_afs_read_symlink (grub_fshelp_node_t node
)
350 grub_afs_off_t size
= grub_afs_to_cpu64 (node
->inode
.stream
.size
);
354 size
= sizeof (node
->inode
.stream
);
355 ret
= grub_zalloc (size
+ 1);
358 grub_memcpy (ret
, (char *) &(node
->inode
.stream
),
359 sizeof (node
->inode
.stream
));
362 ret
= grub_zalloc (size
+ 1);
365 grub_afs_read_file (node
, 0, 0, size
, ret
);
370 grub_afs_iterate_dir (grub_fshelp_node_t dir
,
372 (*hook
) (const char *filename
,
373 enum grub_fshelp_filetype filetype
,
374 grub_fshelp_node_t node
))
376 struct grub_afs_btree head
;
377 char node_data
[GRUB_AFS_BNODE_SIZE
];
378 struct grub_afs_bnode
*node
= (struct grub_afs_bnode
*) node_data
;
381 if ((dir
->inode
.stream
.size
== 0)
382 || ((grub_afs_to_cpu32 (dir
->inode
.mode
) & GRUB_AFS_S_IFMT
)
383 != GRUB_AFS_S_IFDIR
))
386 grub_afs_read_file (dir
, 0, 0, sizeof (head
), (char *) &head
);
390 grub_afs_read_file (dir
, 0, grub_afs_to_cpu64 (head
.root
),
391 GRUB_AFS_BNODE_SIZE
, (char *) node
);
395 for (i
= 0; i
< (int) grub_afs_to_cpu32 (head
.tree_depth
) - 1; i
++)
397 grub_afs_bvalue_t blk
;
399 blk
= grub_afs_to_cpu64(B_KEY_VALUE_OFFSET (node
) [0]);
400 grub_afs_read_file (dir
, 0, blk
, GRUB_AFS_BNODE_SIZE
, (char *) node
);
407 grub_uint32_t cur_key
= 0;
411 int key_start
, key_size
;
412 grub_uint16_t
*index
;
414 index
= B_KEY_INDEX_OFFSET (node
);
416 key_start
= (cur_key
> 0)
417 ? grub_afs_to_cpu16 (index
[cur_key
- 1]) : 0;
418 key_size
= grub_afs_to_cpu16 (index
[cur_key
]) - key_start
;
421 char filename
[key_size
+ 1];
422 struct grub_fshelp_node
*fdiro
;
425 fdiro
= grub_malloc (sizeof (struct grub_fshelp_node
));
429 fdiro
->data
= dir
->data
;
430 if (grub_afs_read_inode (dir
->data
,
432 (B_KEY_VALUE_OFFSET (node
) [cur_key
]),
436 grub_memcpy (filename
, &node
->key_data
[key_start
], key_size
);
437 filename
[key_size
] = 0;
439 mode
= (grub_afs_to_cpu32 (fdiro
->inode
.mode
) & GRUB_AFS_S_IFMT
);
440 if (mode
== GRUB_AFS_S_IFDIR
)
441 type
= GRUB_FSHELP_DIR
;
442 else if (mode
== GRUB_AFS_S_IFREG
)
443 type
= GRUB_FSHELP_REG
;
444 else if (mode
== GRUB_AFS_S_IFLNK
)
445 type
= GRUB_FSHELP_SYMLINK
;
447 type
= GRUB_FSHELP_UNKNOWN
;
449 if (hook (filename
, type
, fdiro
))
454 if (cur_key
>= grub_afs_to_cpu32 (node
->key_count
))
456 if (node
->right
== GRUB_AFS_NULL_VAL
)
459 grub_afs_read_file (dir
, 0, grub_afs_to_cpu64 (node
->right
),
460 GRUB_AFS_BNODE_SIZE
, (char *) node
);
473 grub_afs_validate_sblock (struct grub_afs_sblock
*sb
)
475 if (grub_afs_to_cpu32 (sb
->magic1
) == GRUB_AFS_SBLOCK_MAGIC1
)
477 sb
->magic2
= grub_afs_to_cpu32 (sb
->magic2
);
478 sb
->magic3
= grub_afs_to_cpu32 (sb
->magic3
);
479 sb
->block_shift
= grub_afs_to_cpu32 (sb
->block_shift
);
480 sb
->block_size
= grub_afs_to_cpu32 (sb
->block_size
);
481 sb
->used_blocks
= grub_afs_to_cpu64 (sb
->used_blocks
);
482 sb
->num_blocks
= grub_afs_to_cpu64 (sb
->num_blocks
);
483 sb
->inode_size
= grub_afs_to_cpu32 (sb
->inode_size
);
484 sb
->alloc_group_count
= grub_afs_to_cpu32 (sb
->alloc_group_count
);
485 sb
->alloc_group_shift
= grub_afs_to_cpu32 (sb
->alloc_group_shift
);
486 sb
->block_per_group
= grub_afs_to_cpu32 (sb
->block_per_group
);
487 sb
->alloc_group_count
= grub_afs_to_cpu32 (sb
->alloc_group_count
);
488 sb
->log_size
= grub_afs_to_cpu32 (sb
->log_size
);
493 if ((sb
->magic2
!= GRUB_AFS_SBLOCK_MAGIC2
) ||
494 (sb
->magic3
!= GRUB_AFS_SBLOCK_MAGIC3
))
498 sb
->block_per_group
= 1 << (sb
->alloc_group_shift
);
501 if (((grub_uint32_t
) (1 << sb
->block_shift
) != sb
->block_size
)
502 || (sb
->used_blocks
> sb
->num_blocks
)
503 || (sb
->inode_size
!= sb
->block_size
)
504 || (0 == sb
->block_size
)
506 || ((grub_uint32_t
) (1 << sb
->alloc_group_shift
) !=
507 sb
->block_per_group
* sb
->block_size
)
508 || (sb
->alloc_group_count
* sb
->block_per_group
< sb
->num_blocks
)
509 || (grub_afs_to_cpu16 (sb
->log_block
.len
) != sb
->log_size
)
510 || (grub_afs_to_cpu32 (sb
->valid_log_blocks
) > sb
->log_size
)
518 static struct grub_afs_data
*
519 grub_afs_mount (grub_disk_t disk
)
521 struct grub_afs_data
*data
= 0;
523 data
= grub_malloc (sizeof (struct grub_afs_data
));
527 /* Read the superblock. */
528 if (grub_disk_read (disk
, GRUB_AFS_SBLOCK_SECTOR
, 0,
529 sizeof (struct grub_afs_sblock
), &data
->sblock
))
532 if (! grub_afs_validate_sblock (&data
->sblock
))
535 data
->diropen
.data
= data
;
536 data
->inode
= &data
->diropen
.inode
;
539 if (grub_afs_read_inode (data
,
540 grub_afs_run_to_num (&data
->sblock
,
541 &data
->sblock
.root_dir
),
548 grub_error (GRUB_ERR_BAD_FS
, "not an " GRUB_AFS_FSNAME
" filesystem");
555 grub_afs_open (struct grub_file
*file
, const char *name
)
557 struct grub_afs_data
*data
;
558 struct grub_fshelp_node
*fdiro
= 0;
560 grub_dl_ref (my_mod
);
562 data
= grub_afs_mount (file
->device
->disk
);
566 grub_fshelp_find_file (name
, &data
->diropen
, &fdiro
, grub_afs_iterate_dir
,
567 grub_afs_read_symlink
, GRUB_FSHELP_REG
);
571 grub_memcpy (data
->inode
, &fdiro
->inode
, sizeof (struct grub_afs_inode
));
574 file
->size
= grub_afs_to_cpu64 (data
->inode
->stream
.size
);
583 grub_dl_unref (my_mod
);
589 grub_afs_read (grub_file_t file
, char *buf
, grub_size_t len
)
591 struct grub_afs_data
*data
= (struct grub_afs_data
*) file
->data
;
593 return grub_afs_read_file (&data
->diropen
, file
->read_hook
,
594 file
->offset
, len
, buf
);
598 grub_afs_close (grub_file_t file
)
600 grub_free (file
->data
);
602 grub_dl_unref (my_mod
);
604 return GRUB_ERR_NONE
;
608 grub_afs_dir (grub_device_t device
, const char *path
,
609 int (*hook
) (const char *filename
,
610 const struct grub_dirhook_info
*info
))
612 struct grub_afs_data
*data
= 0;
613 struct grub_fshelp_node
*fdiro
= 0;
615 auto int NESTED_FUNC_ATTR
iterate (const char *filename
,
616 enum grub_fshelp_filetype filetype
,
617 grub_fshelp_node_t node
);
619 int NESTED_FUNC_ATTR
iterate (const char *filename
,
620 enum grub_fshelp_filetype filetype
,
621 grub_fshelp_node_t node
)
623 struct grub_dirhook_info info
;
624 grub_memset (&info
, 0, sizeof (info
));
625 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
628 info
.mtime
= grub_afs_to_cpu64 (node
->inode
.modified_time
) >> 16;
630 info
.mtime
= grub_divmod64 (grub_afs_to_cpu64 (node
->inode
.modified_time
),
634 return hook (filename
, &info
);
637 grub_dl_ref (my_mod
);
639 data
= grub_afs_mount (device
->disk
);
643 grub_fshelp_find_file (path
, &data
->diropen
, &fdiro
, grub_afs_iterate_dir
,
644 grub_afs_read_symlink
, GRUB_FSHELP_DIR
);
648 grub_afs_iterate_dir (fdiro
, iterate
);
650 if (fdiro
!= &data
->diropen
)
656 grub_dl_unref (my_mod
);
662 grub_afs_label (grub_device_t device
, char **label
)
664 struct grub_afs_data
*data
;
665 grub_disk_t disk
= device
->disk
;
667 grub_dl_ref (my_mod
);
669 data
= grub_afs_mount (disk
);
671 *label
= grub_strndup (data
->sblock
.name
, sizeof (data
->sblock
.name
));
675 grub_dl_unref (my_mod
);
683 static struct grub_fs grub_afs_fs
= {
684 .name
= GRUB_AFS_FSNAME
,
686 .open
= grub_afs_open
,
687 .read
= grub_afs_read
,
688 .close
= grub_afs_close
,
689 .label
= grub_afs_label
,
693 #if defined (MODE_BIGENDIAN) && defined (MODE_BFS)
694 GRUB_MOD_INIT (befs_be
)
695 #elif defined (MODE_BFS)
697 #elif defined (MODE_BIGENDIAN)
698 GRUB_MOD_INIT (afs_be
)
703 grub_fs_register (&grub_afs_fs
);
707 #if defined (MODE_BIGENDIAN) && defined (MODE_BFS)
708 GRUB_MOD_FINI (befs_be
)
709 #elif defined (MODE_BFS)
711 #elif defined (MODE_BIGENDIAN)
712 GRUB_MOD_FINI (afs_be
)
717 grub_fs_unregister (&grub_afs_fs
);