/*
 *  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 key root_dir_key = {0, 0, {{0, 0},}};
struct key parent_root_dir_key = {0, 0, {{0, 0},}};
struct key lost_found_dir_key = {0, 0, {{0, 0}, }};
struct 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 key * key,
				     struct path * path, int key_length)
{
    struct buffer_head * bh;   
    unsigned long block;
    struct 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 key * key,
			      struct path * path)
{
    return reiserfs_search_by_key_x (fs, key, path, 3);
}


int reiserfs_search_by_key_4 (reiserfs_filsys_t * fs, struct key * key,
			      struct 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 key * key,
			 int version, struct path * path)
{
    struct buffer_head * bh;
    struct item_head * ih;
    struct 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 key * uget_lkey (struct 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 key * uget_rkey (struct 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 key * reiserfs_next_key (struct 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 key * key, 
				  struct path * path)
{
    struct buffer_head * bh;
    int item_pos;
    struct item_head * ih;
    struct 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 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 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 key * key)
{
    struct 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 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 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 key * dir, char * name,
			   struct path * path)
{
    struct key entry_key;
    struct item_head * ih;
    struct reiserfs_de_head * deh;
    int i, retval;
    struct 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 key * dir, char * name, 
			 unsigned int * min_gen_counter, struct key * key)
{
    struct key entry_key;
    int retval;
    int i;
    INITIALIZE_PATH (path);
    struct item_head * ih;
    struct reiserfs_de_head * deh;
    struct 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 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 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 key * dir, char * name, int name_len,
			struct key * key, __u16 fsck_need)
{
    struct item_head entry_ih = {{0,}, };
    char * entry;
    int retval;
    INITIALIZE_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 path * path, struct 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_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 path badblock_path;
    struct key rd_key = badblock_key;
    struct 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 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 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 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++;
    }
}
