Ejemplo n.º 1
0
/* compose directory item containing "." and ".." entries */
void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
			  __u32 par_dirid, __u32 par_objid)
{
    struct reiserfs_de_head * deh;

    memset (body, 0, EMPTY_DIR_SIZE);
    deh = (struct reiserfs_de_head *)body;
    
    /* direntry header of "." */
    put_deh_offset( &(deh[0]), DOT_OFFSET );
    /* these two are from make_le_item_head, and are are LE */
    deh[0].deh_dir_id = dirid;
    deh[0].deh_objectid = objid;
    deh[0].deh_state = 0; /* Endian safe if 0 */
    put_deh_location( &(deh[0]), EMPTY_DIR_SIZE - ROUND_UP( strlen( "." ) ) );
    mark_de_visible(&(deh[0]));
  
    /* direntry header of ".." */
    put_deh_offset( &(deh[1]), DOT_DOT_OFFSET );
    /* key of ".." for the root directory */
    /* these two are from the inode, and are are LE */
    deh[1].deh_dir_id = par_dirid;
    deh[1].deh_objectid = par_objid;
    deh[1].deh_state = 0; /* Endian safe if 0 */
    put_deh_location( &(deh[1]), deh_location( &(deh[0])) - ROUND_UP( strlen( ".." ) ) );
    mark_de_visible(&(deh[1]));

    /* copy ".." and "." */
    memcpy (body + deh_location( &(deh[0]) ), ".", 1);
    memcpy (body + deh_location( &(deh[1]) ), "..", 2);
}
Ejemplo n.º 2
0
void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
			 __le32 par_dirid, __le32 par_objid)
{
	struct reiserfs_de_head *deh;

	memset(body, 0, EMPTY_DIR_SIZE);
	deh = (struct reiserfs_de_head *)body;

	
	put_deh_offset(&(deh[0]), DOT_OFFSET);
	
	deh[0].deh_dir_id = dirid;
	deh[0].deh_objectid = objid;
	deh[0].deh_state = 0;	
	put_deh_location(&(deh[0]), EMPTY_DIR_SIZE - ROUND_UP(strlen(".")));
	mark_de_visible(&(deh[0]));

	
	put_deh_offset(&(deh[1]), DOT_DOT_OFFSET);
	
	
	deh[1].deh_dir_id = par_dirid;
	deh[1].deh_objectid = par_objid;
	deh[1].deh_state = 0;	
	put_deh_location(&(deh[1]),
			 deh_location(&(deh[0])) - ROUND_UP(strlen("..")));
	mark_de_visible(&(deh[1]));

	
	memcpy(body + deh_location(&(deh[0])), ".", 1);
	memcpy(body + deh_location(&(deh[1])), "..", 2);
}
Ejemplo n.º 3
0
Archivo: dir.c Proyecto: 19Dan01/linux
/*
 * compose directory item containing "." and ".." entries (entries are
 * not aligned to 4 byte boundary)
 */
void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
			    __le32 par_dirid, __le32 par_objid)
{
	struct reiserfs_de_head *dot, *dotdot;

	memset(body, 0, EMPTY_DIR_SIZE_V1);
	dot = (struct reiserfs_de_head *)body;
	dotdot = dot + 1;

	/* direntry header of "." */
	put_deh_offset(dot, DOT_OFFSET);
	/* these two are from make_le_item_head, and are are LE */
	dot->deh_dir_id = dirid;
	dot->deh_objectid = objid;
	dot->deh_state = 0;	/* Endian safe if 0 */
	put_deh_location(dot, EMPTY_DIR_SIZE_V1 - strlen("."));
	mark_de_visible(dot);

	/* direntry header of ".." */
	put_deh_offset(dotdot, DOT_DOT_OFFSET);
	/* key of ".." for the root directory */
	/* these two are from the inode, and are are LE */
	dotdot->deh_dir_id = par_dirid;
	dotdot->deh_objectid = par_objid;
	dotdot->deh_state = 0;	/* Endian safe if 0 */
	put_deh_location(dotdot, deh_location(dot) - strlen(".."));
	mark_de_visible(dotdot);

	/* copy ".." and "." */
	memcpy(body + deh_location(dot), ".", 1);
	memcpy(body + deh_location(dotdot), "..", 2);
}
Ejemplo n.º 4
0
static void sprintf_de_head( char *buf, struct reiserfs_de_head *deh )
{
    if( deh )
        sprintf( buf, "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]", deh_offset(deh), deh_dir_id(deh),
                 deh_objectid(deh), deh_location(deh), deh_state(deh) );
    else
        sprintf( buf, "[NULL]" );

}
Ejemplo n.º 5
0
// de_bh, de_ih, de_deh (points to first element of array), de_item_num is set
inline void set_de_name_and_namelen(struct reiserfs_dir_entry *de)
{
	struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;

	BUG_ON(de->de_entry_num >= ih_entry_count(de->de_ih));

	de->de_entrylen = entry_length(de->de_bh, de->de_ih, de->de_entry_num);
	de->de_namelen = de->de_entrylen - (de_with_sd(deh) ? SD_SIZE : 0);
	de->de_name = B_I_PITEM(de->de_bh, de->de_ih) + deh_location(deh);
	if (de->de_name[de->de_namelen - 1] == 0)
		de->de_namelen = strlen(de->de_name);
}
Ejemplo n.º 6
0
void print_directory_item (FILE * fp, reiserfs_filsys_t fs,
			   struct buffer_head * bh, struct item_head * ih)
{
    int i;
    int namelen;
    struct reiserfs_de_head * deh;
    char * name;
/*    static char namebuf [80];*/

