Initial commit -- seeded with reiserfsprogs 3.x.0j
This commit is contained in:
commit
e7102bdb66
77 files changed
+33513
No files matched your search
@@ -0,0 +1,887 @@
|
||||
/*
|
||||
* Copyrright 2000 by Hans Reiser, licensing governed by reiserfs/README
|
||||
*/
|
||||
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
|
||||
/* this only checks that the node looks like a correct leaf. Item
|
||||
internals are not checked */
|
||||
static int is_correct_leaf (char * buf, int blocksize)
|
||||
{
|
||||
struct block_head * blkh;
|
||||
struct item_head * ih;
|
||||
int used_space;
|
||||
int prev_location;
|
||||
int i;
|
||||
int nr;
|
||||
|
||||
blkh = (struct block_head *)buf;
|
||||
if (!is_leaf_block_head (buf))
|
||||
return 0;
|
||||
|
||||
nr = le16_to_cpu (blkh->blk_nr_item);
|
||||
if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN)))
|
||||
/* item number is too big or too small */
|
||||
return 0;
|
||||
|
||||
ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1;
|
||||
used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location (ih));
|
||||
if (used_space != blocksize - le16_to_cpu (blkh->blk_free_space))
|
||||
/* free space does not match to calculated amount of use space */
|
||||
return 0;
|
||||
|
||||
// FIXME: it is_leaf will hit performance too much - we may have
|
||||
// return 1 here
|
||||
|
||||
/* check tables of item heads */
|
||||
ih = (struct item_head *)(buf + BLKH_SIZE);
|
||||
prev_location = blocksize;
|
||||
for (i = 0; i < nr; i ++, ih ++) {
|
||||
/* items of length are allowed - they may exist for short time
|
||||
during balancing */
|
||||
if (ih_location (ih) > blocksize || ih_location (ih) < IH_SIZE * nr)
|
||||
return 0;
|
||||
if (/*ih_item_len (ih) < 1 ||*/ ih_item_len (ih) > MAX_ITEM_LEN (blocksize))
|
||||
return 0;
|
||||
if (prev_location - ih_location (ih) != ih_item_len (ih))
|
||||
return 0;
|
||||
prev_location = ih_location (ih);
|
||||
}
|
||||
|
||||
// one may imagine much more checks
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* returns 1 if buf looks like an internal node, 0 otherwise */
|
||||
static int is_correct_internal (char * buf, int blocksize)
|
||||
{
|
||||
struct block_head * blkh;
|
||||
int nr;
|
||||
int used_space;
|
||||
|
||||
blkh = (struct block_head *)buf;
|
||||
|
||||
if (!is_internal_block_head (buf))
|
||||
return 0;
|
||||
|
||||
nr = le16_to_cpu (blkh->blk_nr_item);
|
||||
if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE))
|
||||
/* for internal which is not root we might check min number of keys */
|
||||
return 0;
|
||||
|
||||
used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1);
|
||||
if (used_space != blocksize - le16_to_cpu (blkh->blk_free_space))
|
||||
return 0;
|
||||
|
||||
// one may imagine much more checks
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// make sure that bh contains formatted node of reiserfs tree of
|
||||
// 'level'-th level
|
||||
int is_tree_node (struct buffer_head * bh, int level)
|
||||
{
|
||||
if (B_LEVEL (bh) != level)
|
||||
return 0;
|
||||
if (is_leaf_node (bh))
|
||||
return is_correct_leaf (bh->b_data, bh->b_size);
|
||||
|
||||
return is_correct_internal (bh->b_data, bh->b_size);
|
||||
}
|
||||
|
||||
|
||||
static int is_desc_block (struct reiserfs_journal_desc * desc)
|
||||
{
|
||||
if (!memcmp(desc->j_magic, JOURNAL_DESC_MAGIC, 8) &&
|
||||
le32_to_cpu (desc->j_len) > 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int is_reiserfs_magic_string (struct reiserfs_super_block * rs)
|
||||
{
|
||||
return (!strncmp (rs->s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING,
|
||||
strlen ( REISERFS_SUPER_MAGIC_STRING)));
|
||||
}
|
||||
|
||||
|
||||
int is_reiser2fs_magic_string (struct reiserfs_super_block * rs)
|
||||
{
|
||||
return (!strncmp (rs->s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING,
|
||||
strlen ( REISER2FS_SUPER_MAGIC_STRING)));
|
||||
}
|
||||
|
||||
|
||||
/* this one had signature in different place of the super_block
|
||||
structure */
|
||||
int is_prejournaled_reiserfs (struct reiserfs_super_block * rs)
|
||||
{
|
||||
return (!strncmp((char*)rs + REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ,
|
||||
REISERFS_SUPER_MAGIC_STRING, strlen(REISERFS_SUPER_MAGIC_STRING)));
|
||||
}
|
||||
|
||||
|
||||
/* compares description block with commit block. returns 1 if they differ, 0 if they are the same */
|
||||
int does_desc_match_commit (struct reiserfs_journal_desc *desc,
|
||||
struct reiserfs_journal_commit *commit)
|
||||
{
|
||||
if (commit->j_trans_id != desc->j_trans_id || commit->j_len != desc->j_len ||
|
||||
commit->j_len > JOURNAL_TRANS_MAX || commit->j_len <= 0) {
|
||||
return 1 ;
|
||||
}
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
|
||||
/* returns code of reiserfs metadata block (leaf, internal, super
|
||||
block, journal descriptor), unformatted */
|
||||
int who_is_this (char * buf, int blocksize)
|
||||
{
|
||||
if (is_correct_leaf (buf, blocksize))
|
||||
/* block head and item head array seem matching (node level, free
|
||||
space, item number, item locations and length) */
|
||||
return THE_LEAF;
|
||||
|
||||
if (is_correct_internal (buf, blocksize))
|
||||
return THE_INTERNAL;
|
||||
|
||||
/* super block? */
|
||||
if (is_reiser2fs_magic_string ((void *)buf) ||
|
||||
is_reiserfs_magic_string ((void *)buf) ||
|
||||
is_prejournaled_reiserfs ((void *)buf))
|
||||
return THE_SUPER;
|
||||
|
||||
/* journal descriptor block? */
|
||||
if (is_desc_block ((void *)buf))
|
||||
return THE_JDESC;
|
||||
|
||||
/* contents of buf does not look like reiserfs metadata. Bitmaps
|
||||
are possible here */
|
||||
return THE_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
int block_of_journal (reiserfs_filsys_t fs, unsigned long block)
|
||||
{
|
||||
if (block >= SB_JOURNAL_BLOCK (fs) &&
|
||||
block <= SB_JOURNAL_BLOCK (fs) + JOURNAL_BLOCK_COUNT)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int block_of_bitmap (reiserfs_filsys_t fs, unsigned long block)
|
||||
{
|
||||
if (spread_bitmaps (fs)) {
|
||||
if (!(block % (fs->s_blocksize * 8)))
|
||||
/* bitmap block */
|
||||
return 1;
|
||||
return block == 17;
|
||||
} else {
|
||||
/* bitmap in */
|
||||
if (block > 2 && block < 3 + SB_BMAP_NR (fs))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
int i;
|
||||
int bmap_nr;
|
||||
|
||||
bmap_nr = SB_BMAP_NR (fs);
|
||||
for (i = 0; i < bmap_nr; i ++)
|
||||
if (block == SB_AP_BITMAP (fs)[i]->b_blocknr)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* check whether 'block' can be pointed to by an indirect item */
|
||||
int not_data_block (reiserfs_filsys_t fs, unsigned long block)
|
||||
{
|
||||
if (block_of_bitmap (fs, block))
|
||||
/* it is one of bitmap blocks */
|
||||
return 1;
|
||||
|
||||
if (block > 32768)
|
||||
return 0;
|
||||
|
||||
if (block_of_journal (fs, block))
|
||||
/* block of journal area */
|
||||
return 1;
|
||||
|
||||
if (block <= fs->s_sbh->b_blocknr)
|
||||
/* either super block or a block from skipped area at the
|
||||
beginning of filesystem */
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* check whether 'block' can be logged */
|
||||
int not_journalable (reiserfs_filsys_t fs, unsigned long block)
|
||||
{
|
||||
/* we should not update SB with journal copy during fsck */
|
||||
if (block < fs->s_sbh->b_blocknr)
|
||||
return 1;
|
||||
|
||||
if (block_of_journal (fs, block))
|
||||
return 1;
|
||||
|
||||
if (block >= SB_BLOCK_COUNT (fs))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// in reiserfs version 0 (undistributed bitmap)
|
||||
// FIXME: what if number of bitmaps is 15?
|
||||
int get_journal_old_start_must (struct reiserfs_super_block * rs)
|
||||
{
|
||||
return 3 + rs_bmap_nr (rs);
|
||||
}
|
||||
|
||||
|
||||
// in reiserfs version 1 (distributed bitmap) journal starts at 18-th
|
||||
//
|
||||
int get_journal_start_must (int blocksize)
|
||||
{
|
||||
return (REISERFS_DISK_OFFSET_IN_BYTES / blocksize) + 2;
|
||||
}
|
||||
|
||||
int get_bmap_num (struct super_block * s)
|
||||
{
|
||||
return ((is_prejournaled_reiserfs (s->s_rs)) ?
|
||||
(((struct reiserfs_super_block_v0 *)s->s_rs)->s_bmap_nr) :
|
||||
SB_BMAP_NR (s));
|
||||
}
|
||||
|
||||
int get_block_count (struct super_block * s)
|
||||
{
|
||||
return ((is_prejournaled_reiserfs (s->s_rs)) ?
|
||||
(((struct reiserfs_super_block_v0 *)s->s_rs)->s_block_count) :
|
||||
SB_BLOCK_COUNT (s));
|
||||
}
|
||||
|
||||
int get_root_block (struct super_block * s)
|
||||
{
|
||||
return ((is_prejournaled_reiserfs (s->s_rs)) ?
|
||||
(((struct reiserfs_super_block_v0 *)s->s_rs)->s_root_block) :
|
||||
SB_ROOT_BLOCK (s));
|
||||
}
|
||||
|
||||
|
||||
|
||||
int journal_size (struct super_block * s)
|
||||
{
|
||||
return JOURNAL_BLOCK_COUNT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int check_item_f (reiserfs_filsys_t fs, struct item_head * ih, char * item);
|
||||
|
||||
|
||||
/* make sure that key format written in item_head matches to key format
|
||||
defined looking at the key */
|
||||
static int is_key_correct (struct item_head * ih)
|
||||
{
|
||||
if (is_stat_data_ih (ih)) {
|
||||
/* stat data key looks identical in both formats */
|
||||
if (ih_item_len (ih) == SD_SIZE && ih_key_format (ih) == KEY_FORMAT_2) {
|
||||
/*printf ("new stat data\n");*/
|
||||
return 1;
|
||||
}
|
||||
if (ih_item_len (ih) == SD_V1_SIZE && ih_key_format (ih) == KEY_FORMAT_1) {
|
||||
/*printf ("old stat data\n");*/
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (ih_key_format (ih) == key_format (&ih->ih_key))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* check stat data item length, ih_free_space, mode */
|
||||
static int is_bad_sd (reiserfs_filsys_t fs, struct item_head * ih, char * item)
|
||||
{
|
||||
mode_t mode;
|
||||
|
||||
if (ih_entry_count (ih) != 0xffff)
|
||||
return 1;
|
||||
|
||||
if (ih_key_format (ih) == KEY_FORMAT_1) {
|
||||
struct stat_data_v1 * sd = (struct stat_data_v1 *)item;
|
||||
|
||||
if (ih_item_len (ih) != SD_V1_SIZE)
|
||||
/* old stat data must be 32 bytes long */
|
||||
return 1;
|
||||
mode = le16_to_cpu (sd->sd_mode);
|
||||
} else if (ih_key_format (ih) == KEY_FORMAT_2) {
|
||||
struct stat_data * sd = (struct stat_data *)item;
|
||||
|
||||
if (ih_item_len (ih) != SD_SIZE)
|
||||
/* new stat data must be 44 bytes long */
|
||||
return 1;
|
||||
mode = le16_to_cpu (sd->sd_mode);
|
||||
} else
|
||||
return 1;
|
||||
|
||||
if (!S_ISDIR (mode) && !S_ISREG (mode) && !S_ISCHR (mode) &&
|
||||
!S_ISBLK (mode) && !S_ISLNK (mode) && !S_ISFIFO (mode) &&
|
||||
!S_ISSOCK (mode))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* symlinks created by 3.6.x have direct items with ih_free_space == 0 */
|
||||
static int is_bad_direct (reiserfs_filsys_t fs, struct item_head * ih, char * item)
|
||||
{
|
||||
if (ih_entry_count (ih) != 0xffff && ih_entry_count (ih) != 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* check item length, ih_free_space for pure 3.5 format, unformatted node
|
||||
pointers */
|
||||
static int is_bad_indirect (reiserfs_filsys_t fs, struct item_head * ih, char * item,
|
||||
check_unfm_func_t check_unfm_func)
|
||||
{
|
||||
int i;
|
||||
__u32 * ind = (__u32 *)item;
|
||||
|
||||
if (ih_item_len (ih) % UNFM_P_SIZE)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < I_UNFM_NUM (ih); i ++) {
|
||||
if (!ind [i])
|
||||
continue;
|
||||
if (check_unfm_func && check_unfm_func (fs, ind [i]))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fs->s_version == REISERFS_VERSION_1) {
|
||||
/* check ih_free_space for 3.5 format only */
|
||||
if (ih_free_space (ih) > fs->s_blocksize - 1)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct {
|
||||
hashf_t func;
|
||||
char * name;
|
||||
} hashes[] = {{0, "not set"},
|
||||
{keyed_hash, "\"tea\""},
|
||||
{yura_hash, "\"rupasov\""},
|
||||
{r5_hash, "\"r5\""}};
|
||||
|
||||
#define HASH_AMOUNT (sizeof (hashes) / sizeof (hashes [0]))
|
||||
|
||||
|
||||
int known_hashes (void)
|
||||
{
|
||||
return HASH_AMOUNT;
|
||||
}
|
||||
|
||||
|
||||
#define good_name(hashfn,name,namelen,deh_offset) \
|
||||
(GET_HASH_VALUE ((hashfn) (name, namelen)) == GET_HASH_VALUE (deh_offset))
|
||||
|
||||
|
||||
/* this also sets hash function */
|
||||
int is_properly_hashed (reiserfs_filsys_t fs,
|
||||
char * name, int namelen, __u32 offset)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (namelen == 1 && name[0] == '.') {
|
||||
if (offset == DOT_OFFSET)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (namelen == 2 && name[0] == '.' && name[1] == '.') {
|
||||
if (offset == DOT_DOT_OFFSET)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hash_func_is_unknown (fs)) {
|
||||
/* try to find what hash function the name is sorted with */
|
||||
for (i = 1; i < HASH_AMOUNT; i ++) {
|
||||
if (good_name (hashes [i].func, name, namelen, offset)) {
|
||||
if (!hash_func_is_unknown (fs)) {
|
||||
/* two or more hash functions give the same value for this
|
||||
name */
|
||||
fprintf (stderr, "Detecting hash code: could not detect hash with name \"%.*s\"\n",
|
||||
namelen, name);
|
||||
reiserfs_hash (fs) = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* set hash function */
|
||||
reiserfs_hash(fs) = hashes [i].func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (good_name (reiserfs_hash(fs), name, namelen, offset))
|
||||
return 1;
|
||||
#if 0
|
||||
fprintf (stderr, "is_properly_hashed: namelen %d, name \"%s\", offset %u, hash %u\n",
|
||||
namelen, name_from_entry (name, namelen), GET_HASH_VALUE (offset),
|
||||
GET_HASH_VALUE (reiserfs_hash(fs) (name, namelen)));
|
||||
|
||||
/* we could also check whether more than one hash function match on the
|
||||
name */
|
||||
for (i = 1; i < sizeof (hashes) / sizeof (hashes [0]); i ++) {
|
||||
if (i == g_real_hash)
|
||||
continue;
|
||||
if (good_name (hashes[i], name, namelen, deh_offset)) {
|
||||
die ("bad_hash: at least two hashes got screwed up with this name: \"%s\"",
|
||||
bad_name (name, namelen));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int find_hash_in_use (char * name, int namelen, __u32 hash_value_masked, int code_to_try_first)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (code_to_try_first) {
|
||||
if (hash_value_masked == GET_HASH_VALUE (hashes [code_to_try_first].func (name, namelen)))
|
||||
return code_to_try_first;
|
||||
}
|
||||
for (i = 1; i < HASH_AMOUNT; i ++) {
|
||||
if (i == code_to_try_first)
|
||||
continue;
|
||||
if (hash_value_masked == GET_HASH_VALUE (hashes [i].func (name, namelen)))
|
||||
return i;
|
||||
}
|
||||
|
||||
/* not matching hash found */
|
||||
return UNSET_HASH;
|
||||
}
|
||||
|
||||
|
||||
char * code2name (int code)
|
||||
{
|
||||
if (code >= HASH_AMOUNT)
|
||||
code = 0;
|
||||
return hashes [code].name;
|
||||
}
|
||||
|
||||
|
||||
int func2code (hashf_t func)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < HASH_AMOUNT; i ++)
|
||||
if (func == hashes [i].func)
|
||||
return i;
|
||||
|
||||
reiserfs_panic ("func2code: no hashes matches this function\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
hashf_t code2func (int code)
|
||||
{
|
||||
if (code >= HASH_AMOUNT) {
|
||||
reiserfs_warning (stderr, "code2func: wrong hash code %d.\n"
|
||||
"Using default %s hash function\n", code,
|
||||
code2name (DEFAULT_HASH));
|
||||
code = DEFAULT_HASH;
|
||||
}
|
||||
return hashes [code].func;
|
||||
}
|
||||
|
||||
|
||||
int dir_entry_bad_location (struct reiserfs_de_head * deh, struct item_head * ih, int first)
|
||||
{
|
||||
if (deh_location (deh) < DEH_SIZE * ih_entry_count (ih))
|
||||
return 1;
|
||||
|
||||
if (deh_location (deh) >= ih_item_len (ih))
|
||||
return 1;
|
||||
|
||||
if (!first && deh_location (deh) >= deh_location (deh - 1))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* the only corruption which is not considered fatal - is hash mismatching. If
|
||||
bad_dir is set - directory item having such names is considered bad */
|
||||
static int is_bad_directory (reiserfs_filsys_t fs, struct item_head * ih, char * item,
|
||||
int bad_dir)
|
||||
{
|
||||
int i;
|
||||
int namelen;
|
||||
struct reiserfs_de_head * deh = (struct reiserfs_de_head *)item;
|
||||
__u32 prev_offset = 0;
|
||||
__u16 prev_location = ih_item_len (ih);
|
||||
|
||||
for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
|
||||
if (deh_location (deh) >= prev_location)
|
||||
return 1;
|
||||
prev_location = deh_location (deh);
|
||||
|
||||
namelen = name_length (ih, deh, i);
|
||||
if (namelen > REISERFS_MAX_NAME_LEN (fs->s_blocksize)) {
|
||||
return 1;
|
||||
}
|
||||
if (deh_offset (deh) <= prev_offset)
|
||||
return 1;
|
||||
prev_offset = deh_offset (deh);
|
||||
|
||||
/* check hash value */
|
||||
if (!is_properly_hashed (fs, item + prev_location, namelen, prev_offset)) {
|
||||
if (bad_dir)
|
||||
/* make is_bad_leaf to not insert whole leaf. Node will be
|
||||
marked not-insertable and put into tree item by item in
|
||||
pass 2 */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* used by debugreisrefs -p only yet */
|
||||
#if 1
|
||||
int is_it_bad_item (reiserfs_filsys_t fs, struct item_head * ih, char * item,
|
||||
check_unfm_func_t check_unfm, int bad_dir)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (!is_key_correct (ih)) {
|
||||
reiserfs_warning (stderr, "is_key_correct %H\n", ih);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (is_stat_data_ih (ih)) {
|
||||
retval = is_bad_sd (fs, ih, item);
|
||||
/*
|
||||
if (retval)
|
||||
reiserfs_warning (stderr, "is_bad_sd %H\n", ih);*/
|
||||
return retval;
|
||||
}
|
||||
if (is_direntry_ih (ih)) {
|
||||
retval = is_bad_directory (fs, ih, item, bad_dir);
|
||||
/*
|
||||
if (retval)
|
||||
reiserfs_warning (stderr, "is_bad_directory %H\n", ih);*/
|
||||
return retval;
|
||||
}
|
||||
if (is_indirect_ih (ih)) {
|
||||
retval = is_bad_indirect (fs, ih, item, check_unfm);
|
||||
/*
|
||||
if (retval)
|
||||
reiserfs_warning (stderr, "is_bad_indirect %H\n", ih);*/
|
||||
return retval;
|
||||
}
|
||||
if (is_direct_ih (ih)) {
|
||||
retval = is_bad_direct (fs, ih, item);
|
||||
/*
|
||||
if (retval)
|
||||
reiserfs_warning (stderr, "is_bad_direct %H\n", ih);*/
|
||||
return retval;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* prepare new or old stat data for the new directory */
|
||||
void make_dir_stat_data (int blocksize, int key_format,
|
||||
__u32 dirid, __u32 objectid,
|
||||
struct item_head * ih, void * sd)
|
||||
{
|
||||
memset (ih, 0, IH_SIZE);
|
||||
ih->ih_key.k_dir_id = cpu_to_le32 (dirid);
|
||||
ih->ih_key.k_objectid = cpu_to_le32 (objectid);
|
||||
set_offset (key_format, &ih->ih_key, SD_OFFSET);
|
||||
set_type (key_format, &ih->ih_key, TYPE_STAT_DATA);
|
||||
|
||||
set_key_format (ih, key_format);
|
||||
set_free_space (ih, MAX_US_INT);
|
||||
|
||||
if (key_format == KEY_FORMAT_2)
|
||||
{
|
||||
struct stat_data *sd_v2 = (struct stat_data *)sd;
|
||||
|
||||
set_ih_item_len (ih, SD_SIZE);
|
||||
sd_v2->sd_mode = cpu_to_le16 (S_IFDIR + 0755);
|
||||
sd_v2->sd_nlink = cpu_to_le32 (2);
|
||||
sd_v2->sd_uid = 0;
|
||||
sd_v2->sd_gid = 0;
|
||||
sd_v2->sd_size = cpu_to_le64 (EMPTY_DIR_SIZE);
|
||||
sd_v2->sd_atime = sd_v2->sd_ctime = sd_v2->sd_mtime = cpu_to_le32 (time (NULL));
|
||||
sd_v2->u.sd_rdev = 0;
|
||||
sd_v2->sd_blocks = cpu_to_le32 (dir_size2st_blocks (blocksize, EMPTY_DIR_SIZE));
|
||||
}else{
|
||||
struct stat_data_v1 *sd_v1 = (struct stat_data_v1 *)sd;
|
||||
|
||||
set_ih_item_len (ih, SD_V1_SIZE);
|
||||
sd_v1->sd_mode = cpu_to_le16 (S_IFDIR + 0755);
|
||||
sd_v1->sd_nlink = cpu_to_le16 (2);
|
||||
sd_v1->sd_uid = 0;
|
||||
sd_v1->sd_gid = 0;
|
||||
sd_v1->sd_size = cpu_to_le32 (EMPTY_DIR_SIZE_V1);
|
||||
sd_v1->sd_atime = sd_v1->sd_ctime = sd_v1->sd_mtime = cpu_to_le32 (time (NULL));
|
||||
sd_v1->u.sd_blocks = cpu_to_le32 (dir_size2st_blocks (blocksize, EMPTY_DIR_SIZE_V1));
|
||||
sd_v1->sd_first_direct_byte = cpu_to_le32 (NO_BYTES_IN_DIRECT_ITEM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _empty_dir_item (int format, char * body, __u32 dirid, __u32 objid,
|
||||
__u32 par_dirid, __u32 par_objid)
|
||||
{
|
||||
struct reiserfs_de_head * deh;
|
||||
|
||||
memset (body, 0, (format == KEY_FORMAT_2 ? EMPTY_DIR_SIZE : EMPTY_DIR_SIZE_V1));
|
||||
deh = (struct reiserfs_de_head *)body;
|
||||
|
||||
/* direntry header of "." */
|
||||
deh[0].deh_offset = cpu_to_le32 (DOT_OFFSET);
|
||||
deh[0].deh_dir_id = cpu_to_le32 (dirid);
|
||||
deh[0].deh_objectid = cpu_to_le32 (objid);
|
||||
deh[0].deh_state = 0;
|
||||
set_bit (DEH_Visible, &(deh[0].deh_state));
|
||||
|
||||
/* direntry header of ".." */
|
||||
deh[1].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET);
|
||||
/* key of ".." for the root directory */
|
||||
deh[1].deh_dir_id = cpu_to_le32 (par_dirid);
|
||||
deh[1].deh_objectid = cpu_to_le32 (par_objid);
|
||||
deh[1].deh_state = 0;
|
||||
set_bit (DEH_Visible, &(deh[1].deh_state));
|
||||
|
||||
if (format == KEY_FORMAT_2) {
|
||||
deh[0].deh_location = cpu_to_le16 (EMPTY_DIR_SIZE - ROUND_UP (strlen (".")));
|
||||
deh[1].deh_location = cpu_to_le16 (deh_location (&deh[0]) - ROUND_UP (strlen ("..")));
|
||||
} else {
|
||||
deh[0].deh_location = cpu_to_le16 (EMPTY_DIR_SIZE_V1 - strlen ("."));
|
||||
deh[1].deh_location = cpu_to_le16 (deh_location (&deh[0]) - strlen (".."));
|
||||
}
|
||||
|
||||
/* copy ".." and "." */
|
||||
memcpy (body + deh_location (&deh[0]), ".", 1);
|
||||
memcpy (body + deh_location (&deh[1]), "..", 2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
|
||||
__u32 par_dirid, __u32 par_objid)
|
||||
{
|
||||
_empty_dir_item (KEY_FORMAT_1, body, dirid, objid, par_dirid, par_objid);
|
||||
}
|
||||
|
||||
|
||||
void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
|
||||
__u32 par_dirid, __u32 par_objid)
|
||||
{
|
||||
_empty_dir_item (KEY_FORMAT_2, body, dirid, objid, par_dirid, par_objid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* for every item call common action and an action corresponding to
|
||||
item type */
|
||||
void for_every_item (struct buffer_head * bh, item_head_action_t action,
|
||||
item_action_t * actions)
|
||||
{
|
||||
int i;
|
||||
struct item_head * ih;
|
||||
item_action_t iaction;
|
||||
|
||||
ih = B_N_PITEM_HEAD (bh, 0);
|
||||
for (i = 0; i < node_item_number (bh); i ++, ih ++) {
|
||||
if (action)
|
||||
action (ih);
|
||||
|
||||
iaction = actions[get_type (&ih->ih_key)];
|
||||
if (iaction)
|
||||
iaction (bh, ih);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* old keys (on i386) have k_offset_v2.k_type == 15 (direct and
|
||||
indirect) or == 0 (dir items and stat data) */
|
||||
|
||||
/* */
|
||||
int key_format (const struct key * key)
|
||||
{
|
||||
int type;
|
||||
|
||||
type = le16_to_cpu (key->u.k_offset_v2.k_type);
|
||||
|
||||
if (type == 0 || type == 15)
|
||||
return KEY_FORMAT_1;
|
||||
|
||||
return KEY_FORMAT_2;
|
||||
}
|
||||
|
||||
|
||||
loff_t get_offset (const struct key * key)
|
||||
{
|
||||
if (key_format (key) == KEY_FORMAT_1)
|
||||
return le32_to_cpu (key->u.k_offset_v1.k_offset);
|
||||
|
||||
return le64_to_cpu (key->u.k_offset_v2.k_offset);
|
||||
}
|
||||
|
||||
|
||||
int uniqueness2type (__u32 uniqueness)
|
||||
{
|
||||
switch (uniqueness) {
|
||||
case V1_SD_UNIQUENESS: return TYPE_STAT_DATA;
|
||||
case V1_INDIRECT_UNIQUENESS: return TYPE_INDIRECT;
|
||||
case V1_DIRECT_UNIQUENESS: return TYPE_DIRECT;
|
||||
case V1_DIRENTRY_UNIQUENESS: return TYPE_DIRENTRY;
|
||||
}
|
||||
return TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
__u32 type2uniqueness (int type)
|
||||
{
|
||||
switch (type) {
|
||||
case TYPE_STAT_DATA: return V1_SD_UNIQUENESS;
|
||||
case TYPE_INDIRECT: return V1_INDIRECT_UNIQUENESS;
|
||||
case TYPE_DIRECT: return V1_DIRECT_UNIQUENESS;
|
||||
case TYPE_DIRENTRY: return V1_DIRENTRY_UNIQUENESS;
|
||||
}
|
||||
return V1_UNKNOWN_UNIQUENESS;
|
||||
}
|
||||
|
||||
|
||||
int get_type (const struct key * key)
|
||||
{
|
||||
if (key_format (key) == KEY_FORMAT_1)
|
||||
return uniqueness2type (le32_to_cpu (key->u.k_offset_v1.k_uniqueness));
|
||||
return le16_to_cpu (key->u.k_offset_v2.k_type);
|
||||
}
|
||||
|
||||
|
||||
char * key_of_what (const struct key * key)
|
||||
{
|
||||
switch (get_type (key)) {
|
||||
case TYPE_STAT_DATA: return "SD";
|
||||
case TYPE_INDIRECT: return "IND";
|
||||
case TYPE_DIRECT: return "DRCT";
|
||||
case TYPE_DIRENTRY: return "DIR";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int type_unknown (struct key * key)
|
||||
{
|
||||
int type = get_type (key);
|
||||
|
||||
switch (type) {
|
||||
case TYPE_STAT_DATA:
|
||||
case TYPE_INDIRECT:
|
||||
case TYPE_DIRECT:
|
||||
case TYPE_DIRENTRY:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// this sets key format as well as type of item key belongs to
|
||||
//
|
||||
void set_type (int format, struct key * key, int type)
|
||||
{
|
||||
if (format == KEY_FORMAT_1)
|
||||
key->u.k_offset_v1.k_uniqueness = cpu_to_le32 (type2uniqueness (type));
|
||||
else
|
||||
key->u.k_offset_v2.k_type = cpu_to_le16 (type);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
void set_offset (int format, struct key * key, loff_t offset)
|
||||
{
|
||||
if (format == KEY_FORMAT_1)
|
||||
key->u.k_offset_v1.k_offset = cpu_to_le32 (offset);
|
||||
else
|
||||
key->u.k_offset_v2.k_offset = cpu_to_le64 (offset);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void set_type_and_offset (int format, struct key * key, loff_t offset, int type)
|
||||
{
|
||||
set_type (format, key, type);
|
||||
set_offset (format, key, offset);
|
||||
}
|
||||
|
||||
|
||||
/* length of the directory entry in directory item. This define calculates
|
||||
length of i-th directory entry using directory entry locations from dir
|
||||
entry head. When it calculates length of 0-th directory entry, it uses
|
||||
length of whole item in place of entry location of the non-existent
|
||||
following entry in the calculation. See picture above.*/
|
||||
|
||||
|
||||
// NOTE: this is not name length. This is length of whole entry
|
||||
int entry_length (struct item_head * ih, struct reiserfs_de_head * deh, int pos_in_item)
|
||||
{
|
||||
if (pos_in_item)
|
||||
return (deh_location (deh - 1) - deh_location (deh));
|
||||
return (ih_item_len (ih) - deh_location (deh));
|
||||
}
|
||||
|
||||
|
||||
char * name_in_entry (struct reiserfs_de_head * deh, int pos_in_item)
|
||||
{
|
||||
return ((char *)(deh - pos_in_item) + deh_location(deh));
|
||||
}
|
||||
|
||||
|
||||
int name_length (struct item_head * ih,
|
||||
struct reiserfs_de_head * deh, int pos_in_item)
|
||||
{
|
||||
int len;
|
||||
char * name;
|
||||
|
||||
len = entry_length (ih, deh, pos_in_item);
|
||||
name = name_in_entry (deh, pos_in_item);
|
||||
|
||||
// name might be padded with 0s
|
||||
while (!name [len - 1])
|
||||
len --;
|
||||
|
||||
return len;
|
||||
}
|
||||
Reference in new issue
Block a user