Exemplo n.º 1
0
int ufs_check_dir_entry (const char * function,	struct inode * dir,
	struct ufs_dir_entry * de, struct buffer_head * bh, 
	unsigned long offset)
{
	struct super_block * sb;
	const char * error_msg;
	unsigned flags, swab;
	
	sb = dir->i_sb;
	flags = sb->u.ufs_sb.s_flags;
	swab = sb->u.ufs_sb.s_swab;
	error_msg = NULL;
			
	if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(1))
		error_msg = "reclen is smaller than minimal";
	else if (SWAB16(de->d_reclen) % 4 != 0)
		error_msg = "reclen % 4 != 0";
	else if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(ufs_get_de_namlen(de)))
		error_msg = "reclen is too small for namlen";
	else if (dir && ((char *) de - bh->b_data) + SWAB16(de->d_reclen) >
		 dir->i_sb->s_blocksize)
		error_msg = "directory entry across blocks";
	else if (dir && SWAB32(de->d_ino) > (sb->u.ufs_sb.s_uspi->s_ipg * sb->u.ufs_sb.s_uspi->s_ncg))
		error_msg = "inode out of bounds";

	if (error_msg != NULL)
		ufs_error (sb, function, "bad entry in directory #%lu, size %lu: %s - "
			    "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
			    dir->i_ino, dir->i_size, error_msg, offset,
			    (unsigned long) SWAB32(de->d_ino),
			    SWAB16(de->d_reclen), ufs_get_de_namlen(de));
	
	return (error_msg == NULL ? 1 : 0);
}
Exemplo n.º 2
0
unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment,
	unsigned goal, unsigned count, int * err )
{
	struct super_block * sb;
	struct ufs_sb_private_info * uspi;
	struct ufs_super_block_first * usb1;
	struct buffer_head * bh;
	unsigned cgno, oldcount, newcount, tmp, request, i, result;
	unsigned swab;
	
	UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count))
	
	sb = inode->i_sb;
	swab = sb->u.ufs_sb.s_swab;
	uspi = sb->u.ufs_sb.s_uspi;
	usb1 = ubh_get_usb_first(USPI_UBH);
	*err = -ENOSPC;

	lock_super (sb);
	
	tmp = SWAB32(*p);
	if (count + ufs_fragnum(fragment) > uspi->s_fpb) {
		ufs_warning (sb, "ufs_new_fragments", "internal warning"
			" fragment %u, count %u", fragment, count);
		count = uspi->s_fpb - ufs_fragnum(fragment); 
	}
	oldcount = ufs_fragnum (fragment);
	newcount = oldcount + count;

	/*
	 * Somebody else has just allocated our fragments
	 */
	if (oldcount) {
		if (!tmp) {
			ufs_error (sb, "ufs_new_fragments", "internal error, "
				"fragment %u, tmp %u\n", fragment, tmp);
			return (unsigned)-1;
		}
		if (fragment < inode->u.ufs_i.i_lastfrag) {
			UFSD(("EXIT (ALREADY ALLOCATED)\n"))
			unlock_super (sb);
			return 0;
		}
	}
	else {
		if (tmp) {
			UFSD(("EXIT (ALREADY ALLOCATED)\n"))
			unlock_super(sb);
			return 0;
		}
	}
	
	/*
	 * There is not enough space for user on the device
	 */
	if (!fsuser() && ufs_freespace(usb1, UFS_MINFREE) <= 0) {
		unlock_super (sb);
		UFSD(("EXIT (FAILED)\n"))
		return 0;
	} 
Exemplo n.º 3
0
/*
 * This is blatantly stolen from ext2fs
 */
static int
ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
{
	struct inode *inode = filp->f_dentry->d_inode;
	int error = 0;
	unsigned long offset, lblk, blk;
	int i, stored;
	struct buffer_head * bh;
	struct ufs_dir_entry * de;
	struct super_block * sb;
	int de_reclen;
	unsigned flags, swab;

	sb = inode->i_sb;
	swab = sb->u.ufs_sb.s_swab;
	flags = sb->u.ufs_sb.s_flags;

	UFSD(("ENTER, ino %lu  f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))

	stored = 0;
	bh = NULL;
	offset = filp->f_pos & (sb->s_blocksize - 1);

	while (!error && !stored && filp->f_pos < inode->i_size) {
		lblk = (filp->f_pos) >> sb->s_blocksize_bits;
		/* XXX - ufs_bmap() call needs error checking */
		blk = ufs_bmap(inode, lblk);
		bh = bread (sb->s_dev, blk, sb->s_blocksize);
		if (!bh) {
			/* XXX - error - skip to the next block */
			printk("ufs_readdir: "
			       "dir inode %lu has a hole at offset %lu\n",
			       inode->i_ino, (unsigned long int)filp->f_pos);
			filp->f_pos += sb->s_blocksize - offset;
			continue;
		}

revalidate:
		/* If the dir block has changed since the last call to
		 * readdir(2), then we might be pointing to an invalid
		 * dirent right now.  Scan from the start of the block
		 * to make sure. */
		if (filp->f_version != inode->i_version) {
			for (i = 0; i < sb->s_blocksize && i < offset; ) {
				de = (struct ufs_dir_entry *)(bh->b_data + i);
				/* It's too expensive to do a full
				 * dirent test each time round this
				 * loop, but we do have to test at
				 * least that it is non-zero.  A
				 * failure will be detected in the
				 * dirent test below. */
				de_reclen = SWAB16(de->d_reclen);
				if (de_reclen < 1)
					break;
				i += de_reclen;
			}
			offset = i;
			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
				| offset;
			filp->f_version = inode->i_version;
		}

		while (!error && filp->f_pos < inode->i_size
		       && offset < sb->s_blocksize) {
			de = (struct ufs_dir_entry *) (bh->b_data + offset);
			/* XXX - put in a real ufs_check_dir_entry() */
			if ((de->d_reclen == 0) || (ufs_get_de_namlen(de) == 0)) {
			/* SWAB16() was unneeded -- compare to 0 */
				filp->f_pos = (filp->f_pos &
				              (sb->s_blocksize - 1)) +
				               sb->s_blocksize;
				brelse(bh);
				return stored;
			}
			if (!ufs_check_dir_entry ("ufs_readdir", inode, de,
						   bh, offset)) {
				/* On error, skip the f_pos to the
				   next block. */
				filp->f_pos = (filp->f_pos &
				              (sb->s_blocksize - 1)) +
					       sb->s_blocksize;
				brelse (bh);
				return stored;
			}
			offset += SWAB16(de->d_reclen);
			if (de->d_ino) {
			/* SWAB16() was unneeded -- compare to 0 */
				/* We might block in the next section
				 * if the data destination is
				 * currently swapped out.  So, use a
				 * version stamp to detect whether or
				 * not the directory has been modified
				 * during the copy operation. */
				unsigned long version = inode->i_version;

				UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino)))
				UFSD(("namlen %u\n", ufs_get_de_namlen(de)))
				error = filldir(dirent, de->d_name, ufs_get_de_namlen(de),
						filp->f_pos, SWAB32(de->d_ino));
				if (error)
					break;
				if (version != inode->i_version)
					goto revalidate;
				stored ++;
			}
			filp->f_pos += SWAB16(de->d_reclen);
		}
		offset = 0;
		brelse (bh);
	}
	UPDATE_ATIME(inode);
	return 0;
}