    if (!I_IS_DIRECTORY_ITEM (ih))
	return;

    //printk ("\n%2%-25s%-30s%-15s%-15s%-15s\n", "    Name", "length", "Object key", "Hash", "Gen number", "Status");
    reiserfs_warning (fp, "%3s: %-25s%s%-22s%-12s%s\n", "###", "Name", "length", "    Object key", "   Hash", "Gen number");
    deh = B_I_DEH (bh, ih);
    for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
	if (dir_entry_bad_location (deh, ih, i == 0 ? 1 : 0)) {
	    reiserfs_warning (fp, "%3d: wrong entry location %u, deh_offset %u\n",
			      i, deh_location (deh), deh_offset (deh));
	    continue;
	}
	if (i && dir_entry_bad_location (deh - 1, ih, ((i - 1) == 0) ? 1 : 0))
	    /* previous entry has bad location so we can not calculate entry
               length */
	    namelen = 25;
	else
	    namelen = name_length (ih, deh, i);

	name = name_in_entry (deh, i);
	reiserfs_warning (fp, "%3d: \"%-25.*s\"(%3d)%20K%12d%5d, loc %u, state %x %s\n", 
			  i, namelen, name, namelen,
                          /* this gets converted in print_short_key() */
			  (struct key *)&(deh->deh_dir_id),
			  GET_HASH_VALUE (deh_offset(deh)),
                          GET_GENERATION_NUMBER (deh_offset(deh)),
			  deh_location (deh), deh_state(deh),
			  fs ? (is_properly_hashed (fs, name, namelen, deh_offset (deh)) ? "" : "(BROKEN)") : "??");
    }
}
Ejemplo n.º 7
0
/*
 * de_bh, de_ih, de_deh (points to first element of array), de_item_num
 * is set
 */
void
set_de_name_and_namelen(struct reiserfs_dir_entry *de)
{
	struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;

	if (de->de_entry_num >= ih_entry_count(de->de_ih)) {
		reiserfs_log(LOG_DEBUG, "BUG\n");
		return;
	}

	de->de_entrylen = entry_length(de->de_bp, de->de_ih, de->de_entry_num);
	de->de_namelen  = de->de_entrylen - (de_with_sd(deh) ? SD_SIZE : 0);
	de->de_name     = B_I_PITEM(de->de_bp, de->de_ih) + deh_location(deh);
	if (de->de_name[de->de_namelen - 1] == 0)
		de->de_namelen = strlen(de->de_name);
}
Ejemplo n.º 8
0
/* FIXME: we can improve fixing of broken keys: we can ssfe direct items which
   go after stat data and have broken keys */
static void pass0_correct_leaf (reiserfs_filsys_t fs,
				struct buffer_head * bh)
{
    int i, j;
    struct item_head * ih;
    __u32 * ind_item;
    unsigned long unfm_ptr;
    int dirty = 0;

 start_again:

    ih = B_N_PITEM_HEAD (bh, 0);
    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
	if (ih->ih_key.k_dir_id == 0 || ih->ih_key.k_objectid == 0) {
	    /* sometimes stat datas get k_objectid==0 or k_dir_id==0 */
	    if (i == (node_item_number (bh) - 1)) {
		/* */
		if (i == 0) {
		    fsck_log ("block %lu: item %d: (%H) is alone in the block\n",
			      bh->b_blocknr, i, ih);
		    return;
		}
		/* delete last item */
		delete_item (fs, bh, i - 1);
		return;
	    }

	    /* there is next item: if it is not stat data - take its k_dir_id
               and k_objectid. if key order will be still wrong - the changed
               item will be deleted */
	    if (!is_stat_data_ih (ih + 1)) {
		fsck_log ("block %lu: item %d: (%H) fixed to ", bh->b_blocknr, i, ih);
		ih->ih_key.k_dir_id = (ih + 1)->ih_key.k_dir_id;
		ih->ih_key.k_objectid = (ih + 1)->ih_key.k_objectid;
		set_offset (KEY_FORMAT_1, &ih->ih_key, 0);
		set_type (KEY_FORMAT_1, &ih->ih_key, TYPE_STAT_DATA);
		fsck_log ("(%H)\n", ih);
		dirty = 1;
	    } else if (i == 0) {
		delete_item (fs, bh, i);
		goto start_again;
	    }
	}

