Example #1
0
void ufs_put_inode (struct inode * inode)
{
	if (inode->i_nlink)
	        return;

	printk("ufs_put_inode: nlink == 0 for inum %lu on dev %d/%d\n",
	       inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
	ufs_print_inode(inode);
	panic("ufs_put_inode: fs is read only, and nlink == 0");

	/* XXX - this code goes here eventually
	inode->i_size = 0;
	if (inode->i_blocks)
	        ufs_truncate(inode);
	ufs_free_inode(inode);
	*/

	return;
}
Example #2
0
/* XXX - ufs_read_inode is a mess */
void ufs_read_inode(struct inode * inode)
{
	struct super_block * sb;
	struct ufs_inode * ufsip;
	struct buffer_head * bh;

	sb = inode->i_sb;

	if (ufs_ino_ok(inode)) {
	        printk("ufs_read_inode: bad inum %lu", inode->i_ino);

	        return;
	}

#if 0
	printk("ufs_read_inode: ino %lu  cg %u  cgino %u  ipg %u  inopb %u\n",
	       inode->i_ino, ufs_ino2cg(inode),
	       (inode->i_ino%sb->u.ufs_sb.s_inopb),
	       sb->u.ufs_sb.s_ipg, sb->u.ufs_sb.s_inopb);
#endif
	bh = bread(inode->i_dev,
	           ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
	           (inode->i_ino%sb->u.ufs_sb.s_ipg)/(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag),
	           BLOCK_SIZE);
	if (!bh) {
	        printk("ufs_read_inode: can't read inode %lu from dev %d/%d",
	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
	        return;
	}

	ufsip = (struct ufs_inode *)bh->b_data;
	ufsip += (inode->i_ino%(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag));

	/*
	 * Copy data to the in-core inode.
	 */
	inode->i_mode = ufsip->ui_mode;
	inode->i_nlink = ufsip->ui_nlink;
	if (inode->i_nlink == 0) {
	        /* XXX */
	        printk("ufs_read_inode: zero nlink ino %lu  dev %u/%u\n",
	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
	        inode->i_nlink = 1;
	        printk("ufs_read_inode: fishy ino %lu pblk %lu dev %u/%u\n",
	               inode->i_ino,
	               ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
	               (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb,
	               MAJOR(inode->i_dev), MINOR(inode->i_dev));
	}
	/* XXX - debugging */
	if (ufsip->ui_gen == 0) {
	        printk("ufs_read_inode: zero gen ino %lu pblk %lu dev %u/%u\n",
	               inode->i_ino,
	               ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
	               (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb,
	               MAJOR(inode->i_dev), MINOR(inode->i_dev));
	}
	/*
	 * Since Linux currently only has 16-bit uid_t and gid_t, we can't
	 * really support EFTs.  For the moment, we use 0 as the uid and gid
	 * if an inode has a uid or gid that won't fit in 16 bits.  This way
	 * random users can't get at these files, since they get dynamically
	 * "chown()ed" to root.
	 */
	if (ufsip->ui_suid == UFS_USEEFT) {
	        /* EFT */
	        inode->i_uid = 0;
	        printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n",
	               ufsip->ui_uid, inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
	               inode->i_uid);
	} else {
	        inode->i_uid = ufsip->ui_suid;
	}
	if (ufsip->ui_suid == UFS_USEEFT) {
	        /* EFT */
	        inode->i_uid = 0;
	        printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n",
	               ufsip->ui_gid, inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
	               inode->i_gid);
	} else {
	        inode->i_gid = ufsip->ui_sgid;
	}

	/*
	 * Linux i_size is 32 bits, so some files on a UFS filesystem may not
	 * be readable.  I let people access the first 32 bits worth of them.
	 * for the rw code, we may want to mark these inodes as read-only.
	 * XXX - bug Linus to make i_size a __u64 instead of a __u32.
	 */
	inode->u.ufs_i.ui_size = ((__u64)(ufsip->ui_size.val[0])<<32) | (__u64)(ufsip->ui_size.val[1]);
	inode->i_size = ufsip->ui_size.val[1]; /* XXX - endianity */
	if (ufsip->ui_size.val[0] != 0) {
	        inode->i_size = 0xffffffff;
	        printk("ufs_read_inode: file too big ino %lu dev %u/%u, faking size\n",
	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
	}
	/*
	 * Linux doesn't keep tv_usec around in the kernel, so we discard it.
	 * XXX - I'm not sure what I should do about writing things.  I may
	 * want to keep this data, but for the moment I think I'll just write
	 * zeros for these fields when writing out inodes.
	 */
	inode->i_atime = ufsip->ui_atime.tv_sec;
	inode->i_mtime = ufsip->ui_mtime.tv_sec;
	inode->i_ctime = ufsip->ui_ctime.tv_sec;
	inode->i_blksize = sb->u.ufs_sb.s_fsize;
	inode->i_blocks = ufsip->ui_blocks;
	inode->i_version = ++event; /* see linux/kernel/sched.c */

	if (S_ISREG(inode->i_mode)) {
	        inode->i_op = &ufs_file_inode_operations;
	} else if (S_ISDIR(inode->i_mode)) {
	        inode->i_op = &ufs_dir_inode_operations;
	} else if (S_ISLNK(inode->i_mode)) {
	        inode->i_op = &ufs_symlink_inode_operations;
	} else if (S_ISCHR(inode->i_mode)) {
	        inode->i_op = &chrdev_inode_operations;
	} else if (S_ISBLK(inode->i_mode)) {
	        inode->i_op = &blkdev_inode_operations;
	} else if (S_ISFIFO(inode->i_mode)) {
	        init_fifo(inode);
	} else {
	        printk("ufs_read_inode: unknown file type 0%o ino %lu dev %d/%d\n",
	               inode->i_mode, inode->i_ino, MAJOR(inode->i_dev),
	               MINOR(inode->i_dev));
	        /* XXX - debugging */
	        ufs_print_inode(inode);
	        inode->i_op = &ufs_file_inode_operations;
	}

	/*
	 * ufs_read_super makes sure that UFS_NDADDR and UFS_NINDIR are sane.
	 */
	if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
	    S_ISLNK(inode->i_mode)) {
	        int i;

	        for (i = 0; i < UFS_NDADDR; i++) {
	                inode->u.ufs_i.ui_db[i] = ufsip->ui_db[i];
	        }
	        for (i = 0; i < UFS_NINDIR; i++) {
	                inode->u.ufs_i.ui_ib[i] = ufsip->ui_ib[i];
	        }
	}

	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
	        /* XXX - should be ui_db[1] on little endian ufs filesystems */
	        inode->i_rdev = to_kdev_t(ufsip->ui_db[0]);
	}

	/* XXX - implement fast and slow symlinks */

	inode->u.ufs_i.ui_flags = ufsip->ui_flags;
	inode->u.ufs_i.ui_gen = ufsip->ui_gen; /* XXX - is this i_version? */
	inode->u.ufs_i.ui_shadow = ufsip->ui_shadow; /* XXX */
	inode->u.ufs_i.ui_uid = ufsip->ui_uid;
	inode->u.ufs_i.ui_gid = ufsip->ui_gid;
	inode->u.ufs_i.ui_oeftflag = ufsip->ui_oeftflag;

	brelse(bh);

	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_INODE)) {
	        ufs_print_inode(inode);
	}

	return;
}
Example #3
0
/*
 * This is blatantly stolen from ext2fs
 */
