Files
reiserfsprogs/reiserfscore/reiserfslib.c
T
Jeff Mahoney 47cff72748 cleanup: run indent with the Linux Kernel style across all code
Over the years, the reiserfs kernel code has been gradually cleaned up
to be more readable. This patch does the same to the progs code.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
2013-08-26 17:14:42 -04:00

1508 lines
39 KiB
C

/*
* Copyright 2000-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
#define _GNU_SOURCE
#include "includes.h"
#include <linux/kdev_t.h>
#include <time.h>
struct reiserfs_key root_dir_key = { 0, 0, {{0, 0},} };
struct reiserfs_key parent_root_dir_key = { 0, 0, {{0, 0},} };
struct reiserfs_key lost_found_dir_key = { 0, 0, {{0, 0},} };
struct reiserfs_key badblock_key =
{ BADBLOCK_DIRID, BADBLOCK_OBJID, {{0, 0},} };
__u16 root_dir_format = 0;
__u16 lost_found_dir_format = 0;
static void make_const_keys(void)
{
set_key_dirid(&root_dir_key, REISERFS_ROOT_PARENT_OBJECTID);
set_key_objectid(&root_dir_key, REISERFS_ROOT_OBJECTID);
set_key_dirid(&parent_root_dir_key, 0);
set_key_objectid(&parent_root_dir_key, REISERFS_ROOT_PARENT_OBJECTID);
}
/* reiserfs needs at least: enough blocks for journal, 64 k at the beginning,
one block for super block, bitmap block and root block. Note that first
bitmap block must point to all of them */
int is_block_count_correct(unsigned long journal_offset,
unsigned int block_size, unsigned long block_count,
unsigned long journal_size)
{
unsigned long blocks;
/* RESERVED, MD RAID SBs, super block, bitmap, root, journal size with journal header */
blocks = journal_offset + journal_size;
/* we have a limit: skipped area, super block, journal and root block
all have to be addressed by one first bitmap */
if (blocks > block_size * 8)
return 0;
if (blocks > block_count)
return 0;
return 1;
}
/* read super block. fixme: only 4k blocks, pre-journaled format
is refused. Journal and bitmap are to be opened separately.
skip_check is set to 1 if checks of openned SB should be omitted.*/
reiserfs_filsys_t *reiserfs_open(char *filename, int flags,
int *error, void *vp, int check)
{
reiserfs_filsys_t *fs;
struct buffer_head *bh;
struct reiserfs_super_block *sb;
int fd;
unsigned int i;
/* convert root dir key and parent root dir key to little endian format */
make_const_keys();
if (error)
*error = 0;
fd = open(filename, flags
#if defined(O_LARGEFILE)
| O_LARGEFILE
#endif
);
if (fd == -1) {
if (error)
*error = errno;
return 0;
}
fs = getmem(sizeof(*fs));
fs->fs_dev = fd;
fs->fs_vp = vp;
asprintf(&fs->fs_file_name, "%s", filename);
/* reiserfs super block is either in 16-th or in 2-nd 4k block of the
device */
for (i = 2; i < 17; i += 14) {
bh = bread(fd, i, 4096);
if (!bh) {
reiserfs_warning(stderr,
"reiserfs_open: bread failed reading block %d\n",
i);
} else {
sb = (struct reiserfs_super_block *)bh->b_data;
if (is_any_reiserfs_magic_string(sb))
goto found;
/* reiserfs signature is not found at the i-th 4k block */
brelse(bh);
}
}
reiserfs_warning(stderr,
"\nreiserfs_open: the reiserfs superblock cannot be found on %s.\n",
filename);
freemem(fs);
close(fd);
fs = NULL;
return fs;
found:
if (!is_blocksize_correct(get_sb_block_size(sb))) {
reiserfs_warning(stderr,
"reiserfs_open: a superblock with wrong parameters "
"was found in the block (%d).\n", i);
freemem(fs);
close(fd);
brelse(bh);
return NULL;
}
if (check) {
/* A few checks of found super block. */
struct buffer_head *tmp_bh;
tmp_bh =
bread(fd, get_sb_block_count(sb) - 1,
get_sb_block_size(sb));
if (!tmp_bh) {
reiserfs_warning(stderr,
"\n%s: Your partition is not big enough to contain the \n"
"filesystem of (%lu) blocks as was specified in the found super block.\n",
__FUNCTION__,
get_sb_block_count(sb) - 1);
freemem(fs);
close(fd);
brelse(bh);
return NULL;
}
brelse(tmp_bh);
}
fs->fs_blocksize = get_sb_block_size(sb);
/* check block size on the filesystem */
if (fs->fs_blocksize != 4096) {
i = bh->b_blocknr * 4096 / fs->fs_blocksize;
brelse(bh);
bh = bread(fd, i, fs->fs_blocksize);
if (!bh) {
reiserfs_warning(stderr,
"reiserfs_open: bread failed reading block %d, size %d\n",
i, fs->fs_blocksize);
freemem(fs);
return 0;
}
sb = (struct reiserfs_super_block *)bh->b_data;
}
fs->fs_hash_function = code2func(get_sb_hash_code(sb));
fs->fs_super_bh = bh;
fs->fs_ondisk_sb = sb;
fs->fs_flags = flags; /* O_RDONLY or O_RDWR */
fs->fs_format = get_reiserfs_format(sb);
/*reiserfs_read_bitmap_blocks(fs); */
if (flags & O_RDWR)
fs->fs_dirt = 1;
else
fs->fs_dirt = 0;
return fs;
}
/* creates buffer for super block and fills it up with fields which are
constant for given size and version of a filesystem */
reiserfs_filsys_t *reiserfs_create(char *filename,
int version,
unsigned long block_count,
int block_size,
int default_journal, int new_format)
{
reiserfs_filsys_t *fs;
unsigned int bmap_nr = reiserfs_bmap_nr(block_count, block_size);;
time_t now;
/* convert root dir key and parent root dir key to little endian format */
make_const_keys();
if (count_blocks(filename, block_size) < block_count) {
reiserfs_warning(stderr,
"reiserfs_create: no enough blocks on device\n");
return 0;
}
if (!is_block_count_correct(REISERFS_DISK_OFFSET_IN_BYTES / block_size,
block_size, block_count, 0)) {
reiserfs_warning(stderr,
"reiserfs_create: can not create that small "
"(%u blocks) filesystem\n", block_count);
return 0;
}
fs = getmem(sizeof(*fs));
if (!fs) {
reiserfs_warning(stderr, "reiserfs_create: getmem failed\n");
return 0;
}
fs->fs_dev = open(filename, O_RDWR | O_EXCL
#if defined(O_LARGEFILE)
| O_LARGEFILE
#endif
);
if (fs->fs_dev == -1) {
reiserfs_warning(stderr,
"reiserfs_create: could not open %s: %s\n",
filename, strerror(errno));
freemem(fs);
return 0;
}
fs->fs_blocksize = block_size;
asprintf(&fs->fs_file_name, "%s", filename);
fs->fs_format = version;
if (new_format)
fs->fs_super_bh = getblk(fs->fs_dev,
REISERFS_DISK_OFFSET_IN_BYTES /
block_size, block_size);
else
fs->fs_super_bh = getblk(fs->fs_dev,
REISERFS_OLD_DISK_OFFSET_IN_BYTES /
block_size, block_size);
if (!fs->fs_super_bh) {
reiserfs_warning(stderr, "reiserfs_create: getblk failed\n");
return 0;
}
mark_buffer_uptodate(fs->fs_super_bh, 1);
fs->fs_ondisk_sb =
(struct reiserfs_super_block *)fs->fs_super_bh->b_data;
memset(fs->fs_ondisk_sb, 0, block_size);
/* fill super block fields which are constant for given version and block count */
set_sb_block_count(fs->fs_ondisk_sb, block_count);
/* sb_free_blocks */
/* sb_root_block */
/* sb_journal_1st_block */
/* sb_journal_dev */
/* sb_orig_journal_size */
/* sb_joural_magic */
/* sb_journal magic_F */
/* sb_mount_id */
/* sb_not_used0 */
/* sb_generation_number */
set_sb_block_size(fs->fs_ondisk_sb, block_size);
switch (version) {
case REISERFS_FORMAT_3_5:
set_sb_oid_maxsize(fs->fs_ondisk_sb,
(block_size -
SB_SIZE_V1) / sizeof(__u32) / 2 * 2);
/* sb_oid_cursize */
/* sb_state */
memcpy(fs->fs_ondisk_sb->s_v1.s_magic,
REISERFS_3_5_SUPER_MAGIC_STRING,
strlen(REISERFS_3_5_SUPER_MAGIC_STRING));
break;
case REISERFS_FORMAT_3_6:
set_sb_oid_maxsize(fs->fs_ondisk_sb,
(block_size -
SB_SIZE) / sizeof(__u32) / 2 * 2);
/* sb_oid_cursize */
/* sb_state */
memcpy(fs->fs_ondisk_sb->s_v1.s_magic,
REISERFS_3_6_SUPER_MAGIC_STRING,
strlen(REISERFS_3_6_SUPER_MAGIC_STRING));
break;
}
if (!default_journal)
memcpy(fs->fs_ondisk_sb->s_v1.s_magic,
REISERFS_JR_SUPER_MAGIC_STRING,
strlen(REISERFS_JR_SUPER_MAGIC_STRING));
/* sb_fsck_state */
/* sb_hash_function_code */
/* sb_tree_height */
set_sb_bmap_nr(fs->fs_ondisk_sb,
reiserfs_bmap_over(bmap_nr) ? 0 : bmap_nr);
set_sb_version(fs->fs_ondisk_sb, version);
set_sb_v2_lastcheck(fs->fs_ondisk_sb, time(&now));
set_sb_v2_check_interval(fs->fs_ondisk_sb, DEFAULT_CHECK_INTERVAL);
set_sb_v2_mnt_count(fs->fs_ondisk_sb, 1);
set_sb_v2_max_mnt_count(fs->fs_ondisk_sb, DEFAULT_MAX_MNT_COUNT);
/* sb_not_used1 */
mark_buffer_dirty(fs->fs_super_bh);
fs->fs_dirt = 1;
return fs;
}
int no_reiserfs_found(reiserfs_filsys_t *fs)
{
return (fs == NULL || fs->fs_blocksize == 0) ? 1 : 0;
}
int new_format(reiserfs_filsys_t *fs)
{
return fs->fs_super_bh->b_blocknr != 2;
}
int spread_bitmaps(reiserfs_filsys_t *fs)
{
return fs->fs_super_bh->b_blocknr != 2;
}
/* 0 means: do not guarantee that fs is consistent */
int reiserfs_is_fs_consistent(reiserfs_filsys_t *fs)
{
if (get_sb_umount_state(fs->fs_ondisk_sb) == FS_CLEANLY_UMOUNTED &&
get_sb_fs_state(fs->fs_ondisk_sb) == FS_CONSISTENT)
return 1;
return 0;
}
/* flush bitmap, brelse super block, flush all dirty buffers, close and open
again the device, read super block */
static void reiserfs_only_reopen(reiserfs_filsys_t *fs, int flag)
{
unsigned long super_block;
/* reiserfs_flush_to_ondisk_bitmap (fs->fs_bitmap2, fs); */
super_block = fs->fs_super_bh->b_blocknr;
brelse(fs->fs_super_bh);
flush_buffers(fs->fs_dev);
invalidate_buffers(fs->fs_dev);
if (close(fs->fs_dev))
die("reiserfs_reopen: closed failed: %s", strerror(errno));
fs->fs_dev = open(fs->fs_file_name, flag
#if defined(O_LARGEFILE)
| O_LARGEFILE
#endif
);
if (fs->fs_dev == -1)
die("reiserfs_reopen: could not reopen device: %s",
strerror(errno));
fs->fs_super_bh = bread(fs->fs_dev, super_block, fs->fs_blocksize);
if (!fs->fs_super_bh)
die("reiserfs_reopen: reading super block failed");
fs->fs_ondisk_sb =
(struct reiserfs_super_block *)fs->fs_super_bh->b_data;
fs->fs_flags = flag; /* O_RDONLY or O_RDWR */
if (flag & O_RDWR)
fs->fs_dirt = 1;
else
fs->fs_dirt = 0;
}
void reiserfs_reopen(reiserfs_filsys_t *fs, int flag)
{
reiserfs_only_reopen(fs, flag);
reiserfs_reopen_journal(fs, flag);
}
int is_opened_rw(reiserfs_filsys_t *fs)
{
if ((fs->fs_flags) & O_RDWR)
return 1;
return 0;
}
/* flush all changes made on a filesystem */
void reiserfs_flush(reiserfs_filsys_t *fs)
{
if (fs->fs_dirt) {
reiserfs_flush_journal(fs);
flush_buffers(fs->fs_dev);
}
fs->fs_dirt = 0;
}
/* free all memory involved into manipulating with filesystem */
void reiserfs_free(reiserfs_filsys_t *fs)
{
reiserfs_free_journal(fs);
reiserfs_free_ondisk_bitmap(fs);
/* release super block and memory used by filesystem handler */
brelse(fs->fs_super_bh);
fs->fs_super_bh = 0;
free_buffers();
free(fs->fs_file_name);
fs->fs_file_name = 0;
freemem(fs);
}
/* this closes everything: journal. bitmap and the fs itself */
void reiserfs_close(reiserfs_filsys_t *fs)
{
reiserfs_close_journal(fs);
reiserfs_close_ondisk_bitmap(fs);
reiserfs_flush(fs);
reiserfs_free(fs);
fsync(fs->fs_dev);
}
int reiserfs_new_blocknrs(reiserfs_filsys_t *fs,
unsigned long *free_blocknrs,
unsigned long start, int amount_needed)
{
if (fs->block_allocator)
return fs->block_allocator(fs, free_blocknrs, start,
amount_needed);
die("block allocator is not defined\n");
return 0;
}
int reiserfs_free_block(reiserfs_filsys_t *fs, unsigned long block)
{
if (fs->block_deallocator)
return fs->block_deallocator(fs, block);
die("block deallocator is not defined\n");
return 0;
}
static int reiserfs_search_by_key_x(reiserfs_filsys_t *fs,
struct reiserfs_key *key,
struct reiserfs_path *path, int key_length)
{
struct buffer_head *bh;
unsigned long block;
struct reiserfs_path_element *curr;
int retval;
block = get_sb_root_block(fs->fs_ondisk_sb);
if (not_data_block(fs, block))
return IO_ERROR;
path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
while (1) {
curr = PATH_OFFSET_PELEMENT(path, ++path->path_length);
bh = curr->pe_buffer =
bread(fs->fs_dev, block, fs->fs_blocksize);
if (bh == 0) {
path->path_length--;
pathrelse(path);
return ITEM_NOT_FOUND;
}
retval =
reiserfs_bin_search(key, B_N_PKEY(bh, 0), B_NR_ITEMS(bh),
is_leaf_node(bh) ? IH_SIZE : KEY_SIZE,
&curr->pe_position,
key_length ==
4 ? comp_keys : comp_keys_3);
if (retval == POSITION_FOUND) {
/* key found, return if this is leaf level */
if (is_leaf_node(bh)) {
path->pos_in_item = 0;
return ITEM_FOUND;
}
curr->pe_position++;
} else {
/* key not found in the node */
if (is_leaf_node(bh))
return ITEM_NOT_FOUND;
}
block = get_dc_child_blocknr(B_N_CHILD(bh, curr->pe_position));
if (not_data_block(fs, block))
return IO_ERROR;
}
printf("search_by_key: you can not get here\n");
return ITEM_NOT_FOUND;
}
int reiserfs_search_by_key_3(reiserfs_filsys_t *fs, struct reiserfs_key *key,
struct reiserfs_path *path)
{
return reiserfs_search_by_key_x(fs, key, path, 3);
}
int reiserfs_search_by_key_4(reiserfs_filsys_t *fs, struct reiserfs_key *key,
struct reiserfs_path *path)
{
return reiserfs_search_by_key_x(fs, key, path, 4);
}
/* key is key of byte in the regular file. This searches in tree
through items and in the found item as well */
int usearch_by_position(reiserfs_filsys_t *s, struct reiserfs_key *key,
int version, struct reiserfs_path *path)
{
struct buffer_head *bh;
struct item_head *ih;
struct reiserfs_key *next_key;
if (reiserfs_search_by_key_3(s, key, path) == ITEM_FOUND) {
ih = get_ih(path);
if (!is_direct_ih(ih) && !is_indirect_ih(ih))
return DIRECTORY_FOUND;
path->pos_in_item = 0;
return POSITION_FOUND;
}
bh = get_bh(path);
ih = get_ih(path);
if (PATH_LAST_POSITION(path) == 0) {
/* previous item does not exist, that means we are in leftmost leaf of
* the tree */
if (!not_of_one_file(&ih->ih_key, key)) {
if (!is_direct_ih(ih) && !is_indirect_ih(ih))
return DIRECTORY_FOUND;
return POSITION_NOT_FOUND;
}
return FILE_NOT_FOUND;
}
/* take previous item */
PATH_LAST_POSITION(path)--;
ih--;
if (not_of_one_file(&ih->ih_key, key) || is_stat_data_ih(ih)) {
/* previous item belongs to another object or is a stat data, check
* next item */
PATH_LAST_POSITION(path)++;
if (PATH_LAST_POSITION(path) < B_NR_ITEMS(bh))
/* next key is in the same node */
next_key = B_N_PKEY(bh, PATH_LAST_POSITION(path));
else
next_key = uget_rkey(path);
if (next_key == 0 || not_of_one_file(next_key, key)) {
/* there is no any part of such file in the tree */
path->pos_in_item = 0;
return FILE_NOT_FOUND;
}
if (is_direntry_key(next_key)) {
reiserfs_warning(stderr,
"usearch_by_position: looking for %k found a directory with the same key\n",
next_key);
return DIRECTORY_FOUND;
}
/* next item is the part of this file */
path->pos_in_item = 0;
return POSITION_NOT_FOUND;
}
if (is_direntry_ih(ih)) {
return DIRECTORY_FOUND;
}
if (is_stat_data_ih(ih)) {
PATH_LAST_POSITION(path)++;
return FILE_NOT_FOUND;
}
/* previous item is part of desired file */
if (I_K_KEY_IN_ITEM(ih, key, bh->b_size)) {
path->pos_in_item = get_offset(key) - get_offset(&ih->ih_key);
if (is_indirect_ih(ih))
path->pos_in_item /= bh->b_size;
return POSITION_FOUND;
}
path->pos_in_item =
is_indirect_ih(ih) ? I_UNFM_NUM(ih) : get_ih_item_len(ih);
return POSITION_NOT_FOUND;
}
static int comp_dir_entries(const void *p1, const void *p2)
{
__u32 off1, off2;
off1 = d32_get((__u32 *) p1, 0);
off2 = *(__u32 *) p2;
if (off1 < off2)
return -1;
if (off1 > off2)
return 1;
return 0;
}
struct reiserfs_key *uget_lkey(struct reiserfs_path *path)
{
int pos, offset = path->path_length;
struct buffer_head *bh;
if (offset < FIRST_PATH_ELEMENT_OFFSET)
die("uget_lkey: illegal offset in the path (%d)", offset);
/* While not higher in path than first element. */
while (offset-- > FIRST_PATH_ELEMENT_OFFSET) {
if (!buffer_uptodate(PATH_OFFSET_PBUFFER(path, offset)))
die("uget_lkey: parent is not uptodate");
/* Parent at the path is not in the tree now. */
if (!B_IS_IN_TREE(bh = PATH_OFFSET_PBUFFER(path, offset)))
die("uget_lkey: buffer on the path is not in tree");
/* Check whether position in the parent is correct. */
if ((pos = PATH_OFFSET_POSITION(path, offset)) > B_NR_ITEMS(bh))
die("uget_lkey: invalid position (%d) in the path",
pos);
/* Check whether parent at the path really points to the child. */
if (get_dc_child_blocknr(B_N_CHILD(bh, pos)) !=
PATH_OFFSET_PBUFFER(path, offset + 1)->b_blocknr)
die("uget_lkey: invalid block number (%d). Must be %ld",
get_dc_child_blocknr(B_N_CHILD(bh, pos)),
PATH_OFFSET_PBUFFER(path, offset + 1)->b_blocknr);
/* Return delimiting key if position in the parent is not equal to zero. */
if (pos)
return B_N_PDELIM_KEY(bh, pos - 1);
}
/* there is no left delimiting key */
return 0;
}
struct reiserfs_key *uget_rkey(struct reiserfs_path *path)
{
int pos, offset = path->path_length;
struct buffer_head *bh;
if (offset < FIRST_PATH_ELEMENT_OFFSET)
die("uget_rkey: illegal offset in the path (%d)", offset);
while (offset-- > FIRST_PATH_ELEMENT_OFFSET) {
if (!buffer_uptodate(PATH_OFFSET_PBUFFER(path, offset)))
die("uget_rkey: parent is not uptodate");
/* Parent at the path is not in the tree now. */
if (!B_IS_IN_TREE(bh = PATH_OFFSET_PBUFFER(path, offset)))
die("uget_rkey: buffer on the path is not in tree");
/* Check whether position in the parrent is correct. */
if ((pos = PATH_OFFSET_POSITION(path, offset)) > B_NR_ITEMS(bh))
die("uget_rkey: invalid position (%d) in the path",
pos);
/* Check whether parent at the path really points to the child. */
if (get_dc_child_blocknr(B_N_CHILD(bh, pos)) !=
PATH_OFFSET_PBUFFER(path, offset + 1)->b_blocknr)
die("uget_rkey: invalid block number (%d). Must be %ld",
get_dc_child_blocknr(B_N_CHILD(bh, pos)),
PATH_OFFSET_PBUFFER(path, offset + 1)->b_blocknr);
/* Return delimiting key if position in the parent is not the last one. */
if (pos != B_NR_ITEMS(bh))
return B_N_PDELIM_KEY(bh, pos);
}
/* there is no right delimiting key */
return 0;
}
struct reiserfs_key *reiserfs_next_key(struct reiserfs_path *path)
{
if (get_item_pos(path) < B_NR_ITEMS(get_bh(path)) - 1)
return B_N_PKEY(get_bh(path), get_item_pos(path) + 1);
return uget_rkey(path);
}
/* NOTE: this only should be used to look for keys who exists */
int reiserfs_search_by_entry_key(reiserfs_filsys_t *fs,
struct reiserfs_key *key,
struct reiserfs_path *path)
{
struct buffer_head *bh;
int item_pos;
struct item_head *ih;
struct reiserfs_key tmpkey;
__u32 offset;
if (reiserfs_search_by_key_4(fs, key, path) == ITEM_FOUND) {
path->pos_in_item = 0;
return POSITION_FOUND;
}
bh = get_bh(path);
item_pos = get_item_pos(path);
ih = get_ih(path);
if (item_pos == 0) {
/* key is less than the smallest key in the tree */
if (not_of_one_file(&(ih->ih_key), key))
/* there are no items of that directory */
return DIRECTORY_NOT_FOUND;
if (!is_direntry_ih(ih)) {
reiserfs_panic
("reiserfs_search_by_entry_key: found item "
"is not of directory type %H", ih);
}
/* key we looked for should be here */
path->pos_in_item = 0;
return POSITION_NOT_FOUND;
}
/* take previous item */
item_pos--;
ih--;
PATH_LAST_POSITION(path)--;
if (not_of_one_file(&(ih->ih_key), key) || !is_direntry_ih(ih)) {
/* previous item belongs to another object or is stat data, check next
item */
item_pos++;
PATH_LAST_POSITION(path)++;
if (item_pos < B_NR_ITEMS(bh)) {
/* next item is in the same node */
ih++;
if (not_of_one_file(&(ih->ih_key), key)) {
/* there are no items of that directory */
path->pos_in_item = 0;
return DIRECTORY_NOT_FOUND;
}
if (!is_direntry_ih(ih))
reiserfs_panic
("_search_by_entry_key: %k is not a directory",
key);
} else {
/* next item is in right neighboring node */
struct reiserfs_key *next_key = uget_rkey(path);
if (next_key == 0 || not_of_one_file(next_key, key)) {
/* there are no items of that directory */
path->pos_in_item = 0;
return DIRECTORY_NOT_FOUND;
}
if (!is_direntry_key(next_key))
reiserfs_panic
("_search_by_entry_key: %k is not a directory",
key);
/* we got right delimiting key - search for it - the entry will be
pasted in position 0 */
copy_key(&tmpkey, next_key);
pathrelse(path);
if (reiserfs_search_by_key_4(fs, &tmpkey, path) !=
ITEM_FOUND || PATH_LAST_POSITION(path) != 0)
reiserfs_panic
("_search_by_entry_key: item corresponding to delimiting key %k not found",
&tmpkey);
}
/* next item is the part of this directory */
path->pos_in_item = 0;
return POSITION_NOT_FOUND;
}
/* previous item is part of desired directory */
offset = get_key_offset_v1(key);
if (reiserfs_bin_search
(&offset, B_I_DEH(bh, ih), get_ih_entry_count(ih), DEH_SIZE,
&(path->pos_in_item), comp_dir_entries) == POSITION_FOUND)
return POSITION_FOUND;
return POSITION_NOT_FOUND;
}
void init_tb_struct(struct tree_balance *tb, reiserfs_filsys_t *fs,
struct reiserfs_path *path, int size)
{
memset(tb, '\0', sizeof(struct tree_balance));
tb->tb_fs = fs;
tb->tb_path = path;
PATH_OFFSET_PBUFFER(path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL;
PATH_OFFSET_POSITION(path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0;
tb->insert_size[0] = size;
}
int reiserfs_remove_entry(reiserfs_filsys_t *fs, struct reiserfs_key *key)
{
struct reiserfs_path path;
struct tree_balance tb;
struct item_head *ih;
struct reiserfs_de_head *deh;
if (reiserfs_search_by_entry_key(fs, key, &path) != POSITION_FOUND) {
pathrelse(&path);
return 1;
}
ih = get_ih(&path);
if (get_ih_entry_count(ih) == 1) {
init_tb_struct(&tb, fs, &path,
-(IH_SIZE + get_ih_item_len(ih)));
if (fix_nodes(M_DELETE, &tb, 0) != CARRY_ON) {
unfix_nodes(&tb);
return 1;
}
do_balance(&tb, 0, 0, M_DELETE, 0);
return 0;
}
deh = B_I_DEH(get_bh(&path), ih) + path.pos_in_item;
init_tb_struct(&tb, fs, &path,
-(DEH_SIZE + entry_length(ih, deh, path.pos_in_item)));
if (fix_nodes(M_CUT, &tb, 0) != CARRY_ON) {
unfix_nodes(&tb);
return 1;
}
do_balance(&tb, 0, 0, M_CUT, 0);
return 0;
}
void reiserfs_paste_into_item(reiserfs_filsys_t *fs,
struct reiserfs_path *path, const void *body,
int size)
{
struct tree_balance tb;
init_tb_struct(&tb, fs, path, size);
if (fix_nodes(M_PASTE, &tb, 0 /*ih */ ) != CARRY_ON)
reiserfs_panic("reiserfs_paste_into_item: fix_nodes failed");
do_balance(&tb, 0, body, M_PASTE, 0 /*zero num */ );
}
void reiserfs_insert_item(reiserfs_filsys_t *fs, struct reiserfs_path *path,
struct item_head *ih, const void *body)
{
struct tree_balance tb;
init_tb_struct(&tb, fs, path, IH_SIZE + get_ih_item_len(ih));
if (fix_nodes(M_INSERT, &tb, ih) != CARRY_ON)
die("reiserfs_insert_item: fix_nodes failed");
do_balance(&tb, ih, body, M_INSERT, 0 /*zero num */ );
}
/*===========================================================================*/
__u32 hash_value(hashf_t func, char *name, int namelen)
{
__u32 res;
res = func(name, namelen);
res = GET_HASH_VALUE(res);
if (res == 0)
res = 128;
return res;
}
/* if name is found in a directory - return 1 and set path to the name,
otherwise return 0 and pathrelse path */
int reiserfs_locate_entry(reiserfs_filsys_t *fs, struct reiserfs_key *dir,
char *name, struct reiserfs_path *path)
{
struct reiserfs_key entry_key;
struct item_head *ih;
struct reiserfs_de_head *deh;
int i, retval;
struct reiserfs_key *rdkey;
set_key_dirid(&entry_key, get_key_dirid(dir));
set_key_objectid(&entry_key, get_key_objectid(dir));
set_key_offset_v1(&entry_key, 0);
set_key_uniqueness(&entry_key, DIRENTRY_UNIQUENESS);
if (reiserfs_search_by_entry_key(fs, &entry_key, path) ==
DIRECTORY_NOT_FOUND) {
pathrelse(path);
return 0;
}
do {
ih = get_ih(path);
deh = B_I_DEH(get_bh(path), ih) + path->pos_in_item;
for (i = path->pos_in_item; i < get_ih_entry_count(ih);
i++, deh++) {
/* the name in directory has the same hash as the given name */
if ((name_in_entry_length(ih, deh, i) ==
(int)strlen(name))
&& !memcmp(name_in_entry(deh, i), name,
strlen(name))) {
path->pos_in_item = i;
return 1;
}
}
rdkey = uget_rkey(path);
if (!rdkey || not_of_one_file(rdkey, dir)) {
pathrelse(path);
return 0;
}
if (!is_direntry_key(rdkey))
reiserfs_panic
("reiserfs_locate_entry: can not find name in broken directory yet");
/* first name of that item may be a name we are looking for */
entry_key = *rdkey;
pathrelse(path);
retval = reiserfs_search_by_entry_key(fs, &entry_key, path);
if (retval != POSITION_FOUND)
reiserfs_panic
("reiserfs_locate_entry: wrong delimiting key in the tree");
} while (1);
return 0;
}
/* returns 0 if name is not found in a directory and 1 if name is
found. Stores key found in the entry in 'key'. Returns minimal not used
generation counter in 'min_gen_counter'. dies if found object is not a
directory. */
int reiserfs_find_entry(reiserfs_filsys_t *fs, struct reiserfs_key *dir,
char *name, unsigned int *min_gen_counter,
struct reiserfs_key *key)
{
struct reiserfs_key entry_key;
int retval;
int i;
INITIALIZE_REISERFS_PATH(path);
struct item_head *ih;
struct reiserfs_de_head *deh;
struct reiserfs_key *rdkey;
__u32 hash;
set_key_dirid(&entry_key, get_key_dirid(dir));
set_key_objectid(&entry_key, get_key_objectid(dir));
if (!strcmp(name, "."))
hash = DOT_OFFSET;
else if (!strcmp(name, ".."))
hash = DOT_DOT_OFFSET;
else
hash = hash_value(reiserfs_hash(fs), name, strlen(name));
set_key_offset_v1(&entry_key, hash);
set_key_uniqueness(&entry_key, DIRENTRY_UNIQUENESS);
*min_gen_counter = 0;
if (reiserfs_search_by_entry_key(fs, &entry_key, &path) ==
DIRECTORY_NOT_FOUND) {
pathrelse(&path);
return 0;
}
do {
ih = get_ih(&path);
deh = B_I_DEH(get_bh(&path), ih) + path.pos_in_item;
for (i = path.pos_in_item; i < get_ih_entry_count(ih);
i++, deh++) {
if (GET_HASH_VALUE(get_deh_offset(deh)) !=
GET_HASH_VALUE(hash)) {
/* all entries having the same hash were scanned */
pathrelse(&path);
return 0;
}
if (GET_GENERATION_NUMBER(get_deh_offset(deh)) ==
*min_gen_counter)
(*min_gen_counter)++;
if ((name_in_entry_length(ih, deh, i) ==
(int)strlen(name))
&&
(!memcmp
(name_in_entry(deh, i), name, strlen(name)))) {
/* entry found in the directory */
if (key) {
memset(key, 0,
sizeof(struct reiserfs_key));
set_key_dirid(key, get_deh_dirid(deh));
set_key_objectid(key,
get_deh_objectid(deh));
}
pathrelse(&path);
return 1; //get_deh_objectid (deh) ? get_deh_objectid (deh) : 1;
}
}
rdkey = uget_rkey(&path);
if (!rdkey || not_of_one_file(rdkey, dir)) {
pathrelse(&path);
return 0;
}
if (!is_direntry_key(rdkey))
reiserfs_panic
("reiserfs_find_entry: can not find name in broken directory yet");
/* next item is the item of the directory we are looking name in */
if (GET_HASH_VALUE(get_offset(rdkey)) != hash) {
/* but there is no names with given hash */
pathrelse(&path);
return 0;
}
/* first name of that item may be a name we are looking for */
entry_key = *rdkey;
pathrelse(&path);
retval = reiserfs_search_by_entry_key(fs, &entry_key, &path);
if (retval != POSITION_FOUND)
reiserfs_panic
("reiserfs_find_entry: wrong delimiting key in the tree");
} while (1);
return 0;
}
/* compose directory entry: dir entry head and name itself */
char *make_entry(char *entry, char *name, struct reiserfs_key *key,
__u32 offset)
{
struct reiserfs_de_head *deh;
__u16 state;
if (!entry)
entry = getmem(DEH_SIZE + ROUND_UP(strlen(name)));
memset(entry, 0, DEH_SIZE + ROUND_UP(strlen(name)));
deh = (struct reiserfs_de_head *)entry;
set_deh_location(deh, 0);
set_deh_offset(deh, offset);
state = (1 << DEH_Visible2);
set_deh_state(deh, state);
/* key of object entry will point to */
set_deh_dirid(deh, get_key_dirid(key));
set_deh_objectid(deh, get_key_objectid(key));
memcpy((char *)(deh + 1), name, strlen(name));
return entry;
}
/* add new name into a directory. If it exists in a directory - do
nothing */
int reiserfs_add_entry(reiserfs_filsys_t *fs, struct reiserfs_key *dir,
char *name, int name_len, struct reiserfs_key *key,
__u16 fsck_need)
{
struct item_head entry_ih = { {0,}, };
char *entry;
int retval;
INITIALIZE_REISERFS_PATH(path);
unsigned int gen_counter;
int item_len;
__u32 hash;
if (reiserfs_find_entry(fs, dir, name, &gen_counter, 0))
/* entry is in the directory already or directory was not found */
return 0;
/* compose entry key to look for its place in the tree */
set_key_dirid(&(entry_ih.ih_key), get_key_dirid(dir));
set_key_objectid(&(entry_ih.ih_key), get_key_objectid(dir));
if (!strcmp(name, "."))
hash = DOT_OFFSET;
else if (!strcmp(name, ".."))
hash = DOT_DOT_OFFSET;
else
hash =
hash_value(reiserfs_hash(fs), name,
strlen(name)) + gen_counter;
set_key_offset_v1(&(entry_ih.ih_key), hash);
set_key_uniqueness(&(entry_ih.ih_key), DIRENTRY_UNIQUENESS);
set_ih_key_format(&entry_ih, KEY_FORMAT_1);
set_ih_entry_count(&entry_ih, 1);
item_len = DEH_SIZE + name_len;
/*
if (get_reiserfs_format (fs->fs_ondisk_sb) == REISERFS_FORMAT_3_5)
item_len = DEH_SIZE + strlen (name);
else if (get_reiserfs_format (fs->fs_ondisk_sb) == REISERFS_FORMAT_3_6)
item_len = DEH_SIZE + ROUND_UP (strlen (name));
else
reiserfs_panic ("unknown fs format");
*/
set_ih_item_len(&entry_ih, item_len);
/* fsck may need to insert item which was not reached yet */
set_ih_flags(&entry_ih, fsck_need);
entry = make_entry(0, name, key, get_offset(&(entry_ih.ih_key)));
retval = reiserfs_search_by_entry_key(fs, &(entry_ih.ih_key), &path);
switch (retval) {
case POSITION_NOT_FOUND:
reiserfs_paste_into_item(fs, &path, entry, item_len);
break;
case DIRECTORY_NOT_FOUND:
set_deh_location((struct reiserfs_de_head *)entry, DEH_SIZE);
reiserfs_insert_item(fs, &path, &entry_ih, entry);
break;
default:
reiserfs_panic
("reiserfs_add_entry: looking for %k (inserting name \"%s\") "
"search_by_entry_key returned %d", &(entry_ih.ih_key),
name, retval);
}
freemem(entry);
return item_len;
}
void copy_key(void *to, void *from)
{
memcpy(to, from, KEY_SIZE);
}
void copy_short_key(void *to, void *from)
{
memcpy(to, from, SHORT_KEY_SIZE);
}
void copy_item_head(void *p_v_to, void *p_v_from)
{
memcpy(p_v_to, p_v_from, IH_SIZE);
}
/* inserts new or old stat data of a directory (unreachable, nlinks == 0) */
int create_dir_sd(reiserfs_filsys_t *fs,
struct reiserfs_path *path, struct reiserfs_key *key,
void (*modify_item) (struct item_head *, void *))
{
struct item_head ih;
struct stat_data sd;
int key_format;
if (fs->fs_format == REISERFS_FORMAT_3_5)
key_format = KEY_FORMAT_1;
else
key_format = KEY_FORMAT_2;
memset(&sd, 0, sizeof(sd));
make_dir_stat_data(fs->fs_blocksize, key_format, get_key_dirid(key),
get_key_objectid(key), &ih, &sd);
/* if calling user is not root set the owner of the root entry
* to the calling user */
if (getuid()) {
if (key_format == KEY_FORMAT_1) {
struct stat_data_v1 *sd_v1 = (struct stat_data_v1 *)&sd;
set_sd_v1_uid(sd_v1, getuid());
set_sd_v1_gid(sd_v1, getgid());
} else {
set_sd_v2_uid(&sd, getuid());
set_sd_v2_gid(&sd, getgid());
}
}
if (modify_item)
modify_item(&ih, &sd);
#if 0
/* set nlink count to 0 and make the item unreachable */
zero_nlink(&ih, &sd, 0);
mark_item_unreachable(&ih);
#endif
reiserfs_insert_item(fs, path, &ih, &sd);
return key_format;
}
void make_sure_root_dir_exists(reiserfs_filsys_t *fs,
void (*modify_item) (struct item_head *, void *),
int ih_flags)
{
INITIALIZE_REISERFS_PATH(path);
/* is there root's stat data */
if (reiserfs_search_by_key_4(fs, &root_dir_key, &path) ==
ITEM_NOT_FOUND) {
root_dir_format =
create_dir_sd(fs, &path, &root_dir_key, modify_item);
} else {
struct item_head *ih = get_ih(&path);
if (!is_stat_data_ih(ih))
reiserfs_panic("It must be root's stat data %k\n",
&ih->ih_key);
root_dir_format =
(get_ih_item_len(get_ih(&path)) ==
SD_SIZE) ? KEY_FORMAT_2 : KEY_FORMAT_1;
pathrelse(&path);
}
/* add "." and ".." if any of them do not exist. Last two
parameters say: 0 - entry is not added on lost_found pass and 1
- mark item unreachable */
reiserfs_add_entry(fs, &root_dir_key, ".",
name_length(".", root_dir_format), &root_dir_key,
ih_flags);
reiserfs_add_entry(fs, &root_dir_key, "..",
name_length("..", root_dir_format),
&parent_root_dir_key, ih_flags);
}
int block_size_ok(int blocksize, int force)
{
int pagesize = getpagesize();
if (blocksize > 4096) {
reiserfs_warning(stderr, "Block sizes larger than 4k are not "
"supported on all architectures.\n");
if (blocksize > pagesize)
reiserfs_warning(stderr,
"The newly created filesystem will not "
"be mountable on this system.\n");
else
reiserfs_warning(stderr,
"The newly created filesystem may not "
"be mountable on other systems.\n");
check_forcing_ask_confirmation(force);
} else if (blocksize < 4096) {
reiserfs_warning(stderr, "Block sizes smaller than 4k "
"are not supported.\n");
return 0;
}
return 1;
}
/* we only can use a file for filesystem or journal if it is either not
mounted block device or regular file and we are forced to use it */
int can_we_format_it(char *device_name, int force)
{
mode_t mode;
dev_t rdev;
if (misc_device_mounted(device_name) > 0) {
/* device looks mounted */
reiserfs_warning(stderr, "'%s' looks mounted.", device_name);
check_forcing_ask_confirmation(force);
}
mode = misc_device_mode(device_name);
rdev = misc_device_rdev(device_name);
if (!S_ISBLK(mode)) {
/* file is not a block device */
reiserfs_warning(stderr, "%s is not a block special device\n",
device_name);
check_forcing_ask_confirmation(force);
} else {
if ((IDE_DISK_MAJOR(major(rdev)) && minor(rdev) % 64 == 0) ||
(SCSI_BLK_MAJOR(major(rdev)) && minor(rdev) % 16 == 0)) {
/* /dev/hda or similar */
reiserfs_warning(stderr,
"%s is entire device, not just one partition!\n",
device_name);
check_forcing_ask_confirmation(force);
}
}
return 1;
}
int create_badblock_bitmap(reiserfs_filsys_t *fs, char *badblocks_file)
{
FILE *fd;
char buf[128];
__u32 blocknr;
int count;
fs->fs_badblocks_bm =
reiserfs_create_bitmap(get_sb_block_count(fs->fs_ondisk_sb));
reiserfs_bitmap_zero(fs->fs_badblocks_bm);
if (!badblocks_file)
return 0;
fd = fopen(badblocks_file, "r");
if (fd == NULL) {
fprintf(stderr,
"%s: Failed to open the given badblock file '%s'.\n\n",
__FUNCTION__, badblocks_file);
return 1;
}
while (!feof(fd)) {
if (fgets(buf, sizeof(buf), fd) == NULL)
break;
count = sscanf(buf, "%u", &blocknr);
if (count <= 0)
continue;
if (blocknr >= get_sb_block_count(fs->fs_ondisk_sb)) {
fprintf(stderr,
"%s: block number (%u) points out of fs size "
"(%u).\n", __FUNCTION__, blocknr,
get_sb_block_count(fs->fs_ondisk_sb));
} else if (not_data_block(fs, blocknr)) {
fprintf(stderr,
"%s: block number (%u) belongs to system "
"reiserfs area. It cannot be relocated.\n",
__FUNCTION__, blocknr);
return 1;
} else {
reiserfs_bitmap_set_bit(fs->fs_badblocks_bm, blocknr);
}
}
fclose(fd);
return 0;
}
void badblock_list(reiserfs_filsys_t *fs, badblock_func_t action, void *data)
{
struct reiserfs_path badblock_path;
struct reiserfs_key rd_key = badblock_key;
struct reiserfs_key *key;
badblock_path.path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
set_type_and_offset(KEY_FORMAT_2, &badblock_key, 1, TYPE_INDIRECT);
while (1) {
if (reiserfs_search_by_key_4(fs, &rd_key, &badblock_path) ==
IO_ERROR) {
fprintf(stderr,
"%s: Some problems while searching by the key "
"occured. Probably due to tree corruptions.\n",
__FUNCTION__);
pathrelse(&badblock_path);
break;
}
if (get_blkh_nr_items(B_BLK_HEAD(get_bh(&badblock_path))) <=
PATH_LAST_POSITION(&badblock_path)) {
pathrelse(&badblock_path);
break;
}
rd_key = get_ih(&badblock_path)->ih_key;
if (get_key_dirid(&rd_key) != BADBLOCK_DIRID ||
get_key_objectid(&rd_key) != BADBLOCK_OBJID ||
!KEY_IS_INDIRECT_KEY(&rd_key)) {
pathrelse(&badblock_path);
break;
}
if ((key = reiserfs_next_key(&badblock_path)))
rd_key = *key;
else
memset(&rd_key, 0, sizeof(rd_key));
action(fs, &badblock_path, data);
if (get_key_dirid(&rd_key) == 0)
break;
}
}
static void callback_badblock_rm(reiserfs_filsys_t *fs,
struct reiserfs_path *badblock_path,
void *data)
{
struct tree_balance tb;
struct item_head *tmp_ih;
tmp_ih = get_ih(badblock_path);
memset(get_item(badblock_path), 0, get_ih_item_len(tmp_ih));
init_tb_struct(&tb, fs, badblock_path,
-(IH_SIZE +
get_ih_item_len(PATH_PITEM_HEAD(badblock_path))));
if (fix_nodes(M_DELETE, &tb, 0) != CARRY_ON)
die("%s: fix_nodes failed", __FUNCTION__);
do_balance( /*tb.transaction_handle, */ &tb, 0, 0, M_DELETE,
0 /*zero num */ );
}
void mark_badblock(reiserfs_filsys_t *fs,
struct reiserfs_path *badblock_path, void *data)
{
struct item_head *tmp_ih;
__u32 *ind_item;
__u32 i;
if (!fs->fs_badblocks_bm)
create_badblock_bitmap(fs, NULL);
tmp_ih = get_ih(badblock_path);
ind_item = (__u32 *) get_item(badblock_path);
for (i = 0; i < I_UNFM_NUM(tmp_ih); i++) {
reiserfs_bitmap_set_bit(fs->fs_badblocks_bm,
d32_get(ind_item, i));
}
pathrelse(badblock_path);
}
void add_badblock_list(reiserfs_filsys_t *fs, int replace)
{
struct tree_balance tb;
struct reiserfs_path badblock_path;
struct item_head badblock_ih;
__u32 ni;
__u64 offset;
__u32 i, j;
if (fs->fs_badblocks_bm == NULL)
return;
/* delete all items with badblock_key */
if (replace)
badblock_list(fs, callback_badblock_rm, NULL);
memset(&badblock_ih, 0, sizeof(badblock_ih));
set_ih_key_format(&badblock_ih, KEY_FORMAT_2);
set_ih_item_len(&badblock_ih, UNFM_P_SIZE);
set_ih_free_space(&badblock_ih, 0);
set_ih_location(&badblock_ih, 0);
set_key_dirid(&badblock_ih.ih_key, BADBLOCK_DIRID);
set_key_objectid(&badblock_ih.ih_key, BADBLOCK_OBJID);
set_type(KEY_FORMAT_2, &badblock_ih.ih_key, TYPE_INDIRECT);
j = 0;
/* insert all badblock pointers */
for (i = 0; i < fs->fs_badblocks_bm->bm_bit_size; i++) {
int retval;
if (!reiserfs_bitmap_test_bit(fs->fs_badblocks_bm, i))
continue;
offset = j * fs->fs_blocksize + 1;
set_offset(KEY_FORMAT_2, &badblock_ih.ih_key, offset);
ni = cpu_to_le32(i);
retval = usearch_by_position(fs, &badblock_ih.ih_key,
key_format(&badblock_ih.ih_key),
&badblock_path);
switch (retval) {
case (FILE_NOT_FOUND):
init_tb_struct(&tb, fs, &badblock_path,
IH_SIZE + get_ih_item_len(&badblock_ih));
if (fix_nodes(M_INSERT, &tb, &badblock_ih) != CARRY_ON)
die("reiserfsck_insert_item: fix_nodes failed");
do_balance(&tb, &badblock_ih, (void *)&ni, M_INSERT, 0);
break;
case (POSITION_NOT_FOUND):
case (POSITION_FOUND):
/* Insert the new item to the found position. */
init_tb_struct(&tb, fs, &badblock_path, UNFM_P_SIZE);
if (fix_nodes(M_PASTE, &tb, 0) != CARRY_ON)
die("reiserfsck_paste_into_item: fix_nodes failed");
do_balance(&tb, 0, (const char *)&ni, M_PASTE, 0);
break;
}
j++;
}
}