	/* this recovers corruptions like the below: 
	   1774 1732 0 0
	   116262638 1732 1 3
	   1774 1736 0 0 */
	if (i && is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) {
	    if (ih->ih_key.k_objectid != (ih - 1)->ih_key.k_objectid ||
		ih->ih_key.k_dir_id != (ih - 1)->ih_key.k_dir_id ||
		get_offset (&ih->ih_key) != 1) {
		if (is_direntry_ih (ih)) {
		    fsck_log ("block %lu: item %d: no \".\" entry found in "
			      "the first item of a directory\n", bh->b_blocknr, i);
		} else {
		    fsck_log ("block %lu: item %d: (%H) fixed to ", 
			  bh->b_blocknr, i, ih);
		    ih->ih_key.k_dir_id = (ih - 1)->ih_key.k_dir_id;
		    ih->ih_key.k_objectid = (ih - 1)->ih_key.k_objectid;
		    
		    if (ih_item_len (ih - 1) == SD_SIZE) {
			/* stat data is new, therefore this item is new too */
			set_offset (KEY_FORMAT_2, &(ih->ih_key), 1);
			if (ih_entry_count (ih) != 0xffff)
			    set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_INDIRECT);
			else
			    set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_DIRECT);
			set_ih_key_format (ih, KEY_FORMAT_2);
		    } else {
			/* stat data is old, therefore this item is old too */
			set_offset (KEY_FORMAT_1, &(ih->ih_key), 1);
			if (ih_entry_count (ih) != 0xffff)
			    set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_INDIRECT);
			else
			    set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_DIRECT);
			set_ih_key_format (ih, KEY_FORMAT_1);
		    }
		    fsck_log ("%H\n", ih);
		    dirty = 1;
		}
	    }
	}

	/* FIXME: corruptions like:
	   56702 66802 1 2
	   56702 65536 0 0
	   56702 66803 1 2
	   do not get recovered (both last items will be deleted) */
	/* delete item if it is not in correct order of object items */
	if (i && not_of_one_file (&ih->ih_key, &(ih - 1)->ih_key) &&
	    !is_stat_data_ih (ih)) {
	    fsck_log ("block %lu: item %d: %H follows non stat item %H - deleted\n",
		      bh->b_blocknr, i, ih, ih - 1);
	    delete_item (fs, bh, i);
	    goto start_again;
	}

	if (i &&  comp_keys (&(ih - 1)->ih_key, &ih->ih_key) != -1) {
	    /* previous item has key not smaller than the key of currect item */
	    if (is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) {
		/* fix key of stat data such as if it was stat data of that item */
		fsck_log ("pass0: block %lu: %d-th item %k is out of order, made a stat data of %d-th (%k)\n",
			  bh->b_blocknr, i - 1, &(ih - 1)->ih_key, i, &ih->ih_key);
		(ih - 1)->ih_key.k_dir_id = ih->ih_key.k_dir_id;
		(ih - 1)->ih_key.k_objectid = ih->ih_key.k_objectid;
		set_offset (KEY_FORMAT_1, &(ih - 1)->ih_key, 0);
		set_type (KEY_FORMAT_1, &(ih - 1)->ih_key, TYPE_STAT_DATA);
		dirty = 1;
	    } else {
		/* ok, we have to delete one of these two - decide which one */
		int retval;

		/* something will be deleted */
		dirty = 1;
		retval = upper_correct (bh, ih - 1, i - 1);
		switch (retval) {
		case 0:
		    /* delete upper item */
		    fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i - 1, &(ih - 1)->ih_key);
		    delete_item (fs, bh, i - 1);
		    goto start_again;

		case 1:
		    /* delete lower item */
		    fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i, &ih->ih_key);
		    delete_item (fs, bh, i);
		    goto start_again;

		default:
		    /* upper item was the first item of a node */
		}

		retval = lower_correct (bh, ih, i);
		switch (retval) {
		case 0:
		    /* delete lower item */
		    fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i, &ih->ih_key);
		    delete_item (fs, bh, i);
		    goto start_again;

		case 1:
		    /* delete upper item */
		    fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i - 1, &(ih - 1)->ih_key);
		    delete_item (fs, bh, i - 1);
		    goto start_again;

		default:
		    /* there wer only two items in a node, so we could not
                       decide what to delete, go and ask user */
		}
		fsck_log ("pass0: which of these items looks better (other will be deleted)?\n"
			  "%H\n%H\n", ih - 1, ih);
		if (fsck_user_confirmed (fs, "1 or 2?", "1\n", 1))
		    delete_item (fs, bh, i - 1);
		else
		    delete_item (fs, bh, i);
		goto start_again;
	    }
	}

	if (is_stat_data_ih (ih) && (ih_item_len (ih) != SD_SIZE &&
				     ih_item_len (ih) != SD_V1_SIZE)) {
	    fsck_log ("pass0: block %lu, stat data of wrong length %H - deleted\n",
		      bh, ih);
	    delete_item (fs, bh, i);
	    goto start_again;
	}

	dirty += correct_key_format (ih);

	if (is_stat_data_ih (ih)) {
	    ;/*correct_stat_data (fs, bh, i);*/
	}

	if (is_direntry_ih (ih)) {
	    verify_directory_item (fs, bh, i);
	    continue;
	}

	if (!is_indirect_ih (ih))
	    continue;
	
	ind_item = (__u32 *)B_I_PITEM (bh, ih);
	for (j = 0; j < I_UNFM_NUM (ih); j ++) {
	    unfm_ptr = le32_to_cpu (ind_item [j]);
	    if (!unfm_ptr)
		continue;
	    
	    if (fsck_mode (fs) == FSCK_ZERO_FILES) {
		/* FIXME: this is temporary mode of fsck */
		ind_item [j] = 0;
		reiserfs_bitmap_clear_bit (fsck_new_bitmap(fs), unfm_ptr);
		tmp_zeroed ++;
		dirty = 1;
		continue;
	    }

	    if (not_data_block (fs, unfm_ptr) || /* journal area or bitmap or super block */
		unfm_ptr >= SB_BLOCK_COUNT (fs)) {/* garbage in pointer */

		stats (fs)->wrong_pointers ++;
		/*
		fsck_log ("pass0: %d-th pointer (%lu) in item %k (leaf block %lu) is wrong\n",
			  j, unfm_ptr, &ih->ih_key, bh->b_blocknr);
		*/
		ind_item [j] = 0;
		dirty = 1;
		continue;
	    }
#if 0
	    if (!was_block_used (unfm_ptr)) {
	      /* this will get to a pool of allocable blocks */
	      ind_item [j] = 0;
	      dirty = 1;
	      stat_wrong_pointer_found (fs);
	      continue;
	    }
#endif
	    /* mark block in bitmaps of unformatted nodes */
	    register_unfm (unfm_ptr);
	}
    }

    /* mark all objectids in use */
    ih = B_N_PITEM_HEAD (bh, 0);
    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
	mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_dir_id));
	mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_objectid));
    }

    if (node_item_number (bh) < 1) {
	/* pass 1 will skip this */
	stats(fs)->all_contents_removed ++;
	fsck_log ("pass0: block %lu got all items deleted\n",
		  bh->b_blocknr);
    } else {
	/* pass1 will use this bitmap */
	pass0_mark_leaf (bh->b_blocknr);

    }
    if (dirty) {
	stats(fs)->leaves_corrected ++;
	mark_buffer_dirty (bh);
    }
}


