示例#1
0
/*=gfunc len
 *
 * what:   get count of values
 *
 * exparg: ag-name, name of AutoGen value
 *
 * doc:  If the named object is a group definition, then "len" is
 *       the same as "count".  Otherwise, if it is one or more text
 *       definitions, then it is the sum of their string lengths.
 *       If it is a single text definition, then it is equivalent to
 *       @code{(string-length (get "ag-name"))}.
=*/
SCM
ag_scm_len(SCM obj)
{
    int len = entry_length(ag_scm2zchars(obj, "ag value"));

    return AG_SCM_INT2SCM(len);
}
示例#2
0
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 (_search_by_entry_key (fs, key, &path) != POSITION_FOUND) {
	pathrelse (&path);
	return 1;
    }

    ih = get_ih (&path);
    if (ih_entry_count (ih) == 1) {
	_init_tb_struct (&tb, fs, &path, -(IH_SIZE + 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;
}
示例#3
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);
}
示例#4
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);
}
示例#5
0
static int reiserfs_readdir (struct file * filp, void * dirent, filldir_t filldir)
{
    struct inode *inode = filp->f_dentry->d_inode;
    struct cpu_key pos_key;	/* key of current position in the directory (key of directory entry) */
    INITIALIZE_PATH (path_to_entry);
    struct buffer_head * bh;
    int item_num, entry_num;
    const struct key * rkey;
    struct item_head * ih, tmp_ih;
    int search_res;
    char * local_buf;
    loff_t next_pos;
    char small_buf[32] ; /* avoid kmalloc if we can */
    struct reiserfs_dir_entry de;


    reiserfs_check_lock_depth("readdir") ;

    /* form key for search the next directory entry using f_pos field of
       file structure */
    make_cpu_key (&pos_key, inode, (filp->f_pos) ? (filp->f_pos) : DOT_OFFSET,
		  TYPE_DIRENTRY, 3);
    next_pos = cpu_key_k_offset (&pos_key);

    /*  reiserfs_warning ("reiserfs_readdir 1: f_pos = %Ld\n", filp->f_pos);*/

    while (1) {
    research:
	/* search the directory item, containing entry with specified key */
	search_res = search_by_entry_key (inode->i_sb, &pos_key, &path_to_entry, &de);
	if (search_res == IO_ERROR) {
	    // FIXME: we could just skip part of directory which could
	    // not be read
	    return -EIO;
	}
	entry_num = de.de_entry_num;
	bh = de.de_bh;
	item_num = de.de_item_num;
	ih = de.de_ih;
	store_ih (&tmp_ih, ih);
		
	/* we must have found item, that is item of this directory, */
	RFALSE( COMP_SHORT_KEYS (&(ih->ih_key), &pos_key),
		"vs-9000: found item %h does not match to dir we readdir %K",
		ih, &pos_key);
	RFALSE( item_num > B_NR_ITEMS (bh) - 1,
		"vs-9005 item_num == %d, item amount == %d", 
		item_num, B_NR_ITEMS (bh));
      
	/* and entry must be not more than number of entries in the item */
	RFALSE( I_ENTRY_COUNT (ih) < entry_num,
		"vs-9010: entry number is too big %d (%d)", 
		entry_num, I_ENTRY_COUNT (ih));

	if (search_res == POSITION_FOUND || entry_num < I_ENTRY_COUNT (ih)) {
	    /* go through all entries in the directory item beginning from the entry, that has been found */
	    struct reiserfs_de_head * deh = B_I_DEH (bh, ih) + entry_num;

	    for (; entry_num < I_ENTRY_COUNT (ih); entry_num ++, deh ++) {
		int d_reclen;
		char * d_name;
		off_t d_off;
		ino_t d_ino;

		if (!de_visible (deh))
		    /* it is hidden entry */
		    continue;
		d_reclen = entry_length (bh, ih, entry_num);
		d_name = B_I_DEH_ENTRY_FILE_NAME (bh, ih, deh);
		if (!d_name[d_reclen - 1])
		    d_reclen = strlen (d_name);
	
		if (d_reclen > REISERFS_MAX_NAME_LEN(inode->i_sb->s_blocksize)){
		    /* too big to send back to VFS */
		    continue ;
		}
		d_off = deh_offset (deh);
		filp->f_pos = d_off ;
		d_ino = deh_objectid (deh);
		if (d_reclen <= 32) {
		  local_buf = small_buf ;
		} else {
		    local_buf = reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb) ;
		    if (!local_buf) {
			pathrelse (&path_to_entry);
			return -ENOMEM ;
		    }
		    if (item_moved (&tmp_ih, &path_to_entry)) {
			reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
			goto research;
		    }
		}
		// Note, that we copy name to user space via temporary
		// buffer (local_buf) because filldir will block if
		// user space buffer is swapped out. At that time
		// entry can move to somewhere else
		memcpy (local_buf, d_name, d_reclen);
		if (filldir (dirent, local_buf, d_reclen, d_off, d_ino, 
		             DT_UNKNOWN) < 0) {
		    if (local_buf != small_buf) {
			reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
		    }
		    goto end;
		}
		if (local_buf != small_buf) {
		    reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
		}

		// next entry should be looked for with such offset
		next_pos = deh_offset (deh) + 1;

		if (item_moved (&tmp_ih, &path_to_entry)) {
		    goto research;
		}
	    } /* for */
	}

	if (item_num != B_NR_ITEMS (bh) - 1)
	    // end of directory has been reached
	    goto end;

	/* item we went through is last item of node. Using right
	   delimiting key check is it directory end */
	rkey = get_rkey (&path_to_entry, inode->i_sb);
	if (! comp_le_keys (rkey, &MIN_KEY)) {
	    /* set pos_key to key, that is the smallest and greater
	       that key of the last entry in the item */
	    set_cpu_key_k_offset (&pos_key, next_pos);
	    continue;
	}

	if ( COMP_SHORT_KEYS (rkey, &pos_key)) {
	    // end of directory has been reached
	    goto end;
	}
	
	/* directory continues in the right neighboring block */
	set_cpu_key_k_offset (&pos_key, le_key_k_offset (KEY_FORMAT_3_5, rkey));

    } /* while */


 end:
    // FIXME: ext2_readdir does not reset f_pos
    filp->f_pos = next_pos;
    pathrelse (&path_to_entry);
    reiserfs_check_path(&path_to_entry) ;
    UPDATE_ATIME(inode) ;
    return 0;
}
示例#6
0
int
reiserfs_readdir(struct vop_readdir_args  /* {
		struct vnode *a_vp;
		struct uio *a_uio;
		struct ucred *a_cred;
		int *a_eofflag;
		int *a_ncookies;
		u_long **a_cookies;
	} */*ap)
{
	int error = 0;
	struct dirent dstdp;
	struct uio *uio = ap->a_uio;

	off_t next_pos;
	struct buf *bp;
	struct item_head *ih;
	struct cpu_key pos_key;
	const struct key *rkey;
	struct reiserfs_node *ip;
	struct reiserfs_dir_entry de;
	INITIALIZE_PATH(path_to_entry);
	int entry_num, item_num, search_res;

	/* The NFS part */
	int ncookies = 0;
	u_long *cookies = NULL;

	/*
	 * Form key for search the next directory entry using f_pos field of
	 * file structure
	 */
	ip = VTOI(ap->a_vp);
	make_cpu_key(&pos_key,
	    ip, uio->uio_offset ? uio->uio_offset : DOT_OFFSET,
	    TYPE_DIRENTRY, 3);
	next_pos = cpu_key_k_offset(&pos_key);

	reiserfs_log(LOG_DEBUG, "listing entries for "
	    "(objectid=%d, dirid=%d)\n",
	    pos_key.on_disk_key.k_objectid, pos_key.on_disk_key.k_dir_id);
	reiserfs_log(LOG_DEBUG, "uio_offset = %jd, uio_resid = %d\n",
	    (intmax_t)uio->uio_offset, uio->uio_resid);

	if (ap->a_ncookies && ap->a_cookies) {
		cookies = (u_long *)malloc(
		    uio->uio_resid / 16 * sizeof(u_long),
		    M_REISERFSCOOKIES, M_WAITOK);
	}

	while (1) {
		//research:
		/*
		 * Search the directory item, containing entry with
		 * specified key
		 */
		reiserfs_log(LOG_DEBUG, "search directory to read\n");
		search_res = search_by_entry_key(ip->i_reiserfs, &pos_key,
		    &path_to_entry, &de);
		if (search_res == IO_ERROR) {
			error = EIO;
			goto out;
		}

		entry_num = de.de_entry_num;
		item_num  = de.de_item_num;
		bp = de.de_bp;
		ih = de.de_ih;

		if (search_res == POSITION_FOUND ||
		    entry_num < I_ENTRY_COUNT(ih)) {
			/*
			 * Go through all entries in the directory item
			 * beginning from the entry, that has been found.
			 */
			struct reiserfs_de_head *deh = B_I_DEH(bp, ih) +
			    entry_num;

			if (ap->a_ncookies == NULL) {
				cookies = NULL;
			} else {
				//ncookies = 
			}

			reiserfs_log(LOG_DEBUG,
			    "walking through directory entries\n");
			for (; entry_num < I_ENTRY_COUNT(ih);
			    entry_num++, deh++) {
				int d_namlen;
				char *d_name;
				off_t d_off;
				ino_t d_ino;

				if (!de_visible(deh)) {
					/* It is hidden entry */
					continue;
				}

				d_namlen = entry_length(bp, ih, entry_num);
				d_name   = B_I_DEH_ENTRY_FILE_NAME(bp, ih, deh);
				if (!d_name[d_namlen - 1])
					d_namlen = strlen(d_name);
				reiserfs_log(LOG_DEBUG, "  - `%s' (len=%d)\n",
				    d_name, d_namlen);

				if (d_namlen > REISERFS_MAX_NAME(
				    ip->i_reiserfs->s_blocksize)) {
					/* Too big to send back to VFS */
					continue;
				}

#if 0
				/* Ignore the .reiserfs_priv entry */
				if (reiserfs_xattrs(ip->i_reiserfs) &&
				    !old_format_only(ip->i_reiserfs) &&
				    filp->f_dentry == ip->i_reiserfs->s_root &&
				    REISERFS_SB(ip->i_reiserfs)->priv_root &&
				    REISERFS_SB(ip->i_reiserfs)->priv_root->d_inode &&
				    deh_objectid(deh) ==
				    le32toh(INODE_PKEY(REISERFS_SB(
				    ip->i_reiserfs)->priv_root->d_inode)->k_objectid)) {
					continue;
				}
#endif

				d_off = deh_offset(deh);
				d_ino = deh_objectid(deh);
				uio->uio_offset = d_off;

				/* Copy to user land */
				dstdp.d_fileno = d_ino;
				dstdp.d_type   = DT_UNKNOWN;
				dstdp.d_namlen = d_namlen;
				dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp);
				bcopy(d_name, dstdp.d_name, dstdp.d_namlen);
				bzero(dstdp.d_name + dstdp.d_namlen,
				    dstdp.d_reclen -
				    offsetof(struct dirent, d_name) -
				    dstdp.d_namlen);

				if (d_namlen > 0) {
					if (dstdp.d_reclen <= uio->uio_resid) {
						reiserfs_log(LOG_DEBUG, "     copying to user land\n");
						error = uiomove(&dstdp,
						    dstdp.d_reclen, uio);
						if (error)
							goto end;
						if (cookies != NULL) {
							cookies[ncookies] =
							    d_off;
							ncookies++;
						}
					} else
						break;
				} else {
					error = EIO;
					break;
				}

				next_pos = deh_offset(deh) + 1;
			}
			reiserfs_log(LOG_DEBUG, "...done\n");
		}

		reiserfs_log(LOG_DEBUG, "checking item num (%d == %d ?)\n",
		    item_num, B_NR_ITEMS(bp) - 1);
		if (item_num != B_NR_ITEMS(bp) - 1) {
			/* End of directory has been reached */
			reiserfs_log(LOG_DEBUG, "end reached\n");
			if (ap->a_eofflag)
				*ap->a_eofflag = 1;
			goto end;
		}

		/*
		 * Item we went through is last item of node. Using right
		 * delimiting key check is it directory end
		 */
		reiserfs_log(LOG_DEBUG, "get right key\n");
		rkey = get_rkey(&path_to_entry, ip->i_reiserfs);
		reiserfs_log(LOG_DEBUG, "right key = (objectid=%d, dirid=%d)\n",
		    rkey->k_objectid, rkey->k_dir_id);

		reiserfs_log(LOG_DEBUG, "compare it to MIN_KEY\n");
		reiserfs_log(LOG_DEBUG, "MIN KEY = (objectid=%d, dirid=%d)\n",
		    MIN_KEY.k_objectid, MIN_KEY.k_dir_id);
		if (comp_le_keys(rkey, &MIN_KEY) == 0) {
			/* Set pos_key to key, that is the smallest and greater
			 * that key of the last entry in the item */
			reiserfs_log(LOG_DEBUG, "continuing on the right\n");
			set_cpu_key_k_offset(&pos_key, next_pos);
			continue;
		}

		reiserfs_log(LOG_DEBUG, "compare it to pos_key\n");
		reiserfs_log(LOG_DEBUG, "pos key = (objectid=%d, dirid=%d)\n",
		    pos_key.on_disk_key.k_objectid,
		    pos_key.on_disk_key.k_dir_id);
		if (COMP_SHORT_KEYS(rkey, &pos_key)) {
			/* End of directory has been reached */
			reiserfs_log(LOG_DEBUG, "end reached (right)\n");
			if (ap->a_eofflag)
				*ap->a_eofflag = 1;
			goto end;
		}

		/* Directory continues in the right neighboring block */
		reiserfs_log(LOG_DEBUG, "continuing with a new offset\n");
		set_cpu_key_k_offset(&pos_key,
		    le_key_k_offset(KEY_FORMAT_3_5, rkey));
		reiserfs_log(LOG_DEBUG,
		    "new pos key = (objectid=%d, dirid=%d)\n",
		    pos_key.on_disk_key.k_objectid,
		    pos_key.on_disk_key.k_dir_id);
	}

