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);