static int is_bad_sd (struct item_head * ih, char * item)
{
    struct stat_data * sd = (struct stat_data *)item;

    if (le32_to_cpu(ih->ih_key.u.k_offset_v1.k_offset) || le32_to_cpu(ih->ih_key.u.k_offset_v1.k_uniqueness)) {
	reiserfs_warning (stderr, "Bad SD? %H\n", ih);
	return 1;
    }

    if (ih_item_len (ih) == SD_V1_SIZE) {
	/* looks like old stat data */
	if (ih_key_format (ih) != KEY_FORMAT_1)
	    fsck_log ("item %H has wrong format\n", ih);
	return 0;
    }

    if (!S_ISDIR (sd_v2_mode(sd)) && !S_ISREG(sd_v2_mode(sd)) &&
	!S_ISCHR (sd_v2_mode(sd)) && !S_ISBLK(sd_v2_mode(sd)) &&
	!S_ISLNK (sd_v2_mode(sd)) && !S_ISFIFO(sd_v2_mode(sd)) &&
	!S_ISSOCK(sd_v2_mode(sd))) {	
	/*fsck_log ("file %k unexpected mode encountered 0%o\n", &ih->ih_key, sd_v2_mode(sd))*/;
    }
    return 0;
}


int is_bad_directory (struct item_head * ih, char * item, int dev, int blocksize)
{
    int i;
    char * name;
    int namelen, entrylen;
    struct reiserfs_de_head * deh = (struct reiserfs_de_head *)item;
    __u32 prev_offset = 0;
    __u16 prev_location = ih_item_len (ih);
    int min_entry_size = 1;/* we have no way to understand whether the
                              filesystem were created in 3.6 format or
                              converted to it. So, we assume that minimal name
                              length is 1 */

    if (ih_item_len (ih) / (DEH_SIZE + min_entry_size) < ih_entry_count (ih))
	/* entry count is too big */
	return 1;

    for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
	entrylen = entry_length(ih, deh, i);
	if (entrylen > REISERFS_MAX_NAME_LEN (blocksize)) {
	    return 1;
	}
	if (deh_offset (deh) <= prev_offset) {
	    return 1;
	}
	prev_offset = deh_offset (deh);

	if (deh_location(deh) + entrylen != prev_location) {
	    return 1;
	}
	prev_location = deh_location (deh);

	namelen = name_length (ih, deh, i);
	name = name_in_entry (deh, i);
	if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) {
	    return 1;
	}
    }
    return 0;
}


