URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k/trunk/linux/linux-2.4/fs/befs
- from Rev 1275 to Rev 1765
- ↔ Reverse comparison
Rev 1275 → Rev 1765
/inode.c
0,0 → 1,53
/* |
* inode.c |
* |
* Copyright (C) 2001 Will Dyson <will_dyson@pobox.com> |
*/ |
|
#include <linux/fs.h> |
|
#include "befs.h" |
#include "inode.h" |
#include "endian.h" |
|
/* |
Validates the correctness of the befs inode |
Returns BEFS_OK if the inode should be used, otherwise |
returns BEFS_BAD_INODE |
*/ |
int |
befs_check_inode(struct super_block *sb, befs_inode * raw_inode, |
befs_blocknr_t inode) |
{ |
u32 magic1 = fs32_to_cpu(sb, raw_inode->magic1); |
befs_inode_addr ino_num = fsrun_to_cpu(sb, raw_inode->inode_num); |
u32 flags = fs32_to_cpu(sb, raw_inode->flags); |
|
/* check magic header. */ |
if (magic1 != BEFS_INODE_MAGIC1) { |
befs_error(sb, |
"Inode has a bad magic header - inode = %lu", inode); |
return BEFS_BAD_INODE; |
} |
|
/* |
* Sanity check2: inodes store their own block address. Check it. |
*/ |
if (inode != iaddr2blockno(sb, &ino_num)) { |
befs_error(sb, "inode blocknr field disagrees with vfs " |
"VFS: %lu, Inode %lu", |
inode, iaddr2blockno(sb, &ino_num)); |
return BEFS_BAD_INODE; |
} |
|
/* |
* check flag |
*/ |
|
if (!(flags & BEFS_INODE_IN_USE)) { |
befs_error(sb, "inode is not used - inode = %lu", inode); |
return BEFS_BAD_INODE; |
} |
|
return BEFS_OK; |
} |
/super.c
0,0 → 1,112
/* |
* super.c |
* |
* Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com> |
* |
* Licensed under the GNU GPL. See the file COPYING for details. |
* |
*/ |
|
#include <linux/fs.h> |
|
#include "befs.h" |
#include "super.h" |
#include "endian.h" |
|
/** |
* load_befs_sb -- Read from disk and properly byteswap all the fields |
* of the befs superblock |
* |
* |
* |
* |
*/ |
int |
befs_load_sb(struct super_block *sb, befs_super_block * disk_sb) |
{ |
befs_sb_info *befs_sb = BEFS_SB(sb); |
|
/* Check the byte order of the filesystem */ |
if (le32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE) |
befs_sb->byte_order = BEFS_BYTESEX_LE; |
else if (be32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE) |
befs_sb->byte_order = BEFS_BYTESEX_BE; |
|
befs_sb->magic1 = fs32_to_cpu(sb, disk_sb->magic1); |
befs_sb->magic2 = fs32_to_cpu(sb, disk_sb->magic2); |
befs_sb->magic3 = fs32_to_cpu(sb, disk_sb->magic3); |
befs_sb->block_size = fs32_to_cpu(sb, disk_sb->block_size); |
befs_sb->block_shift = fs32_to_cpu(sb, disk_sb->block_shift); |
befs_sb->num_blocks = fs64_to_cpu(sb, disk_sb->num_blocks); |
befs_sb->used_blocks = fs64_to_cpu(sb, disk_sb->used_blocks); |
befs_sb->inode_size = fs32_to_cpu(sb, disk_sb->inode_size); |
|
befs_sb->blocks_per_ag = fs32_to_cpu(sb, disk_sb->blocks_per_ag); |
befs_sb->ag_shift = fs32_to_cpu(sb, disk_sb->ag_shift); |
befs_sb->num_ags = fs32_to_cpu(sb, disk_sb->num_ags); |
|
befs_sb->log_blocks = fsrun_to_cpu(sb, disk_sb->log_blocks); |
befs_sb->log_start = fs64_to_cpu(sb, disk_sb->log_start); |
befs_sb->log_end = fs64_to_cpu(sb, disk_sb->log_end); |
|
befs_sb->root_dir = fsrun_to_cpu(sb, disk_sb->root_dir); |
befs_sb->indices = fsrun_to_cpu(sb, disk_sb->indices); |
befs_sb->nls = NULL; |
|
return BEFS_OK; |
} |
|
int |
befs_check_sb(struct super_block *sb) |
{ |
befs_sb_info *befs_sb = BEFS_SB(sb); |
|
/* Check magic headers of super block */ |
if ((befs_sb->magic1 != BEFS_SUPER_MAGIC1) |
|| (befs_sb->magic2 != BEFS_SUPER_MAGIC2) |
|| (befs_sb->magic3 != BEFS_SUPER_MAGIC3)) { |
befs_error(sb, "invalid magic header"); |
return BEFS_ERR; |
} |
|
/* |
* Check blocksize of BEFS. |
* |
* Blocksize of BEFS is 1024, 2048, 4096 or 8192. |
*/ |
|
if ((befs_sb->block_size != 1024) |
&& (befs_sb->block_size != 2048) |
&& (befs_sb->block_size != 4096) |
&& (befs_sb->block_size != 8192)) { |
befs_error(sb, "invalid blocksize: %u", befs_sb->block_size); |
return BEFS_ERR; |
} |
|
if (befs_sb->block_size > PAGE_SIZE) { |
befs_error(sb, "blocksize(%u) cannot be larger" |
"than system pagesize(%lu)", befs_sb->block_size, |
PAGE_SIZE); |
return BEFS_ERR; |
} |
|
/* |
* block_shift and block_size encode the same information |
* in different ways as a consistency check. |
*/ |
|
if ((1 << befs_sb->block_shift) != befs_sb->block_size) { |
befs_error(sb, "block_shift disagrees with block_size. " |
"Corruption likely."); |
return BEFS_ERR; |
} |
|
if (befs_sb->log_start != befs_sb->log_end) { |
befs_error(sb, "Filesystem not clean! There are blocks in the " |
"journal. You must boot into BeOS and mount this volume " |
"to make it clean."); |
return BEFS_ERR; |
} |
|
return BEFS_OK; |
} |
/befs_fs_types.h
0,0 → 1,213
/* |
* include/linux/befs_fs_types.h |
* |
* Copyright (C) 2001 Will Dyson (will@cs.earlham.edu) |
* |
* |
* |
* from linux/include/linux/befs_fs.h |
* |
* Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp) |
* |
*/ |
|
#ifndef _LINUX_BEFS_FS_TYPES |
#define _LINUX_BEFS_FS_TYPES |
|
#ifdef __KERNEL__ |
#include <linux/types.h> |
#endif /*__KERNEL__*/ |
|
#define PACKED __attribute__ ((__packed__)) |
|
/* |
* Max name lengths of BFS |
*/ |
|
#define BEFS_NAME_LEN 255 |
|
#define BEFS_SYMLINK_LEN 144 |
#define BEFS_NUM_DIRECT_BLOCKS 12 |
#define B_OS_NAME_LENGTH 32 |
|
/* The datastream blocks mapped by the double-indirect |
* block are always 4 fs blocks long. |
* This eliminates the need for linear searches among |
* the potentially huge number of indirect blocks |
* |
* Err. Should that be 4 fs blocks or 4k??? |
* It matters on large blocksize volumes |
*/ |
#define BEFS_DBLINDIR_BRUN_LEN 4 |
|
/* |
* Flags of superblock |
*/ |
|
enum super_flags { |
BEFS_BYTESEX_BE, |
BEFS_BYTESEX_LE, |
BEFS_CLEAN = 0x434c454e, |
BEFS_DIRTY = 0x44495254, |
BEFS_SUPER_MAGIC1 = 0x42465331, /* BFS1 */ |
BEFS_SUPER_MAGIC2 = 0xdd121031, |
BEFS_SUPER_MAGIC3 = 0x15b6830e, |
}; |
|
#define BEFS_BYTEORDER_NATIVE 0x42494745 |
|
#define BEFS_SUPER_MAGIC BEFS_SUPER_MAGIC1 |
|
/* |
* Flags of inode |
*/ |
|
#define BEFS_INODE_MAGIC1 0x3bbe0ad9 |
|
enum inode_flags { |
BEFS_INODE_IN_USE = 0x00000001, |
BEFS_ATTR_INODE = 0x00000004, |
BEFS_INODE_LOGGED = 0x00000008, |
BEFS_INODE_DELETED = 0x00000010, |
BEFS_LONG_SYMLINK = 0x00000040, |
BEFS_PERMANENT_FLAG = 0x0000ffff, |
BEFS_INODE_NO_CREATE = 0x00010000, |
BEFS_INODE_WAS_WRITTEN = 0x00020000, |
BEFS_NO_TRANSACTION = 0x00040000, |
}; |
/* |
* On-Disk datastructures of BeFS |
*/ |
|
typedef u64 befs_off_t; |
typedef u64 befs_time_t; |
typedef void befs_binode_etc; |
|
/* Block runs */ |
typedef struct { |
u32 allocation_group; |
u16 start; |
u16 len; |
} PACKED befs_block_run; |
|
typedef befs_block_run befs_inode_addr; |
|
/* |
* The Superblock Structure |
*/ |
typedef struct { |
char name[B_OS_NAME_LENGTH]; |
u32 magic1; |
u32 fs_byte_order; |
|
u32 block_size; |
u32 block_shift; |
|
befs_off_t num_blocks; |
befs_off_t used_blocks; |
|
u32 inode_size; |
|
u32 magic2; |
u32 blocks_per_ag; |
u32 ag_shift; |
u32 num_ags; |
|
u32 flags; |
|
befs_block_run log_blocks; |
befs_off_t log_start; |
befs_off_t log_end; |
|
u32 magic3; |
befs_inode_addr root_dir; |
befs_inode_addr indices; |
|
} PACKED befs_super_block; |
|
/* |
* Note: the indirect and dbl_indir block_runs may |
* be longer than one block! |
*/ |
typedef struct { |
befs_block_run direct[BEFS_NUM_DIRECT_BLOCKS]; |
befs_off_t max_direct_range; |
befs_block_run indirect; |
befs_off_t max_indirect_range; |
befs_block_run double_indirect; |
befs_off_t max_double_indirect_range; |
befs_off_t size; |
} PACKED befs_data_stream; |
|
/* Attribute */ |
typedef struct { |
u32 type; |
u16 name_size; |
u16 data_size; |
char name[1]; |
} PACKED befs_small_data; |
|
/* Inode structure */ |
typedef struct { |
u32 magic1; |
befs_inode_addr inode_num; |
u32 uid; |
u32 gid; |
u32 mode; |
u32 flags; |
befs_time_t create_time; |
befs_time_t last_modified_time; |
befs_inode_addr parent; |
befs_inode_addr attributes; |
u32 type; |
|
u32 inode_size; |
u32 etc; /* not use */ |
|
union { |
befs_data_stream datastream; |
char symlink[BEFS_SYMLINK_LEN]; |
} data; |
|
u32 pad[4]; /* not use */ |
befs_small_data small_data[1]; |
} PACKED befs_inode; |
|
/* |
* B+tree superblock |
*/ |
|
#define BEFS_BTREE_MAGIC 0x69f6c2e8 |
|
enum btree_types { |
BTREE_STRING_TYPE = 0, |
BTREE_INT32_TYPE = 1, |
BTREE_UINT32_TYPE = 2, |
BTREE_INT64_TYPE = 3, |
BTREE_UINT64_TYPE = 4, |
BTREE_FLOAT_TYPE = 5, |
BTREE_DOUBLE_TYPE = 6 |
}; |
|
typedef struct { |
u32 magic; |
u32 node_size; |
u32 max_depth; |
u32 data_type; |
befs_off_t root_node_ptr; |
befs_off_t free_node_ptr; |
befs_off_t max_size; |
} PACKED befs_btree_super; |
|
/* |
* Header stucture of each btree node |
*/ |
typedef struct { |
befs_off_t left; |
befs_off_t right; |
befs_off_t overflow; |
u16 all_key_count; |
u16 all_key_length; |
} PACKED befs_btree_nodehead; |
|
#endif /* _LINUX_BEFS_FS_TYPES */ |
/btree.c
0,0 → 1,785
/* |
* linux/fs/befs/btree.c |
* |
* Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com> |
* |
* Licensed under the GNU GPL. See the file COPYING for details. |
* |
* 2002-02-05: Sergey S. Kostyliov added binary search withing |
* btree nodes. |
* |
* Many thanks to: |
* |
* Dominic Giampaolo, author of "Practical File System |
* Design with the Be File System", for such a helpful book. |
* |
* Marcus J. Ranum, author of the b+tree package in |
* comp.sources.misc volume 10. This code is not copied from that |
* work, but it is partially based on it. |
* |
* Makoto Kato, author of the original BeFS for linux filesystem |
* driver. |
*/ |
|
#include <linux/kernel.h> |
#include <linux/string.h> |
#include <linux/slab.h> |
#include <linux/mm.h> |
|
#include "befs.h" |
#include "btree.h" |
#include "datastream.h" |
#include "endian.h" |
|
/* |
* The btree functions in this file are built on top of the |
* datastream.c interface, which is in turn built on top of the |
* io.c interface. |
*/ |
|
/* Befs B+tree structure: |
* |
* The first thing in the tree is the tree superblock. It tells you |
* all kinds of usefull things about the tree, like where the rootnode |
* is located, and the size of the nodes (always 1024 with current version |
* of BeOS). |
* |
* The rest of the tree consists of a series of nodes. Nodes contain a header |
* (struct befs_btree_nodehead), the packed key data, an array of shorts |
* containing the ending offsets for each of the keys, and an array of |
* befs_off_t values. In interior nodes, the keys are the ending keys for |
* the childnode they point to, and the values are offsets into the |
* datastream containing the tree. |
*/ |
|
/* Note: |
* |
* The book states 2 confusing things about befs b+trees. First, |
* it states that the overflow feild of node headers is used by internal nodes |
* to point to another node that "effectivly continues this one". Here is what |
* I belive that means. Each key in internal nodes points to another node that |
* contains key values less than itself. Inspection reveals that the last key |
* in the internal node is not the last key in the index. Keys that are |
* greater than the last key in the internal node go into the overflow node. |
* I imagine there is a performance reason for this. |
* |
* Second, it states that the header of a btree node is sufficient to |
* distinguish internal nodes from leaf nodes. Without saying exactly how. |
* After figuring out the first, it becomes obvious that internal nodes have |
* overflow nodes and leafnodes do not. |
*/ |
|
/* |
* Currently, this code is only good for directory B+trees. |
* In order to be used for other BFS indexes, it needs to be extended to handle |
* duplicate keys and non-string keytypes (int32, int64, float, double). |
*/ |
|
/* |
* In memory structure of each btree node |
*/ |
typedef struct { |
befs_btree_nodehead head; /* head of node converted to cpu byteorder */ |
struct buffer_head *bh; |
befs_btree_nodehead *od_node; /* on disk node */ |
} befs_btree_node; |
|
/* local constants */ |
const static befs_off_t befs_bt_inval = 0xffffffffffffffff; |
|
/* local functions */ |
static int befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds, |
befs_btree_super * bt_super, |
befs_btree_node * this_node, |
befs_off_t * node_off); |
|
static int befs_bt_read_super(struct super_block *sb, befs_data_stream * ds, |
befs_btree_super * sup); |
|
static int befs_bt_read_node(struct super_block *sb, befs_data_stream * ds, |
befs_btree_node * node, befs_off_t node_off); |
|
static int befs_leafnode(befs_btree_node * node); |
|
static u16 *befs_bt_keylen_index(befs_btree_node * node); |
|
static befs_off_t *befs_bt_valarray(befs_btree_node * node); |
|
static char *befs_bt_keydata(befs_btree_node * node); |
|
static int befs_find_key(struct super_block *sb, befs_btree_node * node, |
const char *findkey, befs_off_t * value); |
|
static char *befs_bt_get_key(struct super_block *sb, befs_btree_node * node, |
int index, u16 * keylen); |
|
static int befs_compare_strings(const void *key1, int keylen1, |
const void *key2, int keylen2); |
|
/** |
* befs_bt_read_super - read in btree superblock convert to cpu byteorder |
* @sb: Filesystem superblock |
* @ds: Datastream to read from |
* @sup: Buffer in which to place the btree superblock |
* |
* Calls befs_read_datastream to read in the btree superblock and |
* makes sure it is in cpu byteorder, byteswapping if nessisary. |
* |
* On success, returns BEFS_OK and *@sup contains the btree superblock, |
* in cpu byte order. |
* |
* On failure, BEFS_ERR is returned. |
*/ |
static int |
befs_bt_read_super(struct super_block *sb, befs_data_stream * ds, |
befs_btree_super * sup) |
{ |
struct buffer_head *bh = NULL; |
befs_btree_super *od_sup = NULL; |
|
befs_debug(sb, "---> befs_btree_read_super()"); |
|
bh = befs_read_datastream(sb, ds, 0, NULL); |
|
if (!bh) { |
befs_error(sb, "Couldn't read index header."); |
goto error; |
} |
od_sup = (befs_btree_super *) bh->b_data; |
befs_dump_index_entry(sb, od_sup); |
|
sup->magic = fs32_to_cpu(sb, od_sup->magic); |
sup->node_size = fs32_to_cpu(sb, od_sup->node_size); |
sup->max_depth = fs32_to_cpu(sb, od_sup->max_depth); |
sup->data_type = fs32_to_cpu(sb, od_sup->data_type); |
sup->root_node_ptr = fs64_to_cpu(sb, od_sup->root_node_ptr); |
sup->free_node_ptr = fs64_to_cpu(sb, od_sup->free_node_ptr); |
sup->max_size = fs64_to_cpu(sb, od_sup->max_size); |
|
brelse(bh); |
if (sup->magic != BEFS_BTREE_MAGIC) { |
befs_error(sb, "Index header has bad magic."); |
goto error; |
} |
|
befs_debug(sb, "<--- befs_btree_read_super()"); |
return BEFS_OK; |
|
error: |
befs_debug(sb, "<--- befs_btree_read_super() ERROR"); |
return BEFS_ERR; |
} |
|
/** |
* befs_bt_read_node - read in btree node and convert to cpu byteorder |
* @sb: Filesystem superblock |
* @ds: Datastream to read from |
* @node: Buffer in which to place the btree node |
* @node_off: Starting offset (in bytes) of the node in @ds |
* |
* Calls befs_read_datastream to read in the indicated btree node and |
* makes sure its header feilds are in cpu byteorder, byteswapping if |
* nessisary. |
* Note: node->bh must be NULL when this function called first |
* time. Don't forget brelse(node->bh) after last call. |
* |
* On success, returns BEFS_OK and *@node contains the btree node that |
* starts at @node_off, with the node->head fields in cpu byte order. |
* |
* On failure, BEFS_ERR is returned. |
*/ |
|
static int |
befs_bt_read_node(struct super_block *sb, befs_data_stream * ds, |
befs_btree_node * node, befs_off_t node_off) |
{ |
uint off = 0; |
|
befs_debug(sb, "---> befs_bt_read_node()"); |
|
if (node->bh) |
brelse(node->bh); |
|
node->bh = befs_read_datastream(sb, ds, node_off, &off); |
if (!node->bh) { |
befs_error(sb, "befs_bt_read_node() failed to read " |
"node at %Lu", node_off); |
befs_debug(sb, "<--- befs_bt_read_node() ERROR"); |
|
return BEFS_ERR; |
} |
node->od_node = |
(befs_btree_nodehead *) ((void *) node->bh->b_data + off); |
|
befs_dump_index_node(sb, node->od_node); |
|
node->head.left = fs64_to_cpu(sb, node->od_node->left); |
node->head.right = fs64_to_cpu(sb, node->od_node->right); |
node->head.overflow = fs64_to_cpu(sb, node->od_node->overflow); |
node->head.all_key_count = |
fs16_to_cpu(sb, node->od_node->all_key_count); |
node->head.all_key_length = |
fs16_to_cpu(sb, node->od_node->all_key_length); |
|
befs_debug(sb, "<--- befs_btree_read_node()"); |
return BEFS_OK; |
} |
|
/** |
* befs_btree_find - Find a key in a befs B+tree |
* @sb: Filesystem superblock |
* @ds: Datastream containing btree |
* @key: Key string to lookup in btree |
* @value: Value stored with @key |
* |
* On sucess, returns BEFS_OK and sets *@value to the value stored |
* with @key (usually the disk block number of an inode). |
* |
* On failure, returns BEFS_ERR or BEFS_BT_NOT_FOUND. |
* |
* Algorithm: |
* Read the superblock and rootnode of the b+tree. |
* Drill down through the interior nodes using befs_find_key(). |
* Once at the correct leaf node, use befs_find_key() again to get the |
* actuall value stored with the key. |
*/ |
int |
befs_btree_find(struct super_block *sb, befs_data_stream * ds, |
const char *key, befs_off_t * value) |
{ |
befs_btree_node *this_node = NULL; |
befs_btree_super bt_super; |
befs_off_t node_off; |
int res; |
|
befs_debug(sb, "---> befs_btree_find() Key: %s", key); |
|
if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) { |
befs_error(sb, |
"befs_btree_find() failed to read index superblock"); |
goto error; |
} |
|
this_node = (befs_btree_node *) kmalloc(sizeof (befs_btree_node), |
GFP_NOFS); |
if (!this_node) { |
befs_error(sb, "befs_btree_find() failed to allocate %u " |
"bytes of memory", sizeof (befs_btree_node)); |
goto error; |
} |
|
this_node->bh = NULL; |
|
/* read in root node */ |
node_off = bt_super.root_node_ptr; |
if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) { |
befs_error(sb, "befs_btree_find() failed to read " |
"node at %Lu", node_off); |
goto error_alloc; |
} |
|
while (!befs_leafnode(this_node)) { |
res = befs_find_key(sb, this_node, key, &node_off); |
if (res == BEFS_BT_NOT_FOUND) |
node_off = this_node->head.overflow; |
/* if no match, go to overflow node */ |
if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) { |
befs_error(sb, "befs_btree_find() failed to read " |
"node at %Lu", node_off); |
goto error_alloc; |
} |
} |
|
/* at the correct leaf node now */ |
|
res = befs_find_key(sb, this_node, key, value); |
|
brelse(this_node->bh); |
kfree(this_node); |
|
if (res != BEFS_BT_MATCH) { |
befs_debug(sb, "<--- befs_btree_find() Key %s not found", key); |
*value = 0; |
return BEFS_BT_NOT_FOUND; |
} |
befs_debug(sb, "<--- befs_btree_find() Found key %s, value %Lu", |
key, *value); |
return BEFS_OK; |
|
error_alloc: |
kfree(this_node); |
error: |
*value = 0; |
befs_debug(sb, "<--- befs_btree_find() ERROR"); |
return BEFS_ERR; |
} |
|
/** |
* befs_find_key - Search for a key within a node |
* @sb: Filesystem superblock |
* @node: Node to find the key within |
* @key: Keystring to search for |
* @value: If key is found, the value stored with the key is put here |
* |
* finds exact match if one exists, and returns BEFS_BT_MATCH |
* If no exact match, finds first key in node that is greater |
* (alpabeticly) than the search key and returns BEFS_BT_PARMATCH |
* (for partial match, I guess). Can you think of something better to |
* call it? |
* |
* If no key was a match or greater than the search key, return |
* BEFS_BT_NOT_FOUND. |
* |
* Use binary search instead of a linear. |
*/ |
static int |
befs_find_key(struct super_block *sb, befs_btree_node * node, |
const char *findkey, befs_off_t * value) |
{ |
int first, last, mid; |
int eq; |
u16 keylen; |
int findkey_len; |
char *thiskey; |
befs_off_t *valarray; |
|
befs_debug(sb, "---> befs_find_key() %s", findkey); |
|
*value = 0; |
|
findkey_len = strlen(findkey); |
|
/* if node can not contain key, just skeep this node */ |
last = node->head.all_key_count - 1; |
thiskey = befs_bt_get_key(sb, node, last, &keylen); |
|
eq = befs_compare_strings(thiskey, keylen, findkey, findkey_len); |
if (eq < 0) { |
befs_debug(sb, "<--- befs_find_key() %s not found", findkey); |
return BEFS_BT_NOT_FOUND; |
} |
|
valarray = befs_bt_valarray(node); |
|
/* simple binary search */ |
first = 0; |
mid = 0; |
while (last >= first) { |
mid = (last + first) / 2; |
befs_debug(sb, "first: %d, last: %d, mid: %d", first, last, |
mid); |
thiskey = befs_bt_get_key(sb, node, mid, &keylen); |
eq = befs_compare_strings(thiskey, keylen, findkey, |
findkey_len); |
*value = fs64_to_cpu(sb, valarray[mid]); |
|
if (eq == 0) { |
befs_debug(sb, "<--- befs_find_key() found %s at %d", |
thiskey, mid); |
|
return BEFS_BT_MATCH; |
} |
if (eq > 0) |
last = mid - 1; |
else |
first = mid + 1; |
} |
if (eq < 0) |
*value = fs64_to_cpu(sb, valarray[mid + 1]); |
befs_debug(sb, "<--- befs_find_key() found %s at %d", thiskey, mid); |
return BEFS_BT_PARMATCH; |
} |
|
/** |
* befs_btree_read - Traverse leafnodes of a btree |
* @sb: Filesystem superblock |
* @ds: Datastream containing btree |
* @key_no: Key number (alphabetical order) of key to read |
* @bufsize: Size of the buffer to return key in |
* @keybuf: Pointer to a buffer to put the key in |
* @keysize: Length of the returned key |
* @value: Value stored with the returned key |
* |
* Heres how it works: Key_no is the index of the key/value pair to |
* retun in keybuf/value. |
* Bufsize is the size of keybuf (BEFS_NAME_LEN+1 is a good size). Keysize is |
* the number of charecters in the key (just a convience). |
* |
* Algorithm: |
* Get the first leafnode of the tree. See if the requested key is in that |
* node. If not, follow the node->right link to the next leafnode. Repeat |
* until the (key_no)th key is found or the tree is out of keys. |
*/ |
int |
befs_btree_read(struct super_block *sb, befs_data_stream * ds, |
loff_t key_no, size_t bufsize, char *keybuf, size_t * keysize, |
befs_off_t * value) |
{ |
befs_btree_node *this_node; |
befs_btree_super bt_super; |
befs_off_t node_off = 0; |
int cur_key; |
befs_off_t *valarray; |
char *keystart; |
u16 keylen; |
int res; |
|
uint key_sum = 0; |
|
befs_debug(sb, "---> befs_btree_read()"); |
|
if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) { |
befs_error(sb, |
"befs_btree_read() failed to read index superblock"); |
goto error; |
} |
|
if ((this_node = (befs_btree_node *) |
kmalloc(sizeof (befs_btree_node), GFP_NOFS)) == NULL) { |
befs_error(sb, "befs_btree_read() failed to allocate %u " |
"bytes of memory", sizeof (befs_btree_node)); |
goto error; |
} |
|
node_off = bt_super.root_node_ptr; |
this_node->bh = NULL; |
|
/* seeks down to first leafnode, reads it into this_node */ |
res = befs_btree_seekleaf(sb, ds, &bt_super, this_node, &node_off); |
if (res == BEFS_BT_EMPTY) { |
brelse(this_node->bh); |
kfree(this_node); |
*value = 0; |
*keysize = 0; |
befs_debug(sb, "<--- befs_btree_read() Tree is EMPTY"); |
return BEFS_BT_EMPTY; |
} else if (res == BEFS_ERR) { |
goto error_alloc; |
} |
|
/* find the leaf node containing the key_no key */ |
|
while (key_sum + this_node->head.all_key_count <= key_no) { |
|
/* no more nodes to look in: key_no is too large */ |
if (this_node->head.right == befs_bt_inval) { |
*keysize = 0; |
*value = 0; |
befs_debug(sb, |
"<--- befs_btree_read() END of keys at %Lu", |
key_sum + this_node->head.all_key_count); |
brelse(this_node->bh); |
kfree(this_node); |
return BEFS_BT_END; |
} |
|
key_sum += this_node->head.all_key_count; |
node_off = this_node->head.right; |
|
if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) { |
befs_error(sb, "befs_btree_read() failed to read " |
"node at %Lu", node_off); |
goto error_alloc; |
} |
} |
|
/* how many keys into this_node is key_no */ |
cur_key = key_no - key_sum; |
|
/* get pointers to datastructures within the node body */ |
valarray = befs_bt_valarray(this_node); |
|
keystart = befs_bt_get_key(sb, this_node, cur_key, &keylen); |
|
befs_debug(sb, "Read [%Lu,%d]: keysize %d", node_off, cur_key, keylen); |
|
if (bufsize < keylen + 1) { |
befs_error(sb, "befs_btree_read() keybuf too small (%u) " |
"for key of size %d", bufsize, keylen); |
brelse(this_node->bh); |
goto error_alloc; |
}; |
|
strncpy(keybuf, keystart, keylen); |
*value = fs64_to_cpu(sb, valarray[cur_key]); |
*keysize = keylen; |
keybuf[keylen] = '\0'; |
|
befs_debug(sb, "Read [%Lu,%d]: Key \"%.*s\", Value %Lu", node_off, |
cur_key, keylen, keybuf, *value); |
|
brelse(this_node->bh); |
kfree(this_node); |
|
befs_debug(sb, "<--- befs_btree_read()"); |
|
return BEFS_OK; |
|
error_alloc: |
kfree(this_node); |
|
error: |
*keysize = 0; |
*value = 0; |
befs_debug(sb, "<--- befs_btree_read() ERROR"); |
return BEFS_ERR; |
} |
|
/** |
* befs_btree_seekleaf - Find the first leafnode in the btree |
* @sb: Filesystem superblock |
* @ds: Datastream containing btree |
* @bt_super: Pointer to the uperblock of the btree |
* @this_node: Buffer to return the leafnode in |
* @node_off: Pointer to offset of current node within datastream. Modified |
* by the function. |
* |
* |
* Helper function for btree traverse. Moves the current position to the |
* start of the first leaf node. |
* |
* Also checks for an empty tree. If there are no keys, returns BEFS_BT_EMPTY. |
*/ |
static int |
befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds, |
befs_btree_super * bt_super, befs_btree_node * this_node, |
befs_off_t * node_off) |
{ |
|
befs_debug(sb, "---> befs_btree_seekleaf()"); |
|
if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) { |
befs_error(sb, "befs_btree_seekleaf() failed to read " |
"node at %Lu", *node_off); |
goto error; |
} |
befs_debug(sb, "Seekleaf to root node %Lu", *node_off); |
|
if (this_node->head.all_key_count == 0 && befs_leafnode(this_node)) { |
befs_debug(sb, "<--- befs_btree_seekleaf() Tree is EMPTY"); |
return BEFS_BT_EMPTY; |
} |
|
while (!befs_leafnode(this_node)) { |
|
if (this_node->head.all_key_count == 0) { |
befs_debug(sb, "befs_btree_seekleaf() encountered " |
"an empty interior node: %Lu. Using Overflow " |
"node: %Lu", *node_off, |
this_node->head.overflow); |
*node_off = this_node->head.overflow; |
} else { |
befs_off_t *valarray = befs_bt_valarray(this_node); |
*node_off = fs64_to_cpu(sb, valarray[0]); |
} |
if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) { |
befs_error(sb, "befs_btree_seekleaf() failed to read " |
"node at %Lu", *node_off); |
goto error; |
} |
|
befs_debug(sb, "Seekleaf to child node %Lu", *node_off); |
} |
befs_debug(sb, "Node %Lu is a leaf node", *node_off); |
|
return BEFS_OK; |
|
error: |
befs_debug(sb, "<--- befs_btree_seekleaf() ERROR"); |
return BEFS_ERR; |
} |
|
/** |
* befs_leafnode - Determine if the btree node is a leaf node or an |
* interior node |
* @node: Pointer to node structure to test |
* |
* Return 1 if leaf, 0 if interior |
*/ |
static int |
befs_leafnode(befs_btree_node * node) |
{ |
/* all interior nodes (and only interior nodes) have an overflow node */ |
if (node->head.overflow == befs_bt_inval) |
return 1; |
else |
return 0; |
} |
|
/** |
* befs_bt_keylen_index - Finds start of keylen index in a node |
* @node: Pointer to the node structure to find the keylen index within |
* |
* Returns a pointer to the start of the key length index array |
* of the B+tree node *@node |
* |
* "The length of all the keys in the node is added to the size of the |
* header and then rounded up to a multiple of four to get the begining |
* of the key length index" (p.88, practical filesystem design). |
* |
* Exept that rounding up to 8 works, and rounding up to 4 doesn't. |
*/ |
static u16 * |
befs_bt_keylen_index(befs_btree_node * node) |
{ |
const int keylen_align = 8; |
unsigned long int off = |
(sizeof (befs_btree_nodehead) + node->head.all_key_length); |
ulong tmp = off % keylen_align; |
|
if (tmp) |
off += keylen_align - tmp; |
|
return (u16 *) ((void *) node->od_node + off); |
} |
|
/** |
* befs_bt_valarray - Finds the start of value array in a node |
* @node: Pointer to the node structure to find the value array within |
* |
* Returns a pointer to the start of the value array |
* of the node pointed to by the node header |
*/ |
static befs_off_t * |
befs_bt_valarray(befs_btree_node * node) |
{ |
void *keylen_index_start = (void *) befs_bt_keylen_index(node); |
size_t keylen_index_size = node->head.all_key_count * sizeof (u16); |
|
return (befs_off_t *) (keylen_index_start + keylen_index_size); |
} |
|
/** |
* befs_bt_keydata - Finds start of keydata array in a node |
* @node: Pointer to the node structure to find the keydata array within |
* |
* Returns a pointer to the start of the keydata array |
* of the node pointed to by the node header |
*/ |
static char * |
befs_bt_keydata(befs_btree_node * node) |
{ |
return (char *) ((void *) node->od_node + sizeof (befs_btree_nodehead)); |
} |
|
/** |
* befs_bt_get_key - returns a pointer to the start of a key |
* @sb: filesystem superblock |
* @node: node in which to look for the key |
* @index: the index of the key to get |
* @keylen: modified to be the length of the key at @index |
* |
* Returns a valid pointer into @node on success. |
* Returns NULL on failure (bad input) and sets *@keylen = 0 |
*/ |
static char * |
befs_bt_get_key(struct super_block *sb, befs_btree_node * node, |
int index, u16 * keylen) |
{ |
int prev_key_end; |
char *keystart; |
u16 *keylen_index; |
|
if (index < 0 || index > node->head.all_key_count) { |
*keylen = 0; |
return NULL; |
} |
|
keystart = befs_bt_keydata(node); |
keylen_index = befs_bt_keylen_index(node); |
|
if (index == 0) |
prev_key_end = 0; |
else |
prev_key_end = fs16_to_cpu(sb, keylen_index[index - 1]); |
|
*keylen = fs16_to_cpu(sb, keylen_index[index]) - prev_key_end; |
|
return keystart + prev_key_end; |
} |
|
/** |
* befs_compare_strings - compare two strings |
* @key1: pointer to the first key to be compared |
* @keylen1: length in bytes of key1 |
* @key2: pointer to the second key to be compared |
* @kelen2: lenght in bytes of key2 |
* |
* Returns 0 if @key1 and @key2 are equal. |
* Returns >0 if @key1 is greater. |
* Returns <0 if @key2 is greater.. |
*/ |
static int |
befs_compare_strings(const void *key1, int keylen1, |
const void *key2, int keylen2) |
{ |
int len = min_t(int, keylen1, keylen2); |
int result = strncmp(key1, key2, len); |
if (result == 0) |
result = keylen1 - keylen2; |
return result; |
} |
|
/* These will be used for non-string keyed btrees */ |
#if 0 |
static int |
btree_compare_int32(cont void *key1, int keylen1, const void *key2, int keylen2) |
{ |
return *(int32_t *) key1 - *(int32_t *) key2; |
} |
|
static int |
btree_compare_uint32(cont void *key1, int keylen1, |
const void *key2, int keylen2) |
{ |
if (*(u_int32_t *) key1 == *(u_int32_t *) key2) |
return 0; |
else if (*(u_int32_t *) key1 > *(u_int32_t *) key2) |
return 1; |
|
return -1; |
} |
static int |
btree_compare_int64(cont void *key1, int keylen1, const void *key2, int keylen2) |
{ |
if (*(int64_t *) key1 == *(int64_t *) key2) |
return 0; |
else if (*(int64_t *) key1 > *(int64_t *) key2) |
return 1; |
|
return -1; |
} |
|
static int |
btree_compare_uint64(cont void *key1, int keylen1, |
const void *key2, int keylen2) |
{ |
if (*(u_int64_t *) key1 == *(u_int64_t *) key2) |
return 0; |
else if (*(u_int64_t *) key1 > *(u_int64_t *) key2) |
return 1; |
|
return -1; |
} |
|
static int |
btree_compare_float(cont void *key1, int keylen1, const void *key2, int keylen2) |
{ |
float result = *(float *) key1 - *(float *) key2; |
if (result == 0.0f) |
return 0; |
|
return (result < 0.0f) ? -1 : 1; |
} |
|
static int |
btree_compare_double(cont void *key1, int keylen1, |
const void *key2, int keylen2) |
{ |
double result = *(double *) key1 - *(double *) key2; |
if (result == 0.0) |
return 0; |
|
return (result < 0.0) ? -1 : 1; |
} |
#endif //0 |
/inode.h
0,0 → 1,7
/* |
* inode.h |
* |
*/ |
|
int befs_check_inode(struct super_block *sb, befs_inode * raw_inode, |
befs_blocknr_t inode); |
/super.h
0,0 → 1,7
/* |
* super.h |
*/ |
|
int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb); |
|
int befs_check_sb(struct super_block *sb); |
/endian.h
0,0 → 1,125
/* |
* linux/fs/befs/endian.h |
* |
* Copyright (C) 2001 Will Dyson <will_dyson@pobox.com> |
* |
* Partially based on similar funtions in the sysv driver. |
*/ |
|
#ifndef LINUX_BEFS_ENDIAN |
#define LINUX_BEFS_ENDIAN |
|
#include <linux/byteorder/generic.h> |
|
static inline u64 |
fs64_to_cpu(const struct super_block *sb, u64 n) |
{ |
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) |
return le64_to_cpu(n); |
else |
return be64_to_cpu(n); |
} |
|
static inline u64 |
cpu_to_fs64(const struct super_block *sb, u64 n) |
{ |
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) |
return cpu_to_le64(n); |
else |
return cpu_to_be64(n); |
} |
|
static inline u32 |
fs32_to_cpu(const struct super_block *sb, u32 n) |
{ |
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) |
return le32_to_cpu(n); |
else |
return be32_to_cpu(n); |
} |
|
static inline u32 |
cpu_to_fs32(const struct super_block *sb, u32 n) |
{ |
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) |
return cpu_to_le32(n); |
else |
return cpu_to_be32(n); |
} |
|
static inline u16 |
fs16_to_cpu(const struct super_block *sb, u16 n) |
{ |
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) |
return le16_to_cpu(n); |
else |
return be16_to_cpu(n); |
} |
|
static inline u16 |
cpu_to_fs16(const struct super_block *sb, u16 n) |
{ |
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) |
return cpu_to_le16(n); |
else |
return cpu_to_be16(n); |
} |
|
/* Composite types below here */ |
|
static inline befs_block_run |
fsrun_to_cpu(const struct super_block *sb, befs_block_run n) |
{ |
befs_block_run run; |
|
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) { |
run.allocation_group = le32_to_cpu(n.allocation_group); |
run.start = le16_to_cpu(n.start); |
run.len = le16_to_cpu(n.len); |
} else { |
run.allocation_group = be32_to_cpu(n.allocation_group); |
run.start = be16_to_cpu(n.start); |
run.len = be16_to_cpu(n.len); |
} |
return run; |
} |
|
static inline befs_block_run |
cpu_to_fsrun(const struct super_block *sb, befs_block_run n) |
{ |
befs_block_run run; |
|
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) { |
run.allocation_group = cpu_to_le32(n.allocation_group); |
run.start = cpu_to_le16(n.start); |
run.len = cpu_to_le16(n.len); |
} else { |
run.allocation_group = cpu_to_be32(n.allocation_group); |
run.start = cpu_to_be16(n.start); |
run.len = cpu_to_be16(n.len); |
} |
return run; |
} |
|
static inline befs_data_stream |
fsds_to_cpu(const struct super_block *sb, befs_data_stream n) |
{ |
befs_data_stream data; |
int i; |
|
for (i = 0; i < BEFS_NUM_DIRECT_BLOCKS; ++i) |
data.direct[i] = fsrun_to_cpu(sb, n.direct[i]); |
|
data.max_direct_range = fs64_to_cpu(sb, n.max_direct_range); |
data.indirect = fsrun_to_cpu(sb, n.indirect); |
data.max_indirect_range = fs64_to_cpu(sb, n.max_indirect_range); |
data.double_indirect = fsrun_to_cpu(sb, n.double_indirect); |
data.max_double_indirect_range = fs64_to_cpu(sb, |
n. |
max_double_indirect_range); |
data.size = fs64_to_cpu(sb, n.size); |
|
return data; |
} |
|
#endif //LINUX_BEFS_ENDIAN |
/attribute.c
0,0 → 1,116
/* |
* linux/fs/befs/attribute.c |
* |
* Copyright (C) 2002 Will Dyson <will_dyson@pobox.com> |
* |
* Many thanks to Dominic Giampaolo, author of "Practical File System |
* Design with the Be File System", for such a helpful book. |
* |
*/ |
|
#include <linux/fs.h> |
#include <linux/kernel.h> |
#include <linux/string.h> |
|
#include "befs.h" |
#include "endian.h" |
|
#define SD_DATA(sd)\ |
(void*)((char*)sd + sizeof(*sd) + (sd->name_size - sizeof(sd->name))) |
|
#define SD_NEXT(sd)\ |
(befs_small_data*)((char*)sd + sizeof(*sd) + (sd->name_size - \ |
sizeof(sd->name) + sd->data_size)) |
|
int |
list_small_data(struct super_block *sb, befs_inode * inode, filldir_t filldir); |
|
befs_small_data *find_small_data(struct super_block *sb, befs_inode * inode, |
const char *name); |
int |
read_small_data(struct super_block *sb, befs_inode * inode, |
befs_small_data * sdata, void *buf, size_t bufsize); |
|
/** |
* |
* |
* |
* |
* |
*/ |
befs_small_data * |
find_small_data(struct super_block *sb, befs_inode * inode, const char *name) |
{ |
befs_small_data *sdata = inode->small_data; |
|
while (sdata->type != 0) { |
if (strcmp(name, sdata->name) != 0) { |
return sdata; |
} |
sdata = SD_NEXT(sdata); |
} |
return NULL; |
} |
|
/** |
* |
* |
* |
* |
* |
*/ |
int |
read_small_data(struct super_block *sb, befs_inode * inode, |
const char *name, void *buf, size_t bufsize) |
{ |
befs_small_data *sdata; |
|
sdata = find_small_data(sb, inode, name); |
if (sdata == NULL) |
return BEFS_ERR; |
else if (sdata->data_size > bufsize) |
return BEFS_ERR; |
|
memcpy(buf, SD_DATA(sdata), sdata->data_size); |
|
return BEFS_OK; |
} |
|
/** |
* |
* |
* |
* |
* |
*/ |
int |
list_small_data(struct super_block *sb, befs_inode * inode) |
{ |
|
} |
|
/** |
* |
* |
* |
* |
* |
*/ |
int |
list_attr(struct super_block *sb, befs_inode * inode) |
{ |
|
} |
|
/** |
* |
* |
* |
* |
* |
*/ |
int |
read_attr(struct super_block *sb, befs_inode * inode) |
{ |
|
} |
/ChangeLog
0,0 → 1,417
Version 0.92 (2002-03-29) |
========== |
* Minor cleanup. Ran Lindent on the sources. |
|
Version 0.92 (2002-03-27) |
========== |
* Fixed module makefile problem. It was not compiling all the correct |
source files! |
* Removed duplicated function definition |
* Fixed potential null pointer dereference when reporting an error |
|
Version 0.91 (2002-03-26) |
========== |
* Oy! Fixed stupid bug that would cause an unresolved symbol error. |
Thanks to Laszlo Boszormenyi for pointing this out to me. |
|
Version 0.9 (2002-03-14) |
========== |
* Added Sergey S. Kostyliov's patch to eliminate memcpy() overhead |
from b+tree operations. Changes the befs_read_datastream() interface. |
|
* Segregated the functions that interface directly with the linux vfs |
interface into their own file called linuxvfs.c. [WD] |
|
Version 0.64 (2002-02-07) |
========== |
* Did the string comparision really right this time (btree.c) [WD] |
|
* Fixed up some places where I assumed that a long int could hold |
a pointer value. (btree.c) [WD] |
|
* Andrew Farnham <andrewfarnham@uq.net.au> pointed out that the module |
wouldn't work on older (<2.4.10) kernels due to an unresolved symbol. |
This is bad, since 2.4.9 is still the current RedHat kernel. I added |
a workaround for this problem (compatability.h) [WD] |
|
* Sergey S. Kostyliov made befs_find_key() use a binary search to find |
keys within btree nodes, rather than the linear search we were using |
before. (btree.c) [Sergey S. Kostyliov <rathamahata@php4.ru>] |
|
* Made a debian package of the source for use with kernel-package. [WD] |
|
|
Version 0.63 (2002-01-31) |
========== |
* Fixed bug in befs_find_brun_indirect() that would result in the wrong |
block being read. It was introduced when adding byteswapping in |
0.61. (datastream.c) [WD] |
|
* Fixed a longstanding bug in befs_find_key() that would result in it |
finding the first key that is a substring of the string it is searching |
for. For example, this would cause files in the same directory with |
names like file1 and file2 to mysteriously be duplicates of each other |
(because they have the same inode number). Many thanks to Pavel Roskin |
for reporting this serious bug!!! |
(btree.c) [WD] |
|
* Added support for long symlinks, after Axel Dorfler explained up how |
they work. I had forgotten all about them. (inode.c, symlink.c) [WD] |
|
* Documentation improvements in source. [WD] |
|
* Makefile fix for independant module when CONFIG_MODVERSION is set in |
kernel config [Pavel Roskin <proski@gnu.org>] |
|
* Compile warning fix for namei.c. [Sergey S. Kostyliov <rathamahata@php4.ru>] |
|
|
Version 0.62 |
========== |
* Fixed makefile for module install [WD] |
|
|
Version 0.61 (2002-01-20) |
========== |
* Made functions in endian.h to do the correct byteswapping, no matter |
the arch. [WD] |
|
* Abbandoned silly checks for a NULL superblock pointer in debug.c. [WD] |
|
* Misc code cleanups. Also cleanup of this changelog file. [WD] |
|
* Added byteswapping to all metadata reads from disk. |
Uses the functions from endian.h [WD] |
|
* Remove the typedef of struct super_block to vfs_sb, as it offended |
certain peoples' aesthetic sense. [WD] |
|
* Ditto with the befs_read_block() interface. [WD] |
|
|
Version 0.6 (2001-12-15) |
========== |
* Cleanup of NLS functions (util.c) [WD] |
|
* Make directory lookup/read use the NLS if an iocharset is provided. [WD] |
|
* Fixed stupid bug where specifying the uid or gid mount options as '0' |
would result in the filesystem using the on-disk uid and gid. [WD] |
|
* Added mount option to control debug printing. |
The option is, simply enough, 'debug'. |
(super.c, debug.c) [WD] |
|
* Removed notion of btree handle from btree.c. It was unessisary, as the |
linux VFS doesn't allow us to keep any state between calls. Updated |
dir.c, namei.c befs_fs.h to account for it. [WD] |
|
* Improved handleing of overflow nodes when listing directories. |
Now works for overflow nodes hanging off of nodes other than the root |
node. This is the cleaner solution to Brent Miszalaski's problem. [WD] |
|
* Added new debug/warning/error print functions in debug.c. |
More flexible. Will soon be controllable at mount time |
(see TODO). [WD] |
|
* Rewrote datastream positon lookups. |
(datastream.c) [WD] |
|
* Moved the TODO list to it's own file. |
|
|
Version 0.50 (2001-11-13) |
========== |
* Added workaround for mis-understanding of the nature of the b+trees used |
in directories. A cleaner solution will come after I've thought about it |
for a while. Thanks to Brent Miszalaski for finding and reporting this bug. |
(btree.c) [WD] |
|
* Minor cleanups |
|
* Added test for "impossible" condition of empty internal nodes in |
seekleaf() in btree.c [WD] |
|
* Implemented the abstracted read_block() in io.c [WD] |
|
* Cleaned up the inode validation in inode.c [WD] |
|
* Anton Altaparmakov figured out (by asking Linus :) ) what was causing the |
hanging disk io problem. It turns out you need to have the sync_pages |
callback defined in your address_space_ops, even if it just uses the |
default linux-supplied implementation. Fixed. Works now. |
(file.c) [WD] |
|
* Anton Altaparmakov and Christoph Hellwig alerted me to the fact that |
filesystem code should be using GFP_NOFS instead of GFP_KERNEL as the |
priority parameter to kmalloc(). Fixed. |
(datastream.c, btree.c super.c inode.c) [WD] |
|
* Anton also told me that the blocksize is not allowed to be larger than |
the page size in linux, which is 4k i386. Oops. Added a test for |
(blocksize > PAGE_SIZE), and refuse to mount in that case. What this |
practicaly means is that 8k blocksize volumes won't work without a major |
restructuring of the driver (or an alpha or other 64bit hardware). [WD] |
|
* Cleaned up the befs_count_blocks() function. Much smarter now. |
And somewhat smaller too. [WD] |
|
* Made inode allocations use a slab cache |
(super.c inode.c) [WD] |
|
* Moved the freeing of the private inode section from put_inode() to |
clear_inode(). This fixes a potential free twice type bug. Put_inode() |
can be called multiple times for each inode struct. [WD] |
|
* Converted all non vfs-callback functions to use befs_sb_info as the |
superblock type, rather than struct super_block. This is for |
portablity. [WD] |
|
* Fixed a couple of compile warnings due to use of malloc.h, when slab.h |
is the new way. (inode.c, super.c) [WD] |
|
* Fixed erronous includes of linux/befs_fs_i.h and linux/befs_fs_sb.h |
in inode.c [WD] |
|
Version 0.45 (2001-10-29) |
========== |
* Added functions to get the private superblock and inode structures from |
their enclosing public structures. Switched all references to the |
private portions to use them. (many files) [WD] |
|
* Made read_super and read_inode allocate the private portions of those |
structures into the generic pointer fields of the public structures |
with kmalloc(). put_super and put_inode free them. This allows us not |
to have to touch the definitions of the public structures in |
include/linux/fs.h. Also, befs_inode_info is huge (becuase of the |
symlink string). (super.c, inode.c, befs_fs.h) [WD] |
|
* Fixed a thinko that was corrupting file reads after the first block_run |
is done being read. (datastream.c) [WD] |
|
* Removed fsync() hooks, since a read-only filesystem doesn't need them. |
[Christoph Hellwig]. |
|
* Fixed befs_readlink() (symlink.c) [Christoph Hellwig]. |
|
* Removed all the Read-Write stuff. I'll redo it when it is time to add |
write support (various files) [WD]. |
|
* Removed prototypes for functions who's definitions have been removed |
(befs_fs.h) [WD]. |
|
|
Version 0.4 (2001-10-28) |
========== |
* Made it an option to use the old non-pagecache befs_file_read() for |
testing purposes. (fs/Config.in) |
|
* Fixed unused variable warnings when compiling without debugging. |
|
* Fixed a bug where the inode and super_block didn't get their blockbits |
fields set (inode.c and super.c). |
|
* Release patch version 11. AKA befs-driver version 0.4. |
|
* Thats right. New versioning scheme. |
I've done some serious testing on it now (on my box anyhow), and it |
seems stable and not outragously slow. Existing features are more-or-less |
correct (see TODO list). But it isn't 1.0 yet. I think 0.4 gives me some |
headroom before the big 1.0. |
|
|
2001-10-26 |
========== |
* Fixed date format in this file. Was I smoking crack? |
|
* Removed old datastream code from file.c, since it is nolonger used. |
|
* Generic_read_file() is now used to read regular file data. |
It doesn't chew up the buffer cache (it does page io instead), and seems |
to be about as fast (even though it has to look up each file block |
indivdualy). And it knows about doing readahead, which is a major plus. |
So it does i/o in much larger chunks. It is the correct linux way. It |
uses befs_get_block() by way of befs_readpage() to find the disk offsets |
of blocks, which in turn calls befs_fpos2brun() in datastream.c to do |
the hard work of finding the disk block number. |
|
* Changed method of checking for a dirty filesystem in befs_read_super |
(super.c). Now we check to see if log_start and log_end differ. If so, |
the journal needs to be replayed, and the filesystem cannot be mounted. |
|
* Fixed an extra instance of MOD_DEC_USE_COUNT in super.c |
|
* Fixed a problem with reading the superblock on devices with large sector |
sizes (such as cdroms) on linux 2.4.10 and up. |
|
2001-10-24 |
========== |
* Fix nasty bug in converting block numbers to struct befs_inode_addr. |
Subtle, because the old version was only sometimes wrong. |
Probably responsible for lots of problems. (inode.c) |
|
* Fix bug with reading an empty directory. (btree.c and dir.c) |
|
* This one looks good. Release patch version 10 |
|
2001-10-23 |
========== |
* Added btree searching function. |
|
* Use befs_btree_find in befs_lookup (namei.c) |
|
* Additional comments in btree.c |
|
2001-10-22 |
========== |
* Added B+tree reading functions (in btree.c). |
Made befs_readdir() use them them instead of the cruft in index.c. |
|
2001-09-11 |
========== |
* Converted befs_read_file() to use the new datastream code. |
|
* Finally updated the README file. |
|
* Added many comments. |
|
* Posted version 6 |
|
* Removed byte-order conversion code. |
I have no intention of supporting it, and it was very ugly. |
Flow control with #ifdef (ugh). Maybe I'll redo it once |
native byteorder works 100%. |
|
2001-09-10 |
========== |
* Finished implementing read_datastream() |
|
* made befs_read_brun() more general |
Supports an offset to start at and a max bytes to read |
Added a wrapper function to give the old call |
|
2001-09-30 |
========== |
* Discovered that the datastream handleing code in file.c is quite deficient |
in several respects. For one thing, it doesn't deal with indirect blocks |
|
* Rewrote datastream handleing. |
|
* Created io.c, for io related functions. |
Previously, the befs_bread() funtions lived in file.c |
Created the befs_read_brun() function. |
|
|
2001-09-07 |
========== |
* Made a function to actually count the number of fs blocks used by a file. |
And helper functions. |
(fs/befs/inode.c) |
|
2001-09-05 |
========== |
* Fixed a misunderstanding of the inode fields. |
This fixed the problmem with wrong file sizes from du and others. |
The i_blocks field of the inode struct is not the nuber of blocks for the |
inode, it is the number of blocks for the file. Also, i_blksize is not |
nessisarily the size of the inode, although in practice it works out. |
Changed to blocksize of filesystem. |
(fs/befs/inode.c) |
|
* Permanently removed code that had been provisionally ifdefed out of befs_fs.h |
|
* Since we don't support access time, make that field zero, instead of |
copying m_time. |
(fs/befs/inode.c) |
|
* Added sanity check for inode reading |
Make sure inode we got was the one we asked for. |
(fs/befs/inode.c) |
|
* Code cleanup |
Local pointers to commonly used structures in inode.c. |
Got rid of abominations befs_iaddr2inode() and befs_inode2ino(). |
Replaced with single function iaddr2blockno(). |
(fs/befs/super.c) (fs/befs/inode.c) |
|
2001-09-01 |
========== |
* Fixed the problem with statfs where it would always claim the disk was |
half full, due to improper understanding of the statfs fields. |
(fs/befs/super.c) |
|
* Posted verion 4 of the patch |
|
2001-09-01 |
========== |
* Changed the macros in befs_fs.h to inline functions. |
More readable. Typesafe. Better |
(include/linux/befs_fs.h) |
|
* Moved type definitions from befs_fs.h to a new file, befs_fs_types.h |
Because befs_fs_i.h and befs_fs_sb.h were including befs_fs.h for the |
typedefs, and they are inlcuded in <linux/fs.h>, which has definitions |
that I want the inline functions in befs_fs.h to be able to see. Nasty |
circularity. |
(include/linux/befs_fs.h) |
|
2001-08-30 |
========== |
* Cleaned up some wording. |
|
* Added additional consitency checks on mount |
Check block_size agrees with block_shift |
Check flags == BEFS_CLEAN |
(fs/befs/super.c) |
|
* Tell the kernel to only mount befs read-only. |
By setting the MS_RDONLY flag in befs_read_super(). |
Not that it was possible to write before. But now the kernel won't even try. |
(fs/befs/super.c) |
|
* Got rid of kernel warning on mount. |
The kernel doesn't like it if you call set_blocksize() on a device when |
you have some of its blocks open. Moved the second set_blocksize() to the |
very end of befs_read_super(), after we are done with the disk superblock. |
(fs/befs/super.c) |
|
* Fixed wrong number of args bug in befs_dump_inode |
(fs/befs/debug.c) |
|
* Solved lots of type mismatches in kprint()s |
(everwhere) |
|
2001-08-27 |
========== |
* Cleaned up the fs/Config.in entries a bit, now slightly more descriptive. |
|
* BeFS depends on NLS, so I made activating BeFS enable the NLS questions |
(fs/nls/Config.in) |
|
* Added Configure.help entries for CONFIG_BEFS_FS and CONFIG_DEBUG_BEFS |
(Documentation/Configure.help) |
|
2001-08-?? |
========== |
* Removed superblock locking calls in befs_read_super(). In 2.4, the VFS |
hands us a super_block struct that is already locked. |
|
2001-08-13 |
========== |
* Will Dyson <will_dyson@pobox.com> is now attempting to maintain this module |
Makoto Kato <m_kato@ga2.so-net.ne.jp> is original author.Daniel Berlin |
also did some work on it (fixing it up for the later 2.3.x kernels, IIRC). |
|
* Fixed compile errors on 2.4.1 kernel (WD) |
Resolve rejected patches |
Accomodate changed NLS interface (util.h) |
Needed to include <linux/slab.h> in most files |
Makefile changes |
fs/Config.in changes |
|
* Tried to niceify the code using the ext2 fs as a guide |
Declare befs_fs_type using the DECLARE_FSTYPE_DEV() macro |
|
* Made it a configure option to turn on debugging (fs/Config.in) |
|
* Compiles on 2.4.7 |
/btree.h
0,0 → 1,11
/* |
* btree.h |
* |
*/ |
|
int befs_btree_find(struct super_block *sb, befs_data_stream * ds, |
const char *key, befs_off_t * value); |
|
int befs_btree_read(struct super_block *sb, befs_data_stream * ds, |
loff_t key_no, size_t bufsize, char *keybuf, |
size_t * keysize, befs_off_t * value); |
/io.c
0,0 → 1,99
/* |
* linux/fs/befs/io.c |
* |
* Copyright (C) 2001 Will Dyson <will_dyson@pobox.com |
* |
* Based on portions of file.c and inode.c |
* by Makoto Kato (m_kato@ga2.so-net.ne.jp) |
* |
* Many thanks to Dominic Giampaolo, author of Practical File System |
* Design with the Be File System, for such a helpful book. |
* |
*/ |
|
#include <linux/fs.h> |
|
#include "befs.h" |
#include "io.h" |
|
/* |
* Converts befs notion of disk addr to a disk offset and uses |
* linux kernel function bread() to get the buffer containing |
* the offset. -Will Dyson |
* |
*/ |
|
struct buffer_head * |
befs_bread_iaddr(struct super_block *sb, befs_inode_addr iaddr) |
{ |
struct buffer_head *bh = NULL; |
befs_blocknr_t block = 0; |
vfs_blocknr_t vfs_block = 0; |
befs_sb_info *befs_sb = BEFS_SB(sb); |
|
befs_debug(sb, "---> Enter befs_read_iaddr() " |
"[%u, %hu, %hu]", |
iaddr.allocation_group, iaddr.start, iaddr.len); |
|
if (iaddr.allocation_group > befs_sb->num_ags) { |
befs_error(sb, "BEFS: Invalid allocation group %u, max is %u", |
iaddr.allocation_group, befs_sb->num_ags); |
goto error; |
} |
|
block = iaddr2blockno(sb, &iaddr); |
vfs_block = (vfs_blocknr_t) block; |
|
if (vfs_block != block) { |
befs_error(sb, "Error converting to host blocknr_t. %Lu " |
"is larger than the host can use", block); |
goto error; |
} |
|
befs_debug(sb, "befs_read_iaddr: offset = %lu", block); |
|
bh = bread(sb->s_dev, vfs_block, befs_sb->block_size); |
|
if (bh == NULL) { |
befs_error(sb, "Failed to read block %lu", block); |
goto error; |
} |
|
befs_debug(sb, "<--- befs_read_iaddr()"); |
return bh; |
|
error: |
befs_debug(sb, "<--- befs_read_iaddr() ERROR"); |
return NULL; |
} |
|
struct buffer_head * |
befs_bread(struct super_block *sb, befs_blocknr_t block) |
{ |
struct buffer_head *bh = NULL; |
befs_sb_info *befs_sb = BEFS_SB(sb); |
vfs_blocknr_t vfs_block = (vfs_blocknr_t) block; |
|
befs_debug(sb, "---> Enter befs_read() %Lu", block); |
|
if (vfs_block != block) { |
befs_error(sb, "Error converting to host blocknr_t. %Lu " |
"is larger than the host can use", block); |
goto error; |
} |
|
bh = bread(sb->s_dev, vfs_block, befs_sb->block_size); |
|
if (bh == NULL) { |
befs_error(sb, "Failed to read block %lu", vfs_block); |
goto error; |
} |
|
befs_debug(sb, "<--- befs_read()"); |
|
return bh; |
|
error: |
befs_debug(sb, "<--- befs_read() ERROR"); |
return NULL; |
} |
/io.h
0,0 → 1,8
/* |
* io.h |
*/ |
|
struct buffer_head *befs_bread_iaddr(struct super_block *sb, |
befs_inode_addr iaddr); |
|
struct buffer_head *befs_bread(struct super_block *sb, befs_blocknr_t block); |
/linuxvfs.c
0,0 → 1,1001
/* |
* linux/fs/befs/linuxvfs.c |
* |
* Copyright (C) 2001 Will Dyson <will_dyson@pobox.com |
* |
*/ |
|
#include <linux/blkdev.h> |
#include <linux/init.h> |
#include <linux/module.h> |
#include <linux/slab.h> |
#include <linux/errno.h> |
#include <linux/fs.h> |
#include <linux/stat.h> |
#include <linux/string.h> |
#include <linux/nls.h> |
|
#include "befs.h" |
#include "btree.h" |
#include "inode.h" |
#include "datastream.h" |
#include "super.h" |
#include "io.h" |
#include "endian.h" |
|
EXPORT_NO_SYMBOLS; |
MODULE_DESCRIPTION("BeOS File System (BeFS) driver"); |
MODULE_AUTHOR("Will Dyson"); |
MODULE_LICENSE("GPL"); |
|
/* The units the vfs expects inode->i_blocks to be in */ |
#define VFS_BLOCK_SIZE 512 |
|
static int befs_readdir(struct file *, void *, filldir_t); |
static int befs_get_block(struct inode *, long, struct buffer_head *, int); |
static int befs_readpage(struct file *file, struct page *page); |
static int befs_bmap(struct address_space *mapping, long block); |
static struct dentry *befs_lookup(struct inode *, struct dentry *); |
static void befs_read_inode(struct inode *ino); |
static void befs_clear_inode(struct inode *ino); |
static int befs_init_inodecache(void); |
static void befs_destroy_inodecache(void); |
|
static int befs_readlink(struct dentry *, char *, int); |
static int befs_follow_link(struct dentry *, struct nameidata *nd); |
|
static int befs_utf2nls(struct super_block *sb, const char *in, int in_len, |
char **out, int *out_len); |
static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, |
char **out, int *out_len); |
|
static void befs_put_super(struct super_block *); |
static struct super_block *befs_read_super(struct super_block *, void *, int); |
static int befs_remount(struct super_block *, int *, char *); |
static int befs_statfs(struct super_block *, struct statfs *); |
static int parse_options(char *, befs_mount_options *); |
|
static ssize_t befs_listxattr(struct dentry *dentry, char *buffer, size_t size); |
static ssize_t befs_getxattr(struct dentry *dentry, const char *name, |
void *buffer, size_t size); |
static int befs_setxattr(struct dentry *dentry, const char *name, void *value, |
size_t size, int flags); |
static int befs_removexattr(struct dentry *dentry, const char *name); |
|
/* slab cache for befs_inode_info objects */ |
static kmem_cache_t *befs_inode_cachep; |
|
static const struct super_operations befs_sops = { |
read_inode:befs_read_inode, /* initialize & read inode */ |
clear_inode:befs_clear_inode, /* uninit inode */ |
put_super:befs_put_super, /* uninit super */ |
statfs:befs_statfs, /* statfs */ |
remount_fs:befs_remount, |
}; |
|
struct file_operations befs_dir_operations = { |
read:generic_read_dir, |
readdir:befs_readdir, |
}; |
|
struct inode_operations befs_dir_inode_operations = { |
lookup:befs_lookup, |
}; |
|
struct file_operations befs_file_operations = { |
llseek:default_llseek, |
read:generic_file_read, |
mmap:generic_file_mmap, |
}; |
|
struct inode_operations befs_file_inode_operations = { |
}; |
|
struct address_space_operations befs_aops = { |
readpage:befs_readpage, |
sync_page:block_sync_page, |
bmap:befs_bmap, |
}; |
|
static struct inode_operations befs_symlink_inode_operations = { |
readlink:befs_readlink, |
follow_link:befs_follow_link, |
}; |
|
/* |
* Called by generic_file_read() to read a page of data |
* |
* In turn, simply calls a generic block read function and |
* passes it the address of befs_get_block, for mapping file |
* positions to disk blocks. |
*/ |
static int |
befs_readpage(struct file *file, struct page *page) |
{ |
return block_read_full_page(page, befs_get_block); |
} |
|
static int |
befs_bmap(struct address_space *mapping, long block) |
{ |
return generic_block_bmap(mapping, block, befs_get_block); |
} |
|
/* |
* Generic function to map a file position (block) to a |
* disk offset (passed back in bh_result). |
* |
* Used by many higher level functions. |
* |
* Calls befs_fblock2brun() in datastream.c to do the real work. |
* |
* -WD 10-26-01 |
*/ |
|
static int |
befs_get_block(struct inode *inode, long block, |
struct buffer_head *bh_result, int create) |
{ |
struct super_block *sb = inode->i_sb; |
befs_data_stream *ds = &BEFS_I(inode)->i_data.ds; |
befs_block_run run = BAD_IADDR; |
int res = 0; |
ulong disk_off; |
|
befs_debug(sb, "---> befs_get_block() for inode %lu, block %ld", |
inode->i_ino, block); |
|
if (block < 0) { |
befs_error(sb, "befs_get_block() was asked for a block " |
"number less than zero: block %ld in inode %lu", |
block, inode->i_ino); |
return -EIO; |
} |
|
if (create) { |
befs_error(sb, "befs_get_block() was asked to write to " |
"block %ld in inode %lu", block, inode->i_ino); |
return -EPERM; |
} |
|
res = befs_fblock2brun(sb, ds, block, &run); |
if (res != BEFS_OK) { |
befs_error(sb, |
"<--- befs_get_block() for inode %lu, block " |
"%ld ERROR", inode->i_ino, block); |
return -EFBIG; |
} |
|
disk_off = (ulong) iaddr2blockno(sb, &run); |
|
bh_result->b_dev = inode->i_dev; |
bh_result->b_blocknr = disk_off; |
bh_result->b_state |= (1UL << BH_Mapped); |
|
befs_debug(sb, "<--- befs_get_block() for inode %lu, block %ld, " |
"disk address %lu", inode->i_ino, block, disk_off); |
|
return 0; |
} |
|
static struct dentry * |
befs_lookup(struct inode *dir, struct dentry *dentry) |
{ |
struct inode *inode = NULL; |
struct super_block *sb = dir->i_sb; |
befs_data_stream *ds = &BEFS_I(dir)->i_data.ds; |
befs_off_t offset; |
int ret; |
int utfnamelen; |
char *utfname; |
const char *name = dentry->d_name.name; |
|
befs_debug(sb, "---> befs_lookup() " |
"name %s inode %ld", dentry->d_name.name, dir->i_ino); |
|
/* Convert to UTF-8 */ |
if (BEFS_SB(sb)->nls) { |
ret = |
befs_nls2utf(sb, name, strlen(name), &utfname, &utfnamelen); |
if (ret < 0) { |
befs_debug(sb, "<--- befs_lookup() ERROR"); |
return ERR_PTR(ret); |
} |
ret = befs_btree_find(sb, ds, utfname, &offset); |
kfree(utfname); |
|
} else { |
ret = befs_btree_find(sb, ds, dentry->d_name.name, &offset); |
} |
|
if (ret == BEFS_BT_NOT_FOUND) { |
befs_debug(sb, "<--- befs_lookup() %s not found", |
dentry->d_name.name); |
return ERR_PTR(-ENOENT); |
|
} else if (ret != BEFS_OK || offset == 0) { |
befs_warning(sb, "<--- befs_lookup() Error"); |
return ERR_PTR(-ENODATA); |
} |
|
inode = iget(dir->i_sb, (ino_t) offset); |
if (!inode) |
return ERR_PTR(-EACCES); |
|
d_add(dentry, inode); |
|
befs_debug(sb, "<--- befs_lookup()"); |
|
return NULL; |
} |
|
static int |
befs_readdir(struct file *filp, void *dirent, filldir_t filldir) |
{ |
struct inode *inode = filp->f_dentry->d_inode; |
struct super_block *sb = inode->i_sb; |
befs_data_stream *ds = &BEFS_I(inode)->i_data.ds; |
befs_off_t value; |
int result; |
size_t keysize; |
unsigned char d_type; |
char keybuf[BEFS_NAME_LEN + 1]; |
char *nlsname; |
int nlsnamelen; |
const char *dirname = filp->f_dentry->d_name.name; |
|
befs_debug(sb, "---> befs_readdir() " |
"name %s, inode %ld, filp->f_pos %Ld", |
dirname, inode->i_ino, filp->f_pos); |
|
result = befs_btree_read(sb, ds, filp->f_pos, BEFS_NAME_LEN + 1, |
keybuf, &keysize, &value); |
|
if (result == BEFS_ERR) { |
befs_debug(sb, "<--- befs_readdir() ERROR"); |
befs_error(sb, "IO error reading %s (inode %lu)", |
dirname, inode->i_ino); |
return -EIO; |
|
} else if (result == BEFS_BT_END) { |
befs_debug(sb, "<--- befs_readdir() END"); |
return 0; |
|
} else if (result == BEFS_BT_EMPTY) { |
befs_debug(sb, "<--- befs_readdir() Empty directory"); |
return 0; |
} |
|
d_type = DT_UNKNOWN; |
|
/* Convert to NLS */ |
if (BEFS_SB(sb)->nls) { |
result = |
befs_utf2nls(sb, keybuf, keysize, &nlsname, &nlsnamelen); |
if (result < 0) { |
befs_debug(sb, "<--- befs_readdir() ERROR"); |
return result; |
} |
result = filldir(dirent, nlsname, nlsnamelen, filp->f_pos, |
(ino_t) value, d_type); |
kfree(nlsname); |
|
} else { |
result = filldir(dirent, keybuf, keysize, filp->f_pos, |
(ino_t) value, d_type); |
} |
|
filp->f_pos++; |
|
befs_debug(sb, "<--- befs_readdir() filp->f_pos %Ld", filp->f_pos); |
|
return 0; |
} |
|
static void |
befs_clear_inode(struct inode *inode) |
{ |
befs_inode_info *b_ino = BEFS_I(inode); |
inode->u.generic_ip = NULL; |
|
if (b_ino) { |
kmem_cache_free(befs_inode_cachep, b_ino); |
} |
return; |
} |
|
static void |
befs_read_inode(struct inode *inode) |
{ |
struct buffer_head *bh = NULL; |
befs_inode *raw_inode = NULL; |
|
struct super_block *sb = inode->i_sb; |
befs_sb_info *befs_sb = BEFS_SB(sb); |
befs_inode_info *befs_ino = NULL; |
|
befs_debug(sb, "---> befs_read_inode() " "inode = %lu", inode->i_ino); |
|
inode->u.generic_ip = kmem_cache_alloc(befs_inode_cachep, GFP_NOFS); |
if (inode->u.generic_ip == NULL) { |
befs_error(sb, "Unable to allocate memory for private " |
"portion of inode %lu.", inode->i_ino); |
goto unaquire_none; |
} |
befs_ino = BEFS_I(inode); |
|
/* convert from vfs's inode number to befs's inode number */ |
befs_ino->i_inode_num = blockno2iaddr(sb, inode->i_ino); |
|
befs_debug(sb, " real inode number [%u, %hu, %hu]", |
befs_ino->i_inode_num.allocation_group, |
befs_ino->i_inode_num.start, befs_ino->i_inode_num.len); |
|
bh = befs_bread_iaddr(sb, befs_ino->i_inode_num); |
if (!bh) { |
befs_error(sb, "unable to read inode block - " |
"inode = %lu", inode->i_ino); |
goto unaquire_ino_info; |
} |
|
raw_inode = (befs_inode *) bh->b_data; |
|
befs_dump_inode(sb, raw_inode); |
|
if (befs_check_inode(sb, raw_inode, inode->i_ino) != BEFS_OK) { |
befs_error(sb, "Bad inode: %lu", inode->i_ino); |
goto unaquire_bh; |
} |
|
inode->i_mode = (umode_t) fs32_to_cpu(sb, raw_inode->mode); |
|
/* |
* set uid and gid. But since current BeOS is single user OS, so |
* you can change by "uid" or "gid" options. |
*/ |
|
inode->i_uid = befs_sb->mount_opts.use_uid ? |
befs_sb->mount_opts.uid : (uid_t) fs32_to_cpu(sb, raw_inode->uid); |
inode->i_gid = befs_sb->mount_opts.use_gid ? |
befs_sb->mount_opts.gid : (gid_t) fs32_to_cpu(sb, raw_inode->gid); |
|
inode->i_nlink = 1; |
|
/* |
* BEFS's time is 64 bits, but current VFS is 32 bits... |
* BEFS don't have access time. Nor inode change time. VFS |
* doesn't have creation time. |
*/ |
|
inode->i_mtime = |
(time_t) (fs64_to_cpu(sb, raw_inode->last_modified_time) >> 16); |
inode->i_ctime = inode->i_mtime; |
inode->i_atime = inode->i_mtime; |
inode->i_blkbits = befs_sb->block_shift; |
inode->i_blksize = befs_sb->block_size; |
|
befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num); |
befs_ino->i_parent = fsrun_to_cpu(sb, raw_inode->parent); |
befs_ino->i_attribute = fsrun_to_cpu(sb, raw_inode->attributes); |
befs_ino->i_flags = fs32_to_cpu(sb, raw_inode->flags); |
|
if (S_ISLNK(inode->i_mode) && !(inode->i_flags & BEFS_LONG_SYMLINK)) { |
inode->i_size = 0; |
inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE; |
strncpy(befs_ino->i_data.symlink, raw_inode->data.symlink, |
BEFS_SYMLINK_LEN); |
} else { |
int num_blks; |
|
befs_ino->i_data.ds = |
fsds_to_cpu(sb, raw_inode->data.datastream); |
|
num_blks = befs_count_blocks(sb, &befs_ino->i_data.ds); |
inode->i_blocks = |
num_blks * (befs_sb->block_size / VFS_BLOCK_SIZE); |
inode->i_size = befs_ino->i_data.ds.size; |
} |
|
inode->i_mapping->a_ops = &befs_aops; |
|
if (S_ISREG(inode->i_mode)) { |
inode->i_fop = &befs_file_operations; |
inode->i_op = &befs_file_inode_operations; |
} else if (S_ISDIR(inode->i_mode)) { |
inode->i_op = &befs_dir_inode_operations; |
inode->i_fop = &befs_dir_operations; |
} else if (S_ISLNK(inode->i_mode)) { |
inode->i_op = &befs_symlink_inode_operations; |
} else { |
befs_error(sb, "Inode %lu is not a regular file, " |
"directory or symlink. THAT IS WRONG! BeFS has no " |
"on disk special files", inode->i_ino); |
goto unaquire_bh; |
} |
|
brelse(bh); |
befs_debug(sb, "<--- befs_read_inode()"); |
return; |
|
unaquire_bh: |
brelse(bh); |
|
unaquire_ino_info: |
kmem_cache_free(befs_inode_cachep, inode->u.generic_ip); |
|
unaquire_none: |
make_bad_inode(inode); |
inode->u.generic_ip = NULL; |
befs_debug(sb, "<--- befs_read_inode() - Bad inode"); |
return; |
} |
|
/* Initialize the inode cache. Called at fs setup. |
* |
* Taken from NFS implementation by Al Viro. |
*/ |
static int |
befs_init_inodecache(void) |
{ |
befs_inode_cachep = kmem_cache_create("befs_inode_cache", |
sizeof (struct befs_inode_info), |
0, SLAB_HWCACHE_ALIGN, |
NULL, NULL); |
if (befs_inode_cachep == NULL) { |
printk(KERN_ERR "befs_init_inodecache: " |
"Couldn't initalize inode slabcache\n"); |
return -ENOMEM; |
} |
|
return 0; |
} |
|
/* Called at fs teardown. |
* |
* Taken from NFS implementation by Al Viro. |
*/ |
static void |
befs_destroy_inodecache(void) |
{ |
if (kmem_cache_destroy(befs_inode_cachep)) |
printk(KERN_ERR "befs_destroy_inodecache: " |
"not all structures were freed\n"); |
} |
|
/* |
* The inode of symbolic link is different to data stream. |
* The data stream become link name. Unless the LONG_SYMLINK |
* flag is set. |
*/ |
static int |
befs_follow_link(struct dentry *dentry, struct nameidata *nd) |
{ |
struct super_block *sb = dentry->d_sb; |
befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); |
char *link; |
int res; |
|
if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { |
befs_data_stream *data = &befs_ino->i_data.ds; |
befs_off_t linklen = data->size; |
|
befs_debug(sb, "Follow long symlink"); |
|
link = kmalloc(linklen, GFP_NOFS); |
if (link == NULL) |
return -ENOMEM; |
|
if (befs_read_lsymlink(sb, data, link, linklen) != linklen) { |
kfree(link); |
befs_error(sb, "Failed to read entire long symlink"); |
return -EIO; |
} |
|
res = vfs_follow_link(nd, link); |
|
kfree(link); |
} else { |
link = befs_ino->i_data.symlink; |
res = vfs_follow_link(nd, link); |
} |
|
return res; |
} |
|
static int |
befs_readlink(struct dentry *dentry, char *buffer, int buflen) |
{ |
struct super_block *sb = dentry->d_sb; |
befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); |
char *link; |
int res; |
|
if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { |
befs_data_stream *data = &befs_ino->i_data.ds; |
befs_off_t linklen = data->size; |
|
befs_debug(sb, "Read long symlink"); |
|
link = kmalloc(linklen, GFP_NOFS); |
if (link == NULL) |
return -ENOMEM; |
|
if (befs_read_lsymlink(sb, data, link, linklen) != linklen) { |
kfree(link); |
befs_error(sb, "Failed to read entire long symlink"); |
return -EIO; |
} |
|
res = vfs_readlink(dentry, buffer, buflen, link); |
|
kfree(link); |
} else { |
link = befs_ino->i_data.symlink; |
res = vfs_readlink(dentry, buffer, buflen, link); |
} |
|
return res; |
} |
|
/* |
* UTF-8 to NLS charset convert routine |
* |
* Changed 8/10/01 by Will Dyson. Now use uni2char() / char2uni() rather than |
* the nls tables directly |
*/ |
|
static int |
befs_utf2nls(struct super_block *sb, const char *in, |
int in_len, char **out, int *out_len) |
{ |
struct nls_table *nls = BEFS_SB(sb)->nls; |
int i, o; |
wchar_t uni; |
int unilen, utflen; |
char *result; |
int maxlen = in_len; /* The utf8->nls conversion cant make more chars */ |
|
befs_debug(sb, "---> utf2nls()"); |
|
if (!nls) { |
befs_error(sb, "befs_utf2nls called with no NLS table loaded"); |
return -EINVAL; |
} |
|
*out = result = kmalloc(maxlen, GFP_NOFS); |
if (!*out) { |
befs_error(sb, "befs_utf2nls() cannot allocate memory"); |
*out_len = 0; |
return -ENOMEM; |
} |
|
for (i = o = 0; i < in_len; i += utflen, o += unilen) { |
|
/* convert from UTF-8 to Unicode */ |
utflen = utf8_mbtowc(&uni, &in[i], in_len - i); |
if (utflen < 0) { |
goto conv_err; |
} |
|
/* convert from Unicode to nls */ |
unilen = nls->uni2char(uni, &result[o], 1); |
if (unilen < 0) { |
goto conv_err; |
} |
} |
result[o] = '\0'; |
|
befs_debug(sb, "<--- utf2nls()"); |
|
return o; |
*out_len = o; |
|
conv_err: |
befs_error(sb, "Name using charecter set %s contains a charecter that " |
"cannot be converted to unicode.", nls->charset); |
befs_debug(sb, "<--- utf2nls()"); |
kfree(result); |
return -EILSEQ; |
} |
|
/** |
* befs_nls2utf - Convert NLS string to utf8 encodeing |
* @sb: Superblock |
* @src: Input string buffer in NLS format |
* @srclen: Length of input string in bytes |
* @dest: The output string in UTF8 format |
* @destlen: Length of the output buffer |
* |
* Converts input string @src, which is in the format of the loaded NLS map, |
* into a utf8 string. |
* |
* The destination string @dest is allocated by this function and the caller is |
* responsible for freeing it with kfree() |
* |
* On return, *@destlen is the length of @dest in bytes. |
* |
* On success, the return value is the number of utf8 charecters written to |
* the ouput buffer @dest. |
* |
* On Failure, a negative number coresponding to the error code is returned. |
*/ |
|
static int |
befs_nls2utf(struct super_block *sb, const char *in, |
int in_len, char **out, int *out_len) |
{ |
struct nls_table *nls = BEFS_SB(sb)->nls; |
int i, o; |
wchar_t uni; |
int unilen, utflen; |
char *result; |
int maxlen = 3 * in_len; |
|
befs_debug(sb, "---> nls2utf()\n"); |
|
if (!nls) { |
befs_error(sb, "befs_nls2utf called with no NLS table loaded."); |
return -EINVAL; |
} |
|
*out = result = kmalloc(maxlen, GFP_NOFS); |
if (!*out) { |
befs_error(sb, "befs_nls2utf() cannot allocate memory"); |
*out_len = 0; |
return -ENOMEM; |
} |
|
for (i = o = 0; i < in_len; i += unilen, o += utflen) { |
|
/* convert from nls to unicode */ |
unilen = nls->char2uni(&in[i], in_len - i, &uni); |
if (unilen < 0) { |
goto conv_err; |
} |
|
/* convert from unicode to UTF-8 */ |
utflen = utf8_wctomb(&result[o], uni, 3); |
if (utflen <= 0) { |
goto conv_err; |
} |
} |
|
result[o] = '\0'; |
*out_len = o; |
|
befs_debug(sb, "<--- nls2utf()"); |
|
return i; |
|
conv_err: |
befs_error(sb, "Name using charecter set %s contains a charecter that " |
"cannot be converted to unicode.", nls->charset); |
befs_debug(sb, "<--- nls2utf()"); |
kfree(result); |
return -EILSEQ; |
} |
|
/****Xattr****/ |
|
static ssize_t |
befs_listxattr(struct dentry *dentry, char *buffer, size_t size) |
{ |
printk(KERN_ERR "befs_listxattr called\n"); |
return 0; |
} |
|
static ssize_t |
befs_getxattr(struct dentry *dentry, const char *name, |
void *buffer, size_t size) |
{ |
return 0; |
} |
|
static int |
befs_setxattr(struct dentry *dentry, const char *name, |
void *value, size_t size, int flags) |
{ |
return 0; |
} |
|
static int |
befs_removexattr(struct dentry *dentry, const char *name) |
{ |
return 0; |
} |
|
/****Superblock****/ |
|
static int |
parse_options(char *options, befs_mount_options * opts) |
{ |
char *this_char; |
char *value; |
int ret = 1; |
|
/* Initialize options */ |
opts->uid = 0; |
opts->gid = 0; |
opts->use_uid = 0; |
opts->use_gid = 0; |
opts->iocharset = NULL; |
opts->debug = 0; |
|
if (!options) |
return ret; |
|
for (this_char = strtok(options, ","); this_char != NULL; |
this_char = strtok(NULL, ",")) { |
|
if ((value = strchr(this_char, '=')) != NULL) |
*value++ = 0; |
|
if (!strcmp(this_char, "uid")) { |
if (!value || !*value) { |
ret = 0; |
} else { |
opts->uid = simple_strtoul(value, &value, 0); |
opts->use_uid = 1; |
if (*value) { |
printk(KERN_ERR "BEFS: Invalid uid " |
"option: %s\n", value); |
ret = 0; |
} |
} |
} else if (!strcmp(this_char, "gid")) { |
if (!value || !*value) |
ret = 0; |
else { |
opts->gid = simple_strtoul(value, &value, 0); |
opts->use_gid = 1; |
if (*value) { |
printk(KERN_ERR |
"BEFS: Invalid gid option: " |
"%s\n", value); |
ret = 0; |
} |
} |
} else if (!strcmp(this_char, "iocharset") && value) { |
char *p = value; |
int len; |
|
while (*value && *value != ',') |
value++; |
len = value - p; |
if (len) { |
char *buffer = kmalloc(len + 1, GFP_NOFS); |
if (buffer) { |
opts->iocharset = buffer; |
memcpy(buffer, p, len); |
buffer[len] = 0; |
|
} else { |
printk(KERN_ERR "BEFS: " |
"cannot allocate memory\n"); |
ret = 0; |
} |
} |
} else if (!strcmp(this_char, "debug")) { |
opts->debug = 1; |
} |
} |
|
return ret; |
} |
|
/* This function has the responsibiltiy of getting the |
* filesystem ready for unmounting. |
* Basicly, we free everything that we allocated in |
* befs_read_inode |
*/ |
static void |
befs_put_super(struct super_block *sb) |
{ |
if (BEFS_SB(sb)->mount_opts.iocharset) { |
kfree(BEFS_SB(sb)->mount_opts.iocharset); |
BEFS_SB(sb)->mount_opts.iocharset = NULL; |
} |
|
if (BEFS_SB(sb)->nls) { |
unload_nls(BEFS_SB(sb)->nls); |
BEFS_SB(sb)->nls = NULL; |
} |
|
if (sb->u.generic_sbp) { |
kfree(sb->u.generic_sbp); |
sb->u.generic_sbp = NULL; |
} |
return; |
} |
|
/* Allocate private field of the superblock, fill it. |
* |
* Finish filling the public superblock fields |
* Make the root directory |
* Load a set of NLS translations if needed. |
*/ |
static struct super_block * |
befs_read_super(struct super_block *sb, void *data, int silent) |
{ |
struct buffer_head *bh; |
befs_sb_info *befs_sb; |
befs_super_block *disk_sb; |
int blocksize; |
|
const unsigned long sb_block = 0; |
const off_t x86_sb_off = 512; |
|
sb->u.generic_sbp = kmalloc(sizeof (struct befs_sb_info), GFP_NOFS); |
if (sb->u.generic_sbp == NULL) { |
printk(KERN_ERR |
"BeFS(%s): Unable to allocate memory for private " |
"portion of superblock. Bailing.\n", |
kdevname(sb->s_dev)); |
goto unaquire_none; |
} |
befs_sb = BEFS_SB(sb); |
|
if (!parse_options((char *) data, &befs_sb->mount_opts)) { |
befs_error(sb, "cannot parse mount options"); |
goto unaquire_priv_sbp; |
} |
|
befs_debug(sb, "---> befs_read_super()"); |
|
#ifndef CONFIG_BEFS_RW |
if (!(sb->s_flags & MS_RDONLY)) { |
befs_warning(sb, |
"No write support. Marking filesystem read-only"); |
sb->s_flags |= MS_RDONLY; |
} |
#endif /* CONFIG_BEFS_RW */ |
|
/* |
* Set dummy blocksize to read super block. |
* Will be set to real fs blocksize later. |
* |
* Linux 2.4.10 and later refuse to read blocks smaller than |
* the hardsect size for the device. But we also need to read at |
* least 1k to get the second 512 bytes of the volume. |
* -WD 10-26-01 |
*/ |
blocksize = max_t(int, get_hardsect_size(sb->s_dev), 1024); |
set_blocksize(sb->s_dev, blocksize); |
|
if (!(bh = bread(sb->s_dev, sb_block, blocksize))) { |
befs_error(sb, "unable to read superblock"); |
goto unaquire_priv_sbp; |
} |
|
/* account for offset of super block on x86 */ |
disk_sb = (befs_super_block *) bh->b_data; |
if ((le32_to_cpu(disk_sb->magic1) == BEFS_SUPER_MAGIC1) || |
(be32_to_cpu(disk_sb->magic1) == BEFS_SUPER_MAGIC1)) { |
befs_debug(sb, "Using PPC superblock location"); |
} else { |
befs_debug(sb, "Using x86 superblock location"); |
disk_sb = |
(befs_super_block *) ((void *) bh->b_data + x86_sb_off); |
} |
|
if (befs_load_sb(sb, disk_sb) != BEFS_OK) |
goto unaquire_bh; |
|
befs_dump_super_block(sb, disk_sb); |
|
brelse(bh); |
|
if (befs_check_sb(sb) != BEFS_OK) |
goto unaquire_priv_sbp; |
|
/* |
* set up enough so that it can read an inode |
* Fill in kernel superblock fields from private sb |
*/ |
sb->s_magic = BEFS_SUPER_MAGIC; |
sb->s_blocksize = (ulong) befs_sb->block_size; |
sb->s_blocksize_bits = (unsigned char) befs_sb->block_shift; |
sb->s_op = (struct super_operations *) &befs_sops; |
sb->s_root = |
d_alloc_root(iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)))); |
if (!sb->s_root) { |
befs_error(sb, "get root inode failed"); |
goto unaquire_priv_sbp; |
} |
|
/* load nls library */ |
if (befs_sb->mount_opts.iocharset) { |
befs_debug(sb, "Loading nls: %s", |
befs_sb->mount_opts.iocharset); |
befs_sb->nls = load_nls(befs_sb->mount_opts.iocharset); |
if (!befs_sb->nls) { |
befs_warning(sb, "Cannot load nls %s" |
"loding default nls", |
befs_sb->mount_opts.iocharset); |
befs_sb->nls = load_nls_default(); |
} |
} |
|
/* Set real blocksize of fs */ |
set_blocksize(sb->s_dev, (int) befs_sb->block_size); |
|
return sb; |
/*****************/ |
unaquire_bh: |
brelse(bh); |
|
unaquire_priv_sbp: |
kfree(sb->u.generic_sbp); |
|
unaquire_none: |
sb->s_dev = 0; |
sb->u.generic_sbp = NULL; |
return NULL; |
} |
|
static int |
befs_remount(struct super_block *sb, int *flags, char *data) |
{ |
if (!(*flags & MS_RDONLY)) |
return -EINVAL; |
return 0; |
} |
|
static int |
befs_statfs(struct super_block *sb, struct statfs *buf) |
{ |
|
befs_debug(sb, "---> befs_statfs()"); |
|
buf->f_type = BEFS_SUPER_MAGIC; |
buf->f_bsize = sb->s_blocksize; |
buf->f_blocks = BEFS_SB(sb)->num_blocks; |
buf->f_bfree = BEFS_SB(sb)->num_blocks - BEFS_SB(sb)->used_blocks; |
buf->f_bavail = buf->f_bfree; |
buf->f_files = 0; /* UNKNOWN */ |
buf->f_ffree = 0; /* UNKNOWN */ |
buf->f_namelen = BEFS_NAME_LEN; |
|
befs_debug(sb, "<--- befs_statfs()"); |
|
return 0; |
} |
|
/* |
Makes a variable of type file_system_type, |
named befs_fs_tipe, identified by the "befs" string, |
and containing a reference to the befs_read_super function |
|
Macro declared in <linux/fs.h> |
*/ |
static DECLARE_FSTYPE_DEV(befs_fs_type, "befs", befs_read_super); |
|
static int __init |
init_befs_fs(void) |
{ |
int err; |
|
printk(KERN_INFO "BeFS version: %s\n", BEFS_VERSION); |
|
err = befs_init_inodecache(); |
if (err) |
return err; |
|
return register_filesystem(&befs_fs_type); |
} |
|
static void __exit |
exit_befs_fs(void) |
{ |
befs_destroy_inodecache(); |
|
unregister_filesystem(&befs_fs_type); |
} |
|
/* |
Macros that typecheck the init and exit functions, |
ensures that they are called at init and cleanup, |
and eliminates warnings about unused functions. |
*/ |
module_init(init_befs_fs) |
module_exit(exit_befs_fs) |
/befs.h
0,0 → 1,152
/* |
* befs_fs.h |
* |
* Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com> |
* Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp) |
*/ |
|
#ifndef _LINUX_BEFS_H |
#define _LINUX_BEFS_H |
|
#include "befs_fs_types.h" |
|
/* used in debug.c */ |
#define BEFS_VERSION "0.9.3" |
|
typedef u64 befs_blocknr_t; |
typedef u32 vfs_blocknr_t; |
|
/* |
* BeFS in memory structures |
*/ |
|
typedef struct befs_mount_options { |
gid_t gid; |
uid_t uid; |
int use_gid; |
int use_uid; |
int debug; |
char *iocharset; |
} befs_mount_options; |
|
typedef struct befs_sb_info { |
u32 magic1; |
u32 block_size; |
u32 block_shift; |
int byte_order; |
befs_off_t num_blocks; |
befs_off_t used_blocks; |
u32 inode_size; |
u32 magic2; |
|
/* Allocation group information */ |
u32 blocks_per_ag; |
u32 ag_shift; |
u32 num_ags; |
|
/* jornal log entry */ |
befs_block_run log_blocks; |
befs_off_t log_start; |
befs_off_t log_end; |
|
befs_inode_addr root_dir; |
befs_inode_addr indices; |
u32 magic3; |
|
befs_mount_options mount_opts; |
struct nls_table *nls; |
|
} befs_sb_info; |
|
typedef struct befs_inode_info { |
u32 i_flags; |
u32 i_type; |
|
befs_inode_addr i_inode_num; |
befs_inode_addr i_parent; |
befs_inode_addr i_attribute; |
|
union { |
befs_data_stream ds; |
char symlink[BEFS_SYMLINK_LEN]; |
} i_data; |
|
} befs_inode_info; |
|
enum befs_err { |
BEFS_OK, |
BEFS_ERR, |
BEFS_BAD_INODE, |
BEFS_BT_END, |
BEFS_BT_EMPTY, |
BEFS_BT_MATCH, |
BEFS_BT_PARMATCH, |
BEFS_BT_NOT_FOUND |
}; |
|
/****************************/ |
/* debug.c */ |
void befs_error(const struct super_block *sb, const char *fmt, ...); |
void befs_warning(const struct super_block *sb, const char *fmt, ...); |
void befs_debug(const struct super_block *sb, const char *fmt, ...); |
|
void befs_dump_super_block(const struct super_block *sb, befs_super_block *); |
void befs_dump_inode(const struct super_block *sb, befs_inode *); |
void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *); |
void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *); |
void befs_dump_inode_addr(const struct super_block *sb, befs_inode_addr); |
/****************************/ |
|
/* Gets a pointer to the private portion of the super_block |
* structure from the public part |
*/ |
static inline befs_sb_info * |
BEFS_SB(const struct super_block *super) |
{ |
return (befs_sb_info *) super->u.generic_sbp; |
} |
|
static inline befs_inode_info * |
BEFS_I(const struct inode *inode) |
{ |
return (befs_inode_info *) inode->u.generic_ip; |
} |
|
static inline befs_blocknr_t |
iaddr2blockno(struct super_block *sb, befs_inode_addr * iaddr) |
{ |
return ((iaddr->allocation_group << BEFS_SB(sb)->ag_shift) + |
iaddr->start); |
} |
|
static inline befs_inode_addr |
blockno2iaddr(struct super_block *sb, befs_blocknr_t blockno) |
{ |
befs_inode_addr iaddr; |
iaddr.allocation_group = blockno >> BEFS_SB(sb)->ag_shift; |
iaddr.start = |
blockno - (iaddr.allocation_group << BEFS_SB(sb)->ag_shift); |
iaddr.len = 1; |
|
return iaddr; |
} |
|
static inline unsigned int |
befs_iaddrs_per_block(struct super_block *sb) |
{ |
return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr); |
} |
|
static inline int |
befs_iaddr_is_empty(befs_inode_addr * iaddr) |
{ |
return (!iaddr->allocation_group) && (!iaddr->start) && (!iaddr->len); |
} |
|
static inline size_t |
befs_brun_size(struct super_block *sb, befs_block_run run) |
{ |
return BEFS_SB(sb)->block_size * run.len; |
} |
|
#endif /* _LINUX_BEFS_H */ |
/TODO
0,0 → 1,11
TODO |
========== |
|
* Convert comments to the Kernel-Doc format. |
|
* See if Alexander Viro's option parser made it into the kernel tree. |
Use that if we can. (include/linux/parser.h) |
|
* See if we really need separate types for on-disk and in-memory |
representations of the superblock and inode. |
|
/datastream.c
0,0 → 1,528
/* |
* linux/fs/befs/datastream.c |
* |
* Copyright (C) 2001 Will Dyson <will_dyson@pobox.com> |
* |
* Based on portions of file.c by Makoto Kato <m_kato@ga2.so-net.ne.jp> |
* |
* Many thanks to Dominic Giampaolo, author of "Practical File System |
* Design with the Be File System", for such a helpful book. |
* |
*/ |
|
#include <linux/kernel.h> |
#include <linux/version.h> |
#include <linux/string.h> |
#include <linux/slab.h> |
|
#include "befs.h" |
#include "datastream.h" |
#include "io.h" |
#include "endian.h" |
|
const befs_inode_addr BAD_IADDR = { 0, 0, 0 }; |
|
static int befs_find_brun_direct(struct super_block *sb, |
befs_data_stream * data, |
befs_blocknr_t blockno, befs_block_run * run); |
|
static int befs_find_brun_indirect(struct super_block *sb, |
befs_data_stream * data, |
befs_blocknr_t blockno, |
befs_block_run * run); |
|
static int befs_find_brun_dblindirect(struct super_block *sb, |
befs_data_stream * data, |
befs_blocknr_t blockno, |
befs_block_run * run); |
|
/** |
* befs_read_datastream - get buffer_head containing data, starting from pos. |
* @sb: Filesystem superblock |
* @ds: datastrem to find data with |
* @pos: start of data |
* @off: offset of data in buffer_head->b_data |
* |
* Returns pointer to buffer_head containing data starting with offset @off, |
* if you don't need to know offset just set @off = NULL. |
*/ |
struct buffer_head * |
befs_read_datastream(struct super_block *sb, befs_data_stream * ds, |
befs_off_t pos, uint * off) |
{ |
struct buffer_head *bh = NULL; |
befs_block_run run; |
befs_blocknr_t block; /* block coresponding to pos */ |
|
befs_debug(sb, "---> befs_read_datastream() %Lu", pos); |
block = pos >> BEFS_SB(sb)->block_shift; |
if (off) |
*off = pos - (block << BEFS_SB(sb)->block_shift); |
|
if (befs_fblock2brun(sb, ds, block, &run) != BEFS_OK) { |
befs_error(sb, "BeFS: Error finding disk addr of block %lu", |
block); |
befs_debug(sb, "<--- befs_read_datastream() ERROR"); |
return NULL; |
} |
bh = befs_bread_iaddr(sb, run); |
if (!bh) { |
befs_error(sb, "BeFS: Error reading block %lu from datastream", |
block); |
return NULL; |
} |
|
befs_debug(sb, "<--- befs_read_datastream() read data, starting at %Lu", |
pos); |
|
return bh; |
} |
|
/* |
* Takes a file position and gives back a brun who's starting block |
* is block number fblock of the file. |
* |
* Returns BEFS_OK or BEFS_ERR. |
* |
* Calls specialized functions for each of the three possible |
* datastream regions. |
* |
* 2001-11-15 Will Dyson |
*/ |
int |
befs_fblock2brun(struct super_block *sb, befs_data_stream * data, |
befs_blocknr_t fblock, befs_block_run * run) |
{ |
int err; |
befs_off_t pos = fblock << BEFS_SB(sb)->block_shift; |
|
if (pos < data->max_direct_range) { |
err = befs_find_brun_direct(sb, data, fblock, run); |
|
} else if (pos < data->max_indirect_range) { |
err = befs_find_brun_indirect(sb, data, fblock, run); |
|
} else if (pos < data->max_double_indirect_range) { |
err = befs_find_brun_dblindirect(sb, data, fblock, run); |
|
} else { |
befs_error(sb, |
"befs_fblock2brun() was asked to find block %lu, " |
"which is not mapped by the datastream\n", fblock); |
err = BEFS_ERR; |
} |
return err; |
} |
|
/** |
* befs_read_lsmylink - read long symlink from datastream. |
* @sb: Filesystem superblock |
* @ds: Datastrem to read from |
* @buf: Buffer in wich to place long symlink data |
* @len: Length of the long symlink in bytes |
* |
* Returns the number of bytes read |
*/ |
size_t |
befs_read_lsymlink(struct super_block * sb, befs_data_stream * ds, void *buff, |
befs_off_t len) |
{ |
befs_off_t bytes_read = 0; /* bytes readed */ |
u16 plen; |
struct buffer_head *bh = NULL; |
befs_debug(sb, "---> befs_read_lsymlink() length: %Lu", len); |
|
while (bytes_read < len) { |
bh = befs_read_datastream(sb, ds, bytes_read, NULL); |
if (!bh) { |
befs_error(sb, "BeFS: Error reading datastream block " |
"starting from %Lu", bytes_read); |
befs_debug(sb, "<--- befs_read_lsymlink() ERROR"); |
return bytes_read; |
|
} |
plen = ((bytes_read + BEFS_SB(sb)->block_size) < len) ? |
BEFS_SB(sb)->block_size : len - bytes_read; |
memcpy(buff + bytes_read, bh->b_data, plen); |
brelse(bh); |
bytes_read += plen; |
} |
|
befs_debug(sb, "<--- befs_read_lsymlink() read %u bytes", bytes_read); |
return bytes_read; |
} |
|
/** |
* befs_count_blocks - blocks used by a file |
* @sb: Filesystem superblock |
* @ds: Datastream of the file |
* |
* Counts the number of fs blocks that the file represented by |
* inode occupies on the filesystem, counting both regular file |
* data and filesystem metadata (and eventually attribute data |
* when we support attributes) |
*/ |
|
befs_blocknr_t |
befs_count_blocks(struct super_block * sb, befs_data_stream * ds) |
{ |
befs_blocknr_t blocks; |
befs_blocknr_t datablocks; /* File data blocks */ |
befs_blocknr_t metablocks; /* FS metadata blocks */ |
befs_sb_info *befs_sb = BEFS_SB(sb); |
|
befs_debug(sb, "---> befs_count_blocks()"); |
|
datablocks = ds->size >> befs_sb->block_shift; |
if (ds->size & (befs_sb->block_size - 1)) |
datablocks += 1; |
|
metablocks = 1; /* Start with 1 block for inode */ |
|
/* Size of indirect block */ |
if (ds->size > ds->max_direct_range) |
metablocks += ds->indirect.len; |
|
/* |
Double indir block, plus all the indirect blocks it mapps |
In the double-indirect range, all block runs of data are |
BEFS_DBLINDIR_BRUN_LEN blocks long. Therefore, we know |
how many data block runs are in the double-indirect region, |
and from that we know how many indirect blocks it takes to |
map them. We assume that the indirect blocks are also |
BEFS_DBLINDIR_BRUN_LEN blocks long. |
*/ |
if (ds->size > ds->max_indirect_range && ds->max_indirect_range != 0) { |
uint dbl_bytes; |
uint dbl_bruns; |
uint indirblocks; |
|
dbl_bytes = |
ds->max_double_indirect_range - ds->max_indirect_range; |
dbl_bruns = |
dbl_bytes / (befs_sb->block_size * BEFS_DBLINDIR_BRUN_LEN); |
indirblocks = dbl_bruns / befs_iaddrs_per_block(sb); |
|
metablocks += ds->double_indirect.len; |
metablocks += indirblocks; |
} |
|
blocks = datablocks + metablocks; |
befs_debug(sb, "<--- befs_count_blocks() %u blocks", blocks); |
|
return blocks; |
} |
|
/* |
Finds the block run that starts at file block number blockno |
in the file represented by the datastream data, if that |
blockno is in the direct region of the datastream. |
|
sb: the superblock |
data: the datastream |
blockno: the blocknumber to find |
run: The found run is passed back through this pointer |
|
Return value is BEFS_OK if the blockrun is found, BEFS_ERR |
otherwise. |
|
Algorithm: |
Linear search. Checks each element of array[] to see if it |
contains the blockno-th filesystem block. This is nessisary |
because the block runs map variable amounts of data. Simply |
keeps a count of the number of blocks searched so far (sum), |
incrementing this by the length of each block run as we come |
across it. Adds sum to *count before returning (this is so |
you can search multiple arrays that are logicaly one array, |
as in the indirect region code). |
|
When/if blockno is found, if blockno is inside of a block |
run as stored on disk, we offset the start and lenght members |
of the block run, so that blockno is the start and len is |
still valid (the run ends in the same place). |
|
2001-11-15 Will Dyson |
*/ |
static int |
befs_find_brun_direct(struct super_block *sb, befs_data_stream * data, |
befs_blocknr_t blockno, befs_block_run * run) |
{ |
int i; |
befs_block_run *array = data->direct; |
befs_blocknr_t sum; |
befs_blocknr_t max_block = |
data->max_direct_range >> BEFS_SB(sb)->block_shift; |
|
befs_debug(sb, "---> befs_find_brun_direct(), find %lu", blockno); |
|
if (blockno > max_block) { |
befs_error(sb, "befs_find_brun_direct() passed block outside of" |
"direct region"); |
return BEFS_ERR; |
} |
|
for (i = 0, sum = 0; i < BEFS_NUM_DIRECT_BLOCKS; |
sum += array[i].len, i++) { |
if (blockno >= sum && blockno < sum + (array[i].len)) { |
int offset = blockno - sum; |
run->allocation_group = array[i].allocation_group; |
run->start = array[i].start + offset; |
run->len = array[i].len - offset; |
|
befs_debug(sb, "---> befs_find_brun_direct(), " |
"found %lu at direct[%d]", blockno, i); |
return BEFS_OK; |
} |
} |
|
befs_debug(sb, "---> befs_find_brun_direct() ERROR"); |
return BEFS_ERR; |
} |
|
/* |
Finds the block run that starts at file block number blockno |
in the file represented by the datastream data, if that |
blockno is in the indirect region of the datastream. |
|
sb: the superblock |
data: the datastream |
blockno: the blocknumber to find |
run: The found run is passed back through this pointer |
|
Return value is BEFS_OK if the blockrun is found, BEFS_ERR |
otherwise. |
|
Algorithm: |
For each block in the indirect run of the datastream, read |
it in and search through it for search_blk. |
|
XXX: |
Really should check to make sure blockno is inside indirect |
region. |
|
2001-11-15 Will Dyson |
*/ |
static int |
befs_find_brun_indirect(struct super_block *sb, |
befs_data_stream * data, befs_blocknr_t blockno, |
befs_block_run * run) |
{ |
int i, j; |
befs_blocknr_t sum = 0; |
befs_blocknr_t indir_start_blk; |
befs_blocknr_t search_blk; |
struct buffer_head *indirblock; |
befs_block_run *array; |
|
befs_block_run indirect = data->indirect; |
befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect); |
int arraylen = befs_iaddrs_per_block(sb); |
|
befs_debug(sb, "---> befs_find_brun_indirect(), find %lu", blockno); |
|
indir_start_blk = data->max_direct_range >> BEFS_SB(sb)->block_shift; |
search_blk = blockno - indir_start_blk; |
|
/* Examine blocks of the indirect run one at a time */ |
for (i = 0; i < indirect.len; i++) { |
indirblock = befs_bread(sb, indirblockno + i); |
if (indirblock == NULL) { |
befs_debug(sb, |
"---> befs_find_brun_indirect() failed to " |
"read disk block %lu from the indirect brun", |
indirblockno + i); |
return BEFS_ERR; |
} |
|
array = (befs_block_run *) indirblock->b_data; |
|
for (j = 0; j < arraylen; ++j) { |
int len = fs16_to_cpu(sb, array[j].len); |
|
if (search_blk >= sum && search_blk < sum + len) { |
int offset = search_blk - sum; |
run->allocation_group = |
fs32_to_cpu(sb, array[j].allocation_group); |
run->start = |
fs16_to_cpu(sb, array[j].start) + offset; |
run->len = |
fs16_to_cpu(sb, array[j].len) - offset; |
|
brelse(indirblock); |
befs_debug(sb, |
"<--- befs_find_brun_indirect() found " |
"file block %lu at indirect[%d]", |
blockno, j + (i * arraylen)); |
return BEFS_OK; |
} |
sum += len; |
} |
|
brelse(indirblock); |
} |
|
/* Only fallthrough is an error */ |
befs_error(sb, "BeFS: befs_find_brun_indirect() failed to find " |
"file block %lu", blockno); |
|
befs_debug(sb, "<--- befs_find_brun_indirect() ERROR"); |
return BEFS_ERR; |
} |
|
/* |
Finds the block run that starts at file block number blockno |
in the file represented by the datastream data, if that |
blockno is in the double-indirect region of the datastream. |
|
sb: the superblock |
data: the datastream |
blockno: the blocknumber to find |
run: The found run is passed back through this pointer |
|
Return value is BEFS_OK if the blockrun is found, BEFS_ERR |
otherwise. |
|
Algorithm: |
The block runs in the double-indirect region are different. |
They are always allocated 4 fs blocks at a time, so each |
block run maps a constant amount of file data. This means |
that we can directly calculate how many block runs into the |
double-indirect region we need to go to get to the one that |
maps a particular filesystem block. |
|
We do this in two stages. First we calculate which of the |
inode addresses in the double-indirect block will point us |
to the indirect block that contains the mapping for the data, |
then we calculate which of the inode addresses in that |
indirect block maps the data block we are after. |
|
Oh, and once we've done that, we actually read in the blocks |
that contain the inode addresses we calculated above. Even |
though the double-indirect run may be several blocks long, |
we can calculate which of those blocks will contain the index |
we are after and only read that one. We then follow it to |
the indirect block and perform a similar process to find |
the actual block run that maps the data block we are interested |
in. |
|
Then we offset the run as in befs_find_brun_array() and we are |
done. |
|
2001-11-15 Will Dyson |
*/ |
static int |
befs_find_brun_dblindirect(struct super_block *sb, |
befs_data_stream * data, befs_blocknr_t blockno, |
befs_block_run * run) |
{ |
int dblindir_indx; |
int indir_indx; |
int offset; |
int dbl_which_block; |
int which_block; |
int dbl_block_indx; |
int block_indx; |
off_t dblindir_leftover; |
befs_blocknr_t blockno_at_run_start; |
struct buffer_head *dbl_indir_block; |
struct buffer_head *indir_block; |
befs_block_run indir_run; |
befs_inode_addr *iaddr_array = NULL; |
befs_sb_info *befs_sb = BEFS_SB(sb); |
|
befs_blocknr_t indir_start_blk = |
data->max_indirect_range >> befs_sb->block_shift; |
|
off_t dbl_indir_off = blockno - indir_start_blk; |
|
/* number of data blocks mapped by each of the iaddrs in |
* the indirect block pointed to by the double indirect block |
*/ |
size_t iblklen = BEFS_DBLINDIR_BRUN_LEN; |
|
/* number of data blocks mapped by each of the iaddrs in |
* the double indirect block |
*/ |
size_t diblklen = iblklen * befs_iaddrs_per_block(sb) |
* BEFS_DBLINDIR_BRUN_LEN; |
|
befs_debug(sb, "---> befs_find_brun_dblindirect() find %lu", blockno); |
|
/* First, discover which of the double_indir->indir blocks |
* contains pos. Then figure out how much of pos that |
* accounted for. Then discover which of the iaddrs in |
* the indirect block contains pos. |
*/ |
|
dblindir_indx = dbl_indir_off / diblklen; |
dblindir_leftover = dbl_indir_off % diblklen; |
indir_indx = dblindir_leftover / diblklen; |
|
/* Read double indirect block */ |
dbl_which_block = dblindir_indx / befs_iaddrs_per_block(sb); |
if (dbl_which_block > data->double_indirect.len) { |
befs_error(sb, "The double-indirect index calculated by " |
"befs_read_brun_dblindirect(), %d, is outside the range " |
"of the double-indirect block", dblindir_indx); |
return BEFS_ERR; |
} |
|
dbl_indir_block = befs_bread(sb, |
iaddr2blockno(sb, &data->double_indirect) + |
dbl_which_block); |
if (dbl_indir_block == NULL) { |
befs_error(sb, "befs_read_brun_dblindirect() couldn't read the " |
"double-indirect block at blockno %lu", |
iaddr2blockno(sb, |
&data->double_indirect) + |
dbl_which_block); |
brelse(dbl_indir_block); |
return BEFS_ERR; |
} |
|
dbl_block_indx = |
dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb)); |
iaddr_array = (befs_inode_addr *) dbl_indir_block->b_data; |
indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]); |
brelse(dbl_indir_block); |
iaddr_array = NULL; |
|
/* Read indirect block */ |
which_block = indir_indx / befs_iaddrs_per_block(sb); |
if (which_block > indir_run.len) { |
befs_error(sb, "The indirect index calculated by " |
"befs_read_brun_dblindirect(), %d, is outside the range " |
"of the indirect block", indir_indx); |
return BEFS_ERR; |
} |
|
indir_block = |
befs_bread(sb, iaddr2blockno(sb, &indir_run) + which_block); |
if (indir_block == NULL) { |
befs_error(sb, "befs_read_brun_dblindirect() couldn't read the " |
"indirect block at blockno %lu", |
iaddr2blockno(sb, &indir_run) + which_block); |
brelse(indir_block); |
return BEFS_ERR; |
} |
|
block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb)); |
iaddr_array = (befs_inode_addr *) indir_block->b_data; |
*run = fsrun_to_cpu(sb, iaddr_array[block_indx]); |
brelse(indir_block); |
iaddr_array = NULL; |
|
blockno_at_run_start = indir_start_blk; |
blockno_at_run_start += diblklen * dblindir_indx; |
blockno_at_run_start += iblklen * indir_indx; |
offset = blockno - blockno_at_run_start; |
|
run->start += offset; |
run->len -= offset; |
|
befs_debug(sb, "Found file block %lu in double_indirect[%d][%d]," |
" double_indirect_leftover = %lu", |
blockno, dblindir_indx, indir_indx, dblindir_leftover); |
|
return BEFS_OK; |
} |
/debug.c
0,0 → 1,263
/* |
* linux/fs/befs/debug.c |
* |
* Copyright (C) 2001 Will Dyson (will_dyson at pobox.com) |
* |
* With help from the ntfs-tng driver by Anton Altparmakov |
* |
* Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp) |
* |
* debug functions |
*/ |
|
#ifdef __KERNEL__ |
|
#include <stdarg.h> |
#include <linux/string.h> |
#include <linux/spinlock.h> |
#include <linux/kernel.h> |
#include <linux/fs.h> |
|
#endif /* __KERNEL__ */ |
|
#include "befs.h" |
#include "endian.h" |
|
#define ERRBUFSIZE 1024 |
|
void |
befs_error(const struct super_block *sb, const char *fmt, ...) |
{ |
va_list args; |
char err_buf[ERRBUFSIZE]; |
|
va_start(args, fmt); |
vsnprintf(err_buf, ERRBUFSIZE, fmt, args); |
va_end(args); |
|
printk(KERN_ERR "BeFS(%s): %s\n", bdevname(sb->s_dev), err_buf); |
|
befs_debug(sb, err_buf); |
} |
|
void |
befs_warning(const struct super_block *sb, const char *fmt, ...) |
{ |
va_list args; |
char err_buf[ERRBUFSIZE]; |
|
va_start(args, fmt); |
vsnprintf(err_buf, ERRBUFSIZE, fmt, args); |
va_end(args); |
|
printk(KERN_WARNING "BeFS(%s): %s\n", bdevname(sb->s_dev), err_buf); |
|
befs_debug(sb, err_buf); |
} |
|
void |
befs_debug(const struct super_block *sb, const char *fmt, ...) |
{ |
#ifdef CONFIG_BEFS_DEBUG |
|
va_list args; |
char err_buf[ERRBUFSIZE]; |
|
if (BEFS_SB(sb)->mount_opts.debug) { |
va_start(args, fmt); |
vsnprintf(err_buf, ERRBUFSIZE, fmt, args); |
va_end(args); |
|
printk(KERN_DEBUG "BeFS(%s): %s\n", |
bdevname(sb->s_dev), err_buf); |
} |
#endif //CONFIG_BEFS_DEBUG |
} |
|
void |
befs_dump_inode(const struct super_block *sb, befs_inode * inode) |
{ |
#ifdef CONFIG_BEFS_DEBUG |
|
befs_block_run tmp_run; |
|
befs_debug(sb, "befs_inode infomation"); |
|
befs_debug(sb, " magic1 %08x", fs32_to_cpu(sb, inode->magic1)); |
|
tmp_run = fsrun_to_cpu(sb, inode->inode_num); |
befs_debug(sb, " inode_num %u, %hu, %hu", |
tmp_run.allocation_group, tmp_run.start, tmp_run.len); |
|
befs_debug(sb, " uid %u", fs32_to_cpu(sb, inode->uid)); |
befs_debug(sb, " gid %u", fs32_to_cpu(sb, inode->gid)); |
befs_debug(sb, " mode %08x", fs32_to_cpu(sb, inode->mode)); |
befs_debug(sb, " flags %08x", fs32_to_cpu(sb, inode->flags)); |
befs_debug(sb, " create_time %Lu", |
fs64_to_cpu(sb, inode->create_time)); |
befs_debug(sb, " last_modified_time %Lu", |
fs64_to_cpu(sb, inode->last_modified_time)); |
|
tmp_run = fsrun_to_cpu(sb, inode->parent); |
befs_debug(sb, " parent [%u, %hu, %hu]", |
tmp_run.allocation_group, tmp_run.start, tmp_run.len); |
|
tmp_run = fsrun_to_cpu(sb, inode->attributes); |
befs_debug(sb, " attributes [%u, %hu, %hu]", |
tmp_run.allocation_group, tmp_run.start, tmp_run.len); |
|
befs_debug(sb, " type %08x", fs32_to_cpu(sb, inode->type)); |
befs_debug(sb, " inode_size %u", fs32_to_cpu(sb, inode->inode_size)); |
|
if (S_ISLNK(inode->mode)) { |
befs_debug(sb, " Symbolic link [%s]", inode->data.symlink); |
} else { |
int i; |
|
for (i = 0; i < BEFS_NUM_DIRECT_BLOCKS; i++) { |
tmp_run = |
fsrun_to_cpu(sb, inode->data.datastream.direct[i]); |
befs_debug(sb, " direct %d [%u, %hu, %hu]", i, |
tmp_run.allocation_group, tmp_run.start, |
tmp_run.len); |
} |
befs_debug(sb, " max_direct_range %Lu", |
fs64_to_cpu(sb, |
inode->data.datastream. |
max_direct_range)); |
|
tmp_run = fsrun_to_cpu(sb, inode->data.datastream.indirect); |
befs_debug(sb, " indirect [%u, %hu, %hu]", |
tmp_run.allocation_group, |
tmp_run.start, tmp_run.len); |
|
befs_debug(sb, " max_indirect_range %Lu", |
fs64_to_cpu(sb, |
inode->data.datastream. |
max_indirect_range)); |
|
tmp_run = |
fsrun_to_cpu(sb, inode->data.datastream.double_indirect); |
befs_debug(sb, " double indirect [%u, %hu, %hu]", |
tmp_run.allocation_group, tmp_run.start, |
tmp_run.len); |
|
befs_debug(sb, " max_double_indirect_range %Lu", |
fs64_to_cpu(sb, |
inode->data.datastream. |
max_double_indirect_range)); |
|
befs_debug(sb, " size %Lu", |
fs64_to_cpu(sb, inode->data.datastream.size)); |
} |
|
#endif //CONFIG_BEFS_DEBUG |
} |
|
/* |
* Display super block structure for debug. |
*/ |
|
void |
befs_dump_super_block(const struct super_block *sb, befs_super_block * sup) |
{ |
#ifdef CONFIG_BEFS_DEBUG |
|
befs_block_run tmp_run; |
|
befs_debug(sb, "befs_super_block information"); |
|
befs_debug(sb, " name %s", sup->name); |
befs_debug(sb, " magic1 %08x", fs32_to_cpu(sb, sup->magic1)); |
befs_debug(sb, " fs_byte_order %08x", |
fs32_to_cpu(sb, sup->fs_byte_order)); |
|
befs_debug(sb, " block_size %u", fs32_to_cpu(sb, sup->block_size)); |
befs_debug(sb, " block_shift %u", fs32_to_cpu(sb, sup->block_shift)); |
|
befs_debug(sb, " num_blocks %Lu", fs64_to_cpu(sb, sup->num_blocks)); |
befs_debug(sb, " used_blocks %Lu", fs64_to_cpu(sb, sup->used_blocks)); |
|
befs_debug(sb, " magic2 %08x", fs32_to_cpu(sb, sup->magic2)); |
befs_debug(sb, " blocks_per_ag %u", |
fs32_to_cpu(sb, sup->blocks_per_ag)); |
befs_debug(sb, " ag_shift %u", fs32_to_cpu(sb, sup->ag_shift)); |
befs_debug(sb, " num_ags %u", fs32_to_cpu(sb, sup->num_ags)); |
|
befs_debug(sb, " flags %08x", fs32_to_cpu(sb, sup->flags)); |
|
tmp_run = fsrun_to_cpu(sb, sup->log_blocks); |
befs_debug(sb, " log_blocks %u, %hu, %hu", |
tmp_run.allocation_group, tmp_run.start, tmp_run.len); |
|
befs_debug(sb, " log_start %Ld", fs64_to_cpu(sb, sup->log_start)); |
befs_debug(sb, " log_end %Ld", fs64_to_cpu(sb, sup->log_end)); |
|
befs_debug(sb, " magic3 %08x", fs32_to_cpu(sb, sup->magic3)); |
|
tmp_run = fsrun_to_cpu(sb, sup->root_dir); |
befs_debug(sb, " root_dir %u, %hu, %hu", |
tmp_run.allocation_group, tmp_run.start, tmp_run.len); |
|
tmp_run = fsrun_to_cpu(sb, sup->indices); |
befs_debug(sb, " indices %u, %hu, %hu", |
tmp_run.allocation_group, tmp_run.start, tmp_run.len); |
|
#endif //CONFIG_BEFS_DEBUG |
} |
|
void |
befs_dump_small_data(const struct super_block *sb, befs_small_data * sd) |
{ |
} |
|
void |
befs_dump_run(const struct super_block *sb, befs_block_run run) |
{ |
#ifdef CONFIG_BEFS_DEBUG |
|
run = fsrun_to_cpu(sb, run); |
|
befs_debug(sb, "[%u, %hu, %hu]", |
run.allocation_group, run.start, run.len); |
|
#endif //CONFIG_BEFS_DEBUG |
} |
|
void |
befs_dump_index_entry(const struct super_block *sb, befs_btree_super * super) |
{ |
#ifdef CONFIG_BEFS_DEBUG |
|
befs_debug(sb, "Btree super structure"); |
befs_debug(sb, " magic %08x", fs32_to_cpu(sb, super->magic)); |
befs_debug(sb, " node_size %u", fs32_to_cpu(sb, super->node_size)); |
befs_debug(sb, " max_depth %08x", fs32_to_cpu(sb, super->max_depth)); |
|
befs_debug(sb, " data_type %08x", fs32_to_cpu(sb, super->data_type)); |
befs_debug(sb, " root_node_pointer %016LX", |
fs64_to_cpu(sb, super->root_node_ptr)); |
befs_debug(sb, " free_node_pointer %016LX", |
fs64_to_cpu(sb, super->free_node_ptr)); |
befs_debug(sb, " maximum size %016LX", |
fs64_to_cpu(sb, super->max_size)); |
|
#endif //CONFIG_BEFS_DEBUG |
} |
|
void |
befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead * node) |
{ |
#ifdef CONFIG_BEFS_DEBUG |
|
befs_debug(sb, "Btree node structure"); |
befs_debug(sb, " left %016LX", fs64_to_cpu(sb, node->left)); |
befs_debug(sb, " right %016LX", fs64_to_cpu(sb, node->right)); |
befs_debug(sb, " overflow %016LX", fs64_to_cpu(sb, node->overflow)); |
befs_debug(sb, " all_key_count %hu", |
fs16_to_cpu(sb, node->all_key_count)); |
befs_debug(sb, " all_key_length %hu", |
fs16_to_cpu(sb, node->all_key_length)); |
|
#endif //CONFIG_BEFS_DEBUG |
} |
/datastream.h
0,0 → 1,18
/* |
* datastream.h |
* |
*/ |
|
struct buffer_head *befs_read_datastream(struct super_block *sb, |
befs_data_stream * ds, befs_off_t pos, |
uint * off); |
|
int befs_fblock2brun(struct super_block *sb, befs_data_stream * data, |
befs_blocknr_t fblock, befs_block_run * run); |
|
size_t befs_read_lsymlink(struct super_block *sb, befs_data_stream * data, |
void *buff, befs_off_t len); |
|
befs_blocknr_t befs_count_blocks(struct super_block *sb, befs_data_stream * ds); |
|
extern const befs_inode_addr BAD_IADDR; |
/Makefile
0,0 → 1,15
# |
# Makefile for the linux BeOS filesystem routines. |
# |
# Note! Dependencies are done automagically by 'make dep', which also |
# removes any old dependencies. DON'T put your own dependencies here |
# unless it's something special (ie not a .c file). |
# |
# Note 2! The CFLAGS definitions are now in the main makefile... |
|
O_TARGET := befs.o |
|
obj-y := datastream.o btree.o super.o inode.o debug.o io.o linuxvfs.o |
obj-m := $(O_TARGET) |
|
include $(TOPDIR)/Rules.make |