Beispiel #1
0
static int
ufs_readlink(struct inode * inode, char * buffer, int buflen)
{
	unsigned long int block;
	struct buffer_head * bh = NULL;
	char * link;
	int i;
	char c;

	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
	        printk("ufs_readlink: called on ino %lu dev %u/%u\n",
	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
	}

	if (!S_ISLNK(inode->i_mode)) {
		iput (inode);
		return -EINVAL;
	}
	if (buflen > inode->i_sb->s_blocksize - 1)
		buflen = inode->i_sb->s_blocksize - 1;
	if (inode->i_blocks) {
	        /* XXX - error checking */
	        block = ufs_bmap(inode, 0);
	        if (inode->i_sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) {
	                printk("ufs_readlink: bmap got %lu for ino %lu\n",
	                       block, inode->i_ino);
		} 
	        bh = bread(inode->i_dev, block, BLOCK_SIZE);
		if (!bh) {
			iput (inode);
	                printk("ufs_readlink: can't read block 0 for ino %lu on dev %u/%u\n",
	                       inode->i_ino, MAJOR(inode->i_dev),
	                       MINOR(inode->i_dev));
			return 0;
		}
		link = bh->b_data;
	}
	else {
	        link = (char *)&(inode->u.ufs_i.ui_db[0]);
	}
	i = 0;
	while (i < buflen && (c = link[i])) {
		i++;
		put_user (c, buffer++);
	}
	iput (inode);
	if (bh)
		brelse (bh);
	return i;
}
Beispiel #2
0
/*
 * XXX - blatantly stolen from ext2fs
 */
static int
ufs_follow_link(struct inode * dir, struct inode * inode,
	        int flag, int mode, struct inode ** res_inode)
{
	unsigned long int block;
	int error;
	struct buffer_head * bh;
	char * link;

	bh = NULL;

	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
	        printk("ufs_follow_link: called on ino %lu dev %u/%u\n",
	               dir->i_ino, MAJOR(dir->i_dev), MINOR(dir->i_dev));
	}

	*res_inode = NULL;
	if (!dir) {
	        dir = current->fs->root;
	        dir->i_count++;
	}
	if (!inode) {
		iput (dir);
		return -ENOENT;
	}
	if (!S_ISLNK(inode->i_mode)) {
		iput (dir);
		*res_inode = inode;
		return 0;
	}
	if (current->link_count > 5) {
		iput (dir);
		iput (inode);
		return -ELOOP;
	}
	if (inode->i_blocks) {
	        /* read the link from disk */
	        /* XXX - error checking */
	        block = ufs_bmap(inode, 0);
	        bh = bread(inode->i_dev, block, BLOCK_SIZE);
	        if (bh == NULL) {
	                printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n",
	                       inode->i_ino, MAJOR(inode->i_dev),
	                       MINOR(inode->i_dev));
	                iput(dir);
	                iput(inode);
	                return(-EIO);
	        }
	        link = bh->b_data;
	} else {
	        /* fast symlink */
	        link = (char *)&(inode->u.ufs_i.ui_db[0]);
	}
	current->link_count++;
	error = open_namei (link, flag, mode, res_inode, dir);
	current->link_count--;
	iput (inode);
	if (bh) {
		brelse (bh);
	}
	return(error);
}
Beispiel #3
0
/* XXX - this is a mess, especially for endianity */
int ufs_lookup (struct inode * dir, const char * name, int len,
	        struct inode ** result)
{
	unsigned long int lfragno, fragno;
	struct buffer_head * bh;
	struct ufs_direct * d;