/* change incorrect block adresses by 0. Do not consider such item as incorrect */
static int is_bad_indirect (struct item_head * ih, char * item, int dev, int blocksize)
{
    int i;
    int bad = 0;
    int blocks;

    if (ih_item_len(ih) % UNFM_P_SIZE) {
	fsck_log ("is_bad_indirect: indirect item of %H of invalid length\n", ih);
	return 1;
    }

    blocks = SB_BLOCK_COUNT (fs);
  
    for (i = 0; i < I_UNFM_NUM (ih); i ++) {
	__u32 * ind = (__u32 *)item;

	if (le32_to_cpu (ind[i]) >= blocks) {
	    bad ++;
	    fsck_log ("is_bad_indirect: %d-th pointer of item %H looks bad (%lu)\n",
		      i, ih, le32_to_cpu (ind [i]));
	    continue;
	}
    }
    return bad;
}
Ejemplo n.º 9
0
/* check directory item and try to recover something */
static int verify_directory_item (reiserfs_filsys_t fs, struct buffer_head * bh,
				  int item_num)
{
    struct item_head * ih;
    struct item_head tmp;
    char * item;
    struct reiserfs_de_head * deh;
    char * name;
    int name_len;
    int bad;
    int i, j;
#if 0
    int bad_entries; /* how many bad neighboring entries */
    int total_entry_len;
    char * entries, * end;
#endif
    int dirty;
    int entry_count;
    int hash_code;
    int bad_locations;

#ifdef DEBUG_VERIFY_DENTRY
    char * direntries;
#endif


    ih = B_N_PITEM_HEAD (bh, item_num);
    item = B_I_PITEM (bh,ih);
    deh = (struct reiserfs_de_head *)item;

    dirty = 0;
    bad_locations = 0;
    entry_count = ih_entry_count (ih);


    /* check deh_location */
    for (i = 0; i < ih_entry_count (ih); i ++) {
	/* silently fix deh_state */
	if (deh [i].deh_state != (1 << DEH_Visible)) {
	    deh [i].deh_state = cpu_to_le16 (1 << DEH_Visible);
	    mark_buffer_dirty (bh);
	}
	if (dir_entry_bad_location (deh + i, ih, !i))
	    mark_de_bad_location (deh + i);
    }

#ifdef DEBUG_VERIFY_DENTRY
    direntries = getmem (ih_entry_count (ih) * sizeof (int));

    printf ("entries with bad locations: ");
    for (i = 0; i < ih_entry_count (ih); i ++) {
	if (de_bad_location (deh + i))
	    printf ("%d ", i);
    }
    printf ("\n");
#endif /* DEBUG_VERIFY_DENTRY */


    /* find entries names in which have mismatching deh_offset */
    for (i = ih_entry_count (ih) - 1; i >= 0; i --) {
	if (de_bad (deh + i))
	    /* bad location */
	    continue;

	if (i) {
	    if (deh_location (deh + i - 1) < deh_location (deh + i))
		mark_de_bad_location (deh + i - 1);
	}

	name = name_in_entry (deh + i, i);
	/* we found a name, but we not always we can get its length as
           it depends on deh_location of previous entry */
	name_len = try_to_get_name_length (ih, deh + i, i);

#ifdef DEBUG_VERIFY_DENTRY
	if (name_len == 0)
	    printf ("trying to find name length for %d-th entry\n", i);
#endif /* DEBUG_VERIFY_DENTRY */
	if (is_dot (name, name_len)) {
	    if (i != 0)
		fsck_log ("block %lu: item %d: \".\" is %d-th entry\n",
			  bh->b_blocknr, item_num, i);
	    /* check and fix "." */
	    
	    if (deh_offset (deh + i) != DOT_OFFSET) {
		set_deh_offset(&(deh[i]), DOT_OFFSET);
		mark_buffer_dirty (bh);
	    }
	    /* "." must point to the directory it is in */
	    if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) { /* endian safe */
		fsck_log ("verify_direntry: block %lu, item %H has entry \".\" "
			  "pointing to (%K) instead of (%K)\n", 
			  bh->b_blocknr, ih,
			  &(deh[i].deh_dir_id), &(ih->ih_key));
		deh[i].deh_dir_id = ih->ih_key.k_dir_id; /* both LE */
		deh[i].deh_objectid = ih->ih_key.k_objectid; /* both LE */
		mark_buffer_dirty (bh);
	    }
	} else if (is_dot_dot (name, name_len)) {
	    if (i != 1)
		fsck_log ("block %lu: item %d: \"..\" is %d-th entry\n",
			  bh->b_blocknr, item_num, i);
	    
	    /* check and fix ".." */
	    if (deh_offset (deh + i) != DOT_DOT_OFFSET)
		set_deh_offset(&(deh[i]), DOT_DOT_OFFSET);
	} else {
	    int min_length, max_length;

	    /* check other name */

	    if (name_len == 0) {
		/* we do not know the length of name - we will try to find it */
		min_length = 1;
		max_length = item + ih_item_len (ih) - name;
	    } else
		/* we kow name length, so we will try only one name length */
		min_length = max_length = name_len;

	    for (j = min_length; j <= max_length; j ++) {
		hash_code = find_hash_in_use (name, j,
					      GET_HASH_VALUE (deh_offset (deh + i)),
					      rs_hash (fs->s_rs));
		add_hash_hit (fs, hash_code);
		if (code2func (hash_code) != 0) {
		    /* deh_offset matches to some hash of the name */
		    if (!name_len) {
			fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" "
				  "matching to deh_offset %u. FIXME: should set deh_location "
				  "of previous entry (not ready)\n",
				  bh->b_blocknr, ih, i, j, name, deh_offset (deh + i));
			/* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */
			if (i) {
			    set_deh_location( &(deh[i - 1]),
                                deh_location (deh + i) +
                                ((name[j] || SB_VERSION (fs) ==
                                REISERFS_VERSION_1) ? j : ROUND_UP (j)));
			    mark_de_good_location (deh + i - 1);
			    mark_buffer_dirty (bh);
			}
		    }
		    break;
		}
	    }
	    if (j == max_length + 1) {
		/* deh_offset does not match to anything. it will be
		   deleted for now, but maybe we could just fix a
		   deh_offset if it is in ordeer */
		mark_de_bad_offset (deh + i);
	    }
	}
    } /* for */