static int
ufs_readdir (struct inode * inode, struct file * filp, void * dirent,
	     filldir_t filldir)
{
	int error = 0;
	unsigned long offset, lblk, blk;
	int i, stored;
	struct buffer_head * bh;
	struct ufs_direct * de;
	struct super_block * sb;

	if (!inode || !S_ISDIR(inode->i_mode))
		return -EBADF;
	sb = inode->i_sb;

	if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
	        printk("ufs_readdir: ino %lu  f_pos %lu\n",
	               inode->i_ino, (unsigned long) filp->f_pos);
	        ufs_print_inode(inode);
	}

	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;
	        blk = ufs_bmap(inode, lblk);
	        /* 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_direct *) 
					(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. */
				if (de->d_reclen < 1)
					break;
				i += de->d_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_direct *) (bh->b_data + offset);
	                /* XXX - put in a real ufs_check_dir_entry() */
	                if ((de->d_reclen == 0) || (de->d_namlen == 0)) {
	                        filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize;
	                        brelse(bh);
	                        return stored;
	                }
#if 0
			if (!ext2_check_dir_entry ("ext2_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;
			}
#endif /* XXX */
			offset += de->d_reclen;
			if (de->d_ino) {
				/* 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;
				dcache_add(inode, de->d_name, de->d_namlen,
	                                   de->d_ino);
				version = inode->i_version;
	                        if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
	                                printk("ufs_readdir: filldir(%s,%u)\n",
	                                       de->d_name, de->d_ino);
	                        }
				error = filldir(dirent, de->d_name, de->d_namlen, filp->f_pos, de->d_ino);
				if (error)
					break;
				if (version != inode->i_version)
					goto revalidate;
				stored ++;
			}
			filp->f_pos += de->d_reclen;
		}
		offset = 0;
		brelse (bh);
	}
#if 0 /* XXX */
	if (!IS_RDONLY(inode)) {
		inode->i_atime = CURRENT_TIME;
		inode->i_dirt = 1;
	}
#endif /* XXX */
	return 0;
}