	/*
	 * Touching /xyzzy in a filesystem toggles debugging messages.
	 */
	if ((len == 5) && !(memcmp(name, "xyzzy", len)) &&
	    (dir->i_ino == UFS_ROOTINO)) {
	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG;
	        printk("UFS debugging %s\n",
	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) ?
	               "on": "off");
	        return(-ENOENT);
	}

	/*
	 * Touching /xyzzy.i in a filesystem toggles debugging for ufs_inode.c.
	 */
	if ((len == 7) && !(memcmp(name, "xyzzy.i", len)) &&
	    (dir->i_ino == UFS_ROOTINO)) {
	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_INODE;
	        printk("UFS inode debugging %s\n",
	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ?
	               "on": "off");
	        return(-ENOENT);
	}

	if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) &&
	    (dir->i_ino == UFS_ROOTINO)) {
	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI;
	        printk("UFS namei debugging %s\n",
	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ?
	               "on": "off");
	        return(-ENOENT);
	}

	if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) &&
	    (dir->i_ino == UFS_ROOTINO)) {
	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS;
	        printk("UFS symlink debugging %s\n",
	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ?
	               "on": "off");
	        return(-ENOENT);
	}

	if (dir->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) {
	        printk("ufs_lookup: called for ino %lu  name %s\n",
	               dir->i_ino, name);
	}

	/* XXX - do I want i_blocks in 512-blocks or 1024-blocks? */
	for (lfragno = 0; lfragno < (dir->i_blocks)>>1; lfragno++) {
	        fragno = ufs_bmap(dir, lfragno);
	        /* XXX - ufs_bmap() call needs error checking */
	        /* XXX - s_blocksize is actually the UFS frag size */
	        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
	                printk("ufs_lookup: ino %lu lfragno %lu  fragno %lu\n",
	                       dir->i_ino, lfragno, fragno);
	        }
	        if (fragno == 0) {
	                /* XXX - bug bug bug */
	                return(-ENOENT);
	        }
	        bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize);
	        if (bh == NULL) {
	                printk("ufs_lookup: bread failed: ino %lu, lfragno %lu",
	                       dir->i_ino, lfragno);
	                return(-EIO);
	        }
	        d = (struct ufs_direct *)(bh->b_data);
	        while (((char *)d - bh->b_data + d->d_reclen) <=
	               dir->i_sb->s_blocksize) {
	                /* XXX - skip block if d_reclen or d_namlen is 0 */
	                if ((d->d_reclen == 0) || (d->d_namlen == 0)) {
	                        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
	                                printk("ufs_lookup: skipped space in directory, ino %lu\n",
	                                       dir->i_ino);
	                        }
	                        break;
	                }
	                if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
	                        printk("lfragno 0x%lx  direct d 0x%x  d_ino %u  d_reclen %u  d_namlen %u  d_name `%s'\n",
	                               lfragno, (unsigned int)d, d->d_ino, d->d_reclen, d->d_namlen, d->d_name);
	                }
	                if ((d->d_namlen == len) &&
	                    /* XXX - don't use strncmp() - see ext2fs */
	                    (ufs_match(len, name, d))) {
	                        /* We have a match */
	                        *result = iget(dir->i_sb, d->d_ino);
	                        brelse(bh);
	                        return(0);
	                } else {
	                        /* XXX - bounds checking */
	                        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
	                                printk("ufs_lookup: wanted (%s,%d) got (%s,%d)\n",
	                                       name, len, d->d_name, d->d_namlen);
	                        }
	                }
	                d = (struct ufs_direct *)((char *)d + d->d_reclen);
	        }
	        brelse(bh);
	}
	return(-ENOENT);
}
Beispiel #4
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;
}
Beispiel #5
0
int ufs_dir_iterate(uufsd_t *ufs, ino_t dirino,
		    int (*func)(
					  struct direct *dirent,
					  int n,
					  char *buf,
					  void	*priv_data),
			      void *priv_data)
{
	int i, ret = 0;
	ufs2_daddr_t ndb;
	ufs2_daddr_t blkno;
	int blksize = ufs->d_fs.fs_bsize;
	u_int64_t dir_size;
	char *dirbuf = NULL;
	struct ufs_vnode *vnode;

	vnode = vnode_get(ufs, dirino);
	if (vnode == NULL) {
		ret = -ENOMEM;
		goto out;
	}
	dir_size = vnode2inode(vnode)->i_size;

	dirbuf = malloc(blksize);
	if (!dirbuf) {
		ret = -ENOMEM;
		goto out;
	}

	ndb = howmany(dir_size, ufs->d_fs.fs_bsize);
	int offset, pos = 0;
	for (i = 0; i < ndb ; i++) {
		ret = ufs_bmap(ufs, vnode, i, &blkno);
		if (ret) {
			ret = -EIO;
			goto out;
		}
		blksize = ufs_inode_io_size(vnode2inode(vnode), pos, 0);
		if (blkread(ufs, fsbtodb(&ufs->d_fs, blkno), dirbuf, blksize) == -1) {
			debugf("Unable to read block %d\n",blkno);
			ret = -EIO;
			goto out;
		}
		offset = 0;
		while (offset < blksize && pos + offset < dir_size) {
			struct direct *de = (struct direct *)(dirbuf + offset);

			/* HACK: Restrict frame for func() operations
			 *       to blocks of DIRBLKSIZ bytes
			 */
			int    blockoff = offset % DIRBLKSIZ;
			char * dirblock = dirbuf + (offset-blockoff);

			ret = (*func)(de, blockoff, dirblock, priv_data);
			if (ret & DIRENT_CHANGED) {
				if (blkwrite(ufs, fsbtodb(&ufs->d_fs, blkno), dirbuf, blksize) == -1) {
					debugf("Unable to write block %d\n",blkno);
					ret = -EIO;
					goto out;
				}
			}
			if (ret & DIRENT_ABORT) {
				ret = 0;
				goto out;
			}
			offset += de->d_reclen;
		}
		pos += blksize;
	}

out:
	if (vnode) {
		vnode_put(vnode, 0);
	}
	if (dirbuf) {
		free(dirbuf);
	}
	return ret;
}
Beispiel #6
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;
}