end:
	uio->uio_offset = next_pos;
	pathrelse(&path_to_entry);
	reiserfs_check_path(&path_to_entry);
out:
	if (error && cookies != NULL) {
		free(cookies, M_REISERFSCOOKIES);
	} else if (ap->a_ncookies != NULL && ap->a_cookies != NULL) {
		*ap->a_ncookies = ncookies;
		*ap->a_cookies  = cookies;
	}
	return (error);
}
示例#7
0
int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
			   filldir_t filldir, loff_t *pos)
{
	struct inode *inode = dentry->d_inode;
	struct cpu_key pos_key;	
	INITIALIZE_PATH(path_to_entry);
	struct buffer_head *bh;
	int item_num, entry_num;
	const struct reiserfs_key *rkey;
	struct item_head *ih, tmp_ih;
	int search_res;
	char *local_buf;
	loff_t next_pos;
	char small_buf[32];	
	struct reiserfs_dir_entry de;
	int ret = 0;

	reiserfs_write_lock(inode->i_sb);

	reiserfs_check_lock_depth(inode->i_sb, "readdir");

	make_cpu_key(&pos_key, inode, *pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3);
	next_pos = cpu_key_k_offset(&pos_key);

	path_to_entry.reada = PATH_READA;
	while (1) {
	      research:
		
		search_res =
		    search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry,
					&de);
		if (search_res == IO_ERROR) {
			
			
			ret = -EIO;
			goto out;
		}
		entry_num = de.de_entry_num;
		bh = de.de_bh;
		item_num = de.de_item_num;
		ih = de.de_ih;
		store_ih(&tmp_ih, ih);

		
		RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key),
		       "vs-9000: found item %h does not match to dir we readdir %K",
		       ih, &pos_key);
		RFALSE(item_num > B_NR_ITEMS(bh) - 1,
		       "vs-9005 item_num == %d, item amount == %d",
		       item_num, B_NR_ITEMS(bh));

		
		RFALSE(I_ENTRY_COUNT(ih) < entry_num,
		       "vs-9010: entry number is too big %d (%d)",
		       entry_num, I_ENTRY_COUNT(ih));

		if (search_res == POSITION_FOUND
		    || entry_num < I_ENTRY_COUNT(ih)) {
			
			struct reiserfs_de_head *deh =
			    B_I_DEH(bh, ih) + entry_num;

			for (; entry_num < I_ENTRY_COUNT(ih);
			     entry_num++, deh++) {
				int d_reclen;
				char *d_name;
				off_t d_off;
				ino_t d_ino;

				if (!de_visible(deh))
					
					continue;
				d_reclen = entry_length(bh, ih, entry_num);
				d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh);

				if (d_reclen <= 0 ||
				    d_name + d_reclen > bh->b_data + bh->b_size) {
					pathrelse(&path_to_entry);
					ret = -EIO;
					goto out;
				}

				if (!d_name[d_reclen - 1])
					d_reclen = strlen(d_name);

				if (d_reclen >
				    REISERFS_MAX_NAME(inode->i_sb->
						      s_blocksize)) {
					
					continue;
				}

				
				if (is_privroot_deh(dentry, deh))
					continue;

				d_off = deh_offset(deh);
				*pos = d_off;
				d_ino = deh_objectid(deh);
				if (d_reclen <= 32) {
					local_buf = small_buf;
				} else {
					local_buf = kmalloc(d_reclen,
							    GFP_NOFS);
					if (!local_buf) {
						pathrelse(&path_to_entry);
						ret = -ENOMEM;
						goto out;
					}
					if (item_moved(&tmp_ih, &path_to_entry)) {
						kfree(local_buf);
						goto research;
					}
				}
				
				
				
				
				memcpy(local_buf, d_name, d_reclen);

				reiserfs_write_unlock(inode->i_sb);
				if (filldir
				    (dirent, local_buf, d_reclen, d_off, d_ino,
				     DT_UNKNOWN) < 0) {
					reiserfs_write_lock(inode->i_sb);
					if (local_buf != small_buf) {
						kfree(local_buf);
					}
					goto end;
				}
				reiserfs_write_lock(inode->i_sb);
				if (local_buf != small_buf) {
					kfree(local_buf);
				}
				
				next_pos = deh_offset(deh) + 1;

				if (item_moved(&tmp_ih, &path_to_entry)) {
					goto research;
				}
			}	
		}

		if (item_num != B_NR_ITEMS(bh) - 1)
			
			goto end;

		rkey = get_rkey(&path_to_entry, inode->i_sb);
		if (!comp_le_keys(rkey, &MIN_KEY)) {
			set_cpu_key_k_offset(&pos_key, next_pos);
			continue;
		}

		if (COMP_SHORT_KEYS(rkey, &pos_key)) {
			
			goto end;
		}

		
		set_cpu_key_k_offset(&pos_key,
				     le_key_k_offset(KEY_FORMAT_3_5, rkey));

	}			