#if 0
    /* find entries names in which have mismatching deh_offset */
    for (i = 0; i < ih_entry_count (ih); i ++) {
	if (de_bad (deh + i))
	    /* bad location */
	    continue;

	name = name_in_entry (deh + i, i);
	/* we found a name, but we not always we can get its length as
           it depends on deh_location of previous entry */
	name_len = try_to_get_name_length (ih, deh + i, i);

	if (i == 0 && is_dot (name, name_len)) {
	    
	    /* check and fix "." */
	    
	    if (deh_offset (deh + i) != DOT_OFFSET) {
		deh[i].deh_offset = cpu_to_le32 (DOT_OFFSET);
	    }
	    /* "." must point to the directory it is in */
	    if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) {
		fsck_log ("verify_direntry: block %lu, item %H has entry \".\" "
			  "pointing to (%K) instead of (%K)\n", 
			  bh->b_blocknr, ih,
			  &(deh[i].deh_dir_id), &(ih->ih_key));
		deh[i].deh_dir_id = ih->ih_key.k_dir_id; /* both 32 bit LE */
		deh[i].deh_objectid = ih->ih_key.k_objectid; /* both 32 bit LE */
		mark_buffer_dirty (bh);
	    }
	} else if (i == 1 && is_dot_dot (name, name_len)) {
	    
	    /* check and fix ".." */

	    if (deh_offset (deh + i) != DOT_DOT_OFFSET)
		deh[i].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET);
	} else {
	    int min_length, max_length;

	    /* check other name */

	    if (name_len == 0) {
		/* we do not know the length of name - we will try to find it */
		min_length = 1;
		max_length = item + ih_item_len (ih) - name;
	    } else
		/* we kow name length, so we will try only one name length */
		min_length = max_length = name_len;

	    for (j = min_length; j <= max_length; j ++) {
		hash_code = find_hash_in_use (name, j,
					      GET_HASH_VALUE (deh_offset (deh + i)),
					      rs_hash (fs->s_rs));
		add_hash_hit (fs, hash_code);
		if (code2func (hash_code) != 0) {
		    /* deh_offset matches to some hash of the name */
		    if (!name_len) {
			fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" "
				  "matching to deh_offset %u. FIXME: should set deh_location "
				  "of previous entry (not ready)\n",
				  bh->b_blocknr, ih, i, j, name, deh_offset (deh + i));
			/* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */
			deh[i - 1].deh_location = cpu_to_le16 (deh_location (deh + i) +
							       ((name[j] || SB_VERSION (fs) == REISERFS_VERSION_1) ? j : ROUND_UP (j)));
		    }
		    break;
		}
	    }
	    if (j == max_length + 1) {
		/* deh_offset does not match to anything. it will be
		   deleted for now, but maybe we could just fix a
		   deh_offset if it is in ordeer */
		mark_de_bad_offset (deh + i);
	    }
	}
   }
 #endif

 #ifdef DEBUG_VERIFY_DENTRY
     printf ("entries with mismatching deh_offsets: ");
     for (i = 0; i < ih_entry_count (ih); i ++) {
       if (de_bad_offset (deh + i))
           printf ("%d ", i);
     }
     printf ("\n");
 #endif /* DEBUG_VERIFY_DENTRY */


     /* correct deh_locations such that code cutting entries will not get
        screwed up */
     {
       int prev_loc;
       int loc_fixed;


       prev_loc = ih_item_len (ih);
       for (i = 0; i < ih_entry_count (ih); i ++) {
           loc_fixed = 0;
           if (de_bad_location (deh + i)) {
               set_deh_location(&(deh[i]), prev_loc/* - 1*/);
               mark_buffer_dirty (bh);
               loc_fixed = 1;
           } else {
               if (deh_location (deh + i) >= prev_loc) {
                   set_deh_location(&(deh[i]), prev_loc/* - 1*/);
                   mark_buffer_dirty (bh);
                   loc_fixed = 1;
               }
           }

           prev_loc = deh_location (deh + i);

           if (i == ih_entry_count (ih) - 1) {
               /* last entry starts right after an array of dir entry headers */
               if (!de_bad (deh + i) &&
                   deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih))) {

                   /* free space in the directory item */
                   fsck_log ("verify_direntry: block %lu, item %H has free
pace\n",
                             bh->b_blocknr, ih);
                   cut_entry (fs, bh, item_num, ih_entry_count (ih), 0);
               }
               if (deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih)))
               {

                   set_deh_location(&(deh[i]), DEH_SIZE * ih_entry_count (ih));
                   loc_fixed = 1;
                   mark_buffer_dirty (bh);
               }
           }

 #ifdef DEBUG_VERIFY_DENTRY
           if (loc_fixed)
               direntries [i] = 1;
 #endif
       } /* for */

 #ifdef DEBUG_VERIFY_DENTRY
       printf ("entries with fixed deh_locations: ");
       for (i = 0; i < ih_entry_count (ih); i ++) {
           if (direntries [i])
               printf ("%d ", i);
       }
       printf ("\n");
 #endif /* DEBUG_VERIFY_DENTRY */

     }

 #ifdef DEBUG_VERIFY_DENTRY
     printf (" N  location name\n");
     for (i = 0; i < ih_entry_count (ih); i ++) {
       if (de_bad (deh + i) ||
           (i && de_bad (deh + i - 1)) || /* previous entry marked bad */
           (i < ih_entry_count (ih) - 1 && de_bad (deh + i + 1))) { /* next
ntry is marked bad */
           /* print only entries to be deleted and their nearest neighbors */
           printf ("%3d: %8d ", i, deh_location (deh + i));
           if (de_bad (deh + i))
               printf ("will be deleted\n");
           else
               printf ("\"%.*s\"\n", name_length (ih, deh + i, i),
                       name_in_entry (deh + i, i));
       }
     }
 #endif

     bad = 0;
     tmp = *ih;

     /* delete entries which are marked bad */
     for (i = 0; i < ih_entry_count (ih); i ++) {
       deh = B_I_DEH (bh, ih) + i;
       if (de_bad (deh)) {
           bad ++;
           if (ih_entry_count (ih) == 1) {
               delete_item (fs, bh, item_num);
               break;
           } else {
               cut_entry (fs, bh, item_num, i, 1);
           }
	   i --;
	}
    }
    
    if (bad == ih_entry_count (&tmp)) {
	fsck_log ("pass0: block %lu, item %H - all entries were deleted\n", bh->b_blocknr, &tmp);
	return 0;
    }

    deh = B_I_DEH (bh, ih);
    if (get_offset (&ih->ih_key) != deh_offset (deh)) {
	fsck_log ("verify_direntry: block %lu, item %H:  k_offset and deh_offset %u mismatched\n",
		  bh->b_blocknr, ih, deh_offset (deh));
	set_offset (KEY_FORMAT_1, &ih->ih_key, deh_offset (deh));
	mark_buffer_dirty (bh);
    }
    
    if (bad)
	fsck_log ("pass0: block %lu, item %H: %d entries were deleted of \n",
		  bh->b_blocknr, &tmp, bad);
	
    return 0;

#if 0

    /* FIXME: temporary */
    if (bad_locations > ih_entry_count (ih) / 2) {
	fsck_log ("pass0: block %u: item %d (%H) had too bad directory - deleted\n",
		  bh->b_blocknr, item_num, ih);
	delete_item (fs, bh, item_num);
	return 0;
    }

    if (!dirty)
	return 0;
    
    /* something is broken */

    fsck_log ("pass0: block %lu: %d-th item (%H) has %d bad entries..",
	      bh->b_blocknr, item_num, ih, dirty);

    if (get_offset (&ih->ih_key) == DOT_OFFSET) {
	/* first item of directory - make sure that "." and ".." are in place */
	if (deh_offset (deh) != DOT_OFFSET || name_in_entry (deh, 0)[0] != '.') {
	    set_deh_offset(deh, DOT_OFFSET);
	    name_in_entry (deh, 0)[0] = '.';
	}
	if (deh_offset (deh + 1) != DOT_DOT_OFFSET ||
	    name_in_entry (deh + 1, 1)[0] != '.' || name_in_entry (deh + 1, 1)[1] != '.') {
	    set_deh_offset((deh + 1), DOT_DOT_OFFSET);
	    name_in_entry (deh + 1, 1)[0] = '.';
	    name_in_entry (deh + 1, 1)[1] = '.';
	}
    }

    end = item + ih_item_len (ih);
    deh += ih_entry_count (ih);
    entries = (char *)deh;
    total_entry_len = ih_item_len (ih) - DEH_SIZE * ih_entry_count (ih);
    i = ih_entry_count (ih);

    bad_entries = 0;
    do {
	i --;
	deh --;
	name_len = prob_name (fs, &entries, total_entry_len, deh_offset (deh));
	if (!name_len) {
	    if (!bad_entries) {
                set_deh_location(deh, entries - item);
	    } else {
                set_deh_location(deh, deh_location((deh + 1)) + 1 );
	    }
	    bad_entries ++;
	    
	    /*fsck_log ("verify_directory_item: entry %d: in string \'%s\' there is no substring matching hash %ld\n",
	      i, bad_name (entries, total_entry_len), masked_offset);*/
	    mark_de_bad (deh);
	    continue;
	}
	bad_entries = 0;
	/*fsck_log ("verify_directory_item: entry %d: found \"%s\" name matching hash %ld\n",
	  i, bad_name (entries, name_len), masked_offset);*/
	
	/* 'entries' points now to the name which match given offset -
           so, set deh_location */
        set_deh_location(deh, entries - item);
	deh->deh_state = 0;
	mark_de_visible (deh);
	
	entries += name_len;
	total_entry_len = end - entries;
	/* skip padding zeros */
	while (!*entries) {
	    entries ++;
	    total_entry_len --;
	}
	/* 'entries' points now at the place where next (previous)
           entry should start */
    } while ((char *)deh != item);
    
    
    /* fixme: this will not work if all entries are to be deleted */
    for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
	deh = (struct reiserfs_de_head *)B_I_PITEM (bh, ih) + i;
	if (de_bad (deh)) {
	    if (ih_entry_count (ih) == 1) {
		delete_item (fs, bh, i);
		break;
	    } else {
		cut_entry (fs, bh, item_num, i);
	    }
	    i --;
	}
/*
  fsck_log ("verify_directory_item: %d-th entry is to be deleted: "
  "\"%s\" does not match to hash %lu\n", 
  i, bad_name (name_in_entry (deh, i), name_length (ih, deh, i)),
  deh_offset (deh));
*/
    }
    
    fsck_log ("%d entries were deleted\n", entry_count - ih_entry_count (ih));
    mark_buffer_dirty (bh);

    
    return 0;

#endif
}
Ejemplo n.º 10
0
/* preconditions: reiserfs_read_super already executed, therefore
 *   INFO block is valid
 * returns: 0 if error, nonzero iff we were able to find the file successfully
 * postconditions: on a nonzero return, INFO->fileinfo contains the info
 *   of the file we were trying to look up, filepos is 0 and filemax is
 *   the size of the file.
 */
static int
reiserfs_open_file( char *dirname )
{
     struct reiserfs_de_head *de_head;
     char *rest, ch;
     __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0;

     char linkbuf[PATH_MAX];	/* buffer for following symbolic links */
     int link_count = 0;
     int mode;
     errnum = 0;

     dir_id = cpu_to_le32(REISERFS_ROOT_PARENT_OBJECTID);
     objectid = cpu_to_le32(REISERFS_ROOT_OBJECTID);

     while ( 1 )
     {

	  DEBUG_F( "dirname=%s\n", dirname );

	  /* Search for the stat info first. */
	  if ( !search_stat( dir_id, objectid ) )
	       return 0;


	  DEBUG_F( "sd_mode=0%o sd_size=%Lu\n",
		   sd_mode((struct stat_data *) INFO->current_item ),
		   sd_size(INFO->current_ih, INFO->current_item ));


	  mode = sd_mode((struct stat_data *)INFO->current_item);

	  /* If we've got a symbolic link, then chase it. */
	  if ( S_ISLNK( mode ) )
	  {
	       int len = 0;

	       DEBUG_F("link count = %d\n", link_count);
	       DEBUG_SLEEP;
	       if ( ++link_count > MAX_LINK_COUNT )
	       {
		    DEBUG_F("Symlink loop\n");
		    errnum = FILE_ERR_SYMLINK_LOOP;
		    return 0;
	       }

	       /* Get the symlink size. */
	       INFO->file->len = sd_size(INFO->current_ih, INFO->current_item);

	       /* Find out how long our remaining name is. */
	       while ( dirname[len] && !isspace( dirname[len] ) )
		    len++;

	       if ( INFO->file->len + len > sizeof ( linkbuf ) - 1 )
	       {
		    errnum = FILE_ERR_LENGTH;
		    return 0;
	       }

	       /* Copy the remaining name to the end of the symlink data. Note *
		* that DIRNAME and LINKBUF may overlap! */
	       memmove( linkbuf + INFO->file->len, dirname, len + 1 );

	       INFO->fileinfo.k_dir_id = dir_id;
	       INFO->fileinfo.k_objectid = objectid;
	       INFO->file->pos = 0;
	       if ( !next_key()
		    || reiserfs_read_data( linkbuf, INFO->file->len ) != INFO->file->len ) {
		    DEBUG_F("reiserfs_open_file - if !next_key || reiserfs_read_data\n");
		    DEBUG_SLEEP;
		    errnum = FILE_IOERR;
		    return 0;
	       }


	       DEBUG_F( "symlink=%s\n", linkbuf );
	       DEBUG_SLEEP;

	       dirname = linkbuf;
	       if ( *dirname == '/' )
	       {
		    /* It's an absolute link, so look it up in root. */
		    dir_id = cpu_to_le32(REISERFS_ROOT_PARENT_OBJECTID);
		    objectid = cpu_to_le32(REISERFS_ROOT_OBJECTID);
	       }
	       else
	       {
		    /* Relative, so look it up in our parent directory. */
		    dir_id = parent_dir_id;
		    objectid = parent_objectid;
	       }

	       /* Now lookup the new name. */
	       continue;
	  }

	  /* if we have a real file (and we're not just printing *
	   * possibilities), then this is where we want to exit */

	  if ( !*dirname || isspace( *dirname ) )
	  {
	       if ( !S_ISREG( mode ) )
	       {
		    errnum = FILE_ERR_BAD_TYPE;
		    return 0;
	       }

	       INFO->file->pos = 0;
	       INFO->file->len = sd_size(INFO->current_ih, INFO->current_item);

	       INFO->fileinfo.k_dir_id = dir_id;
	       INFO->fileinfo.k_objectid = objectid;
	       return next_key();
	  }

	  /* continue with the file/directory name interpretation */
	  while ( *dirname == '/' )
	       dirname++;
	  if ( !S_ISDIR( mode ) )
	  {
	       errnum = FILE_ERR_NOTDIR;
	       return 0;
	  }
	  for ( rest = dirname; ( ch = *rest ) && !isspace( ch ) && ch != '/';
		rest++ ) ;
	  *rest = 0;

	  while ( 1 )
	  {
	       char *name_end;
	       int num_entries;

	       if ( !next_key() )
		    return 0;

	       if ( INFO->current_ih->ih_key.k_objectid != objectid )
		    break;

	       name_end = INFO->current_item + ih_item_len(INFO->current_ih);
	       de_head = ( struct reiserfs_de_head * ) INFO->current_item;
	       num_entries = ih_entry_count(INFO->current_ih);
	       while ( num_entries > 0 )
	       {
		    char *filename = INFO->current_item + deh_location(de_head);
		    char tmp = *name_end;

		    if( deh_state(de_head) & (1 << DEH_Visible))
		    {
			 int cmp;

			 /* Directory names in ReiserFS are not null * terminated.
			  * We write a temporary 0 behind it. * NOTE: that this
			  * may overwrite the first block in * the tree cache.
			  * That doesn't hurt as long as we * don't call next_key
			  * () in between. */
			 *name_end = 0;
			 cmp = strcmp( dirname, filename );
			 *name_end = tmp;
			 if ( cmp == 0 )
			      goto found;
		    }
		    /* The beginning of this name marks the end of the next name.
		     */
		    name_end = filename;
		    de_head++;
		    num_entries--;
	       }
	  }

	  errnum = FILE_ERR_NOTFOUND;
	  *rest = ch;
	  return 0;

     found:
	  *rest = ch;
	  dirname = rest;

	  parent_dir_id = dir_id;
	  parent_objectid = objectid;
	  dir_id = de_head->deh_dir_id; /* LE */
	  objectid = de_head->deh_objectid; /* LE */
     }
}