end:
	*pos = next_pos;
	pathrelse(&path_to_entry);
	reiserfs_check_path(&path_to_entry);
out:
	reiserfs_write_unlock(inode->i_sb);
	return ret;
}
示例#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;
}
示例#9
0
int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
			   filldir_t filldir, loff_t *pos)
{
	struct inode *inode = dentry->d_inode;
	struct cpu_key pos_key;	/* key of current position in the directory (key of directory entry) */
	INITIALIZE_PATH(path_to_entry);
	struct buffer_head *bh;
	int item_num, entry_num;
	const struct reiserfs_key *rkey;
	struct item_head *ih, tmp_ih;
	int search_res;
	char *local_buf;
	loff_t next_pos;
	char small_buf[32];	/* avoid kmalloc if we can */
	struct reiserfs_dir_entry de;
	int ret = 0;

	reiserfs_write_lock(inode->i_sb);

	reiserfs_check_lock_depth(inode->i_sb, "readdir");

	/* form key for search the next directory entry using f_pos field of
	   file structure */
	make_cpu_key(&pos_key, inode, *pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3);
	next_pos = cpu_key_k_offset(&pos_key);

	path_to_entry.reada = PATH_READA;
	while (1) {
	      research:
		/* search the directory item, containing entry with specified key */
		search_res =
		    search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry,
					&de);
		if (search_res == IO_ERROR) {
			// FIXME: we could just skip part of directory which could
			// not be read
			ret = -EIO;
			goto out;
		}
		entry_num = de.de_entry_num;
		bh = de.de_bh;
		item_num = de.de_item_num;
		ih = de.de_ih;
		store_ih(&tmp_ih, ih);

		/* we must have found item, that is item of this directory, */
		RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key),
		       "vs-9000: found item %h does not match to dir we readdir %K",
		       ih, &pos_key);
		RFALSE(item_num > B_NR_ITEMS(bh) - 1,
		       "vs-9005 item_num == %d, item amount == %d",
		       item_num, B_NR_ITEMS(bh));

		/* and entry must be not more than number of entries in the item */
		RFALSE(I_ENTRY_COUNT(ih) < entry_num,
		       "vs-9010: entry number is too big %d (%d)",
		       entry_num, I_ENTRY_COUNT(ih));

		if (search_res == POSITION_FOUND
		    || entry_num < I_ENTRY_COUNT(ih)) {
			/* go through all entries in the directory item beginning from the entry, that has been found */
			struct reiserfs_de_head *deh =
			    B_I_DEH(bh, ih) + entry_num;

			for (; entry_num < I_ENTRY_COUNT(ih);
			     entry_num++, deh++) {
				int d_reclen;
				char *d_name;
				off_t d_off;
				ino_t d_ino;
				loff_t cur_pos = deh_offset(deh);

				if (!de_visible(deh))
					/* it is hidden entry */
					continue;
				d_reclen = entry_length(bh, ih, entry_num);
				d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh);

				if (d_reclen <= 0 ||
				    d_name + d_reclen > bh->b_data + bh->b_size) {
					/* There is corrupted data in entry,
					 * We'd better stop here */
					pathrelse(&path_to_entry);
					ret = -EIO;
					goto out;
				}

				if (!d_name[d_reclen - 1])
					d_reclen = strlen(d_name);

				if (d_reclen >
				    REISERFS_MAX_NAME(inode->i_sb->
						      s_blocksize)) {
					/* too big to send back to VFS */
					continue;
				}

				/* Ignore the .reiserfs_priv entry */
				if (is_privroot_deh(dentry, deh))
					continue;

				d_off = deh_offset(deh);
				*pos = d_off;
				d_ino = deh_objectid(deh);
				if (d_reclen <= 32) {
					local_buf = small_buf;
				} else {
					local_buf = kmalloc(d_reclen,
							    GFP_NOFS);
					if (!local_buf) {
						pathrelse(&path_to_entry);
						ret = -ENOMEM;
						goto out;
					}
					if (item_moved(&tmp_ih, &path_to_entry)) {
						kfree(local_buf);
						goto research;
					}
				}
				// Note, that we copy name to user space via temporary
				// buffer (local_buf) because filldir will block if
				// user space buffer is swapped out. At that time
				// entry can move to somewhere else
				memcpy(local_buf, d_name, d_reclen);

				/*
				 * Since filldir might sleep, we can release
				 * the write lock here for other waiters
				 */
				reiserfs_write_unlock(inode->i_sb);
				if (filldir
				    (dirent, local_buf, d_reclen, d_off, d_ino,
				     DT_UNKNOWN) < 0) {
					reiserfs_write_lock(inode->i_sb);
					if (local_buf != small_buf) {
						kfree(local_buf);
					}
					goto end;
				}
				reiserfs_write_lock(inode->i_sb);
				if (local_buf != small_buf) {
					kfree(local_buf);
				}

				/* deh_offset(deh) may be invalid now. */
				next_pos = cur_pos + 1;

				if (item_moved(&tmp_ih, &path_to_entry)) {
					set_cpu_key_k_offset(&pos_key,
							     next_pos);
					goto research;
				}
			}	/* for */
		}

		if (item_num != B_NR_ITEMS(bh) - 1)
			// end of directory has been reached
			goto end;

		/* item we went through is last item of node. Using right
		   delimiting key check is it directory end */
		rkey = get_rkey(&path_to_entry, inode->i_sb);
		if (!comp_le_keys(rkey, &MIN_KEY)) {
			/* set pos_key to key, that is the smallest and greater
			   that key of the last entry in the item */
			set_cpu_key_k_offset(&pos_key, next_pos);
			continue;
		}

		if (COMP_SHORT_KEYS(rkey, &pos_key)) {
			// end of directory has been reached
			goto end;
		}

		/* directory continues in the right neighboring block */
		set_cpu_key_k_offset(&pos_key,
				     le_key_k_offset(KEY_FORMAT_3_5, rkey));

	}			/* while */

end:
	*pos = next_pos;
	pathrelse(&path_to_entry);
	reiserfs_check_path(&path_to_entry);
out:
	reiserfs_write_unlock(inode->i_sb);
	return ret;
}