Beispiel #1
0
static int
befs_readdir(struct file *file, struct dir_context *ctx)
{
	struct inode *inode = file_inode(file);
	struct super_block *sb = inode->i_sb;
	befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
	befs_off_t value;
	int result;
	size_t keysize;
	unsigned char d_type;
	char keybuf[BEFS_NAME_LEN + 1];

	befs_debug(sb, "---> %s name %pD, inode %ld, ctx->pos %lld",
		  __func__, file, inode->i_ino, ctx->pos);

more:
	result = befs_btree_read(sb, ds, ctx->pos, BEFS_NAME_LEN + 1,
				 keybuf, &keysize, &value);

	if (result == BEFS_ERR) {
		befs_debug(sb, "<--- %s ERROR", __func__);
		befs_error(sb, "IO error reading %pD (inode %lu)",
			   file, inode->i_ino);
		return -EIO;

	} else if (result == BEFS_BT_END) {
		befs_debug(sb, "<--- %s END", __func__);
		return 0;

	} else if (result == BEFS_BT_EMPTY) {
		befs_debug(sb, "<--- %s Empty directory", __func__);
		return 0;
	}

	d_type = DT_UNKNOWN;

	/* Convert to NLS */
	if (BEFS_SB(sb)->nls) {
		char *nlsname;
		int nlsnamelen;
		result =
		    befs_utf2nls(sb, keybuf, keysize, &nlsname, &nlsnamelen);
		if (result < 0) {
			befs_debug(sb, "<--- %s ERROR", __func__);
			return result;
		}
		if (!dir_emit(ctx, nlsname, nlsnamelen,
				 (ino_t) value, d_type)) {
			kfree(nlsname);
			return 0;
		}
		kfree(nlsname);
	} else {
		if (!dir_emit(ctx, keybuf, keysize,
				 (ino_t) value, d_type))
			return 0;
	}
	ctx->pos++;
	goto more;
}
Beispiel #2
0
/*
 * Get root directory contents.
 */
static int
zpl_root_iterate(struct file *filp, struct dir_context *ctx)
{
	zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode);
	int error = 0;

	ZFS_ENTER(zsb);

	if (!dir_emit_dots(filp, ctx))
		goto out;

	if (ctx->pos == 2) {
		if (!dir_emit(ctx, ZFS_SNAPDIR_NAME, strlen(ZFS_SNAPDIR_NAME),
		    ZFSCTL_INO_SNAPDIR, DT_DIR))
			goto out;

		ctx->pos++;
	}

	if (ctx->pos == 3) {
		if (!dir_emit(ctx, ZFS_SHAREDIR_NAME, strlen(ZFS_SHAREDIR_NAME),
		    ZFSCTL_INO_SHARES, DT_DIR))
			goto out;

		ctx->pos++;
	}
out:
	ZFS_EXIT(zsb);

	return (error);
}
Beispiel #3
0
bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
                        unsigned int start_pos)
{
    unsigned char d_type = DT_UNKNOWN;
    unsigned int bit_pos;
    struct f2fs_dir_entry *de = NULL;

    bit_pos = ((unsigned long)ctx->pos % d->max);

    while (bit_pos < d->max) {
        bit_pos = find_next_bit_le(d->bitmap, d->max, bit_pos);
        if (bit_pos >= d->max)
            break;

        de = &d->dentry[bit_pos];
        if (de->file_type < F2FS_FT_MAX)
            d_type = f2fs_filetype_table[de->file_type];
        else
            d_type = DT_UNKNOWN;
        if (!dir_emit(ctx, d->filename[bit_pos],
                      le16_to_cpu(de->name_len),
                      le32_to_cpu(de->ino), d_type))
            return true;

        bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
        ctx->pos = start_pos + bit_pos;
    }
    return false;
}
Beispiel #4
0
static Bool
HgfsReaddirFillEntry(filldir_t filldirCb,            // IN: System filler callback
                     void *filldirCtx,               // IN/OUT: System filler context
                     char *entryName,                // IN: entry name
                     uint32 entryNameLength,         // IN: max name length
                     loff_t entryPos,                // IN: position = (ctx-pos)
                     ino_t entryIno,                 // IN: inode entry number
                     uint32 entryType)               // IN: entry type
{
   struct dir_context *ctx = filldirCtx;
   Bool result;

   ASSERT(filldirCb == NULL);   /* Contained within the context structure. */
   ASSERT(ctx != NULL);
   ASSERT(ctx->pos == entryPos);
   ASSERT(entryName != NULL);
   ASSERT(entryNameLength != 0);

   LOG(6, (KERN_DEBUG "VMware hgfs: %s: dir_emit(%s, %u, %Lu)\n",
            __func__, entryName, entryNameLength, ctx->pos));

   result = dir_emit(ctx,              /* filldir callback struct */
                     entryName,        /* name of dirent */
                     entryNameLength,  /* length of name */
                     entryIno,         /* inode number (0 makes it not show) */
                     entryType);       /* type of dirent */
   return result;
}
Beispiel #5
0
static int f2fs_readdir(struct file *file, struct dir_context *ctx)
{
	struct inode *inode = file_inode(file);
	unsigned long npages = dir_blocks(inode);
	unsigned int bit_pos = 0;
	struct f2fs_dentry_block *dentry_blk = NULL;
	struct f2fs_dir_entry *de = NULL;
	struct page *dentry_page = NULL;
	struct file_ra_state *ra = &file->f_ra;
	unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);
	unsigned char d_type = DT_UNKNOWN;

	bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK);

	/* readahead for multi pages of dir */
	if (npages - n > 1 && !ra_has_index(ra, n))
		page_cache_sync_readahead(inode->i_mapping, ra, file, n,
				min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES));

	for (; n < npages; n++) {
		dentry_page = get_lock_data_page(inode, n);
		if (IS_ERR(dentry_page))
			continue;

		dentry_blk = kmap(dentry_page);
		while (bit_pos < NR_DENTRY_IN_BLOCK) {
			bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
							NR_DENTRY_IN_BLOCK,
							bit_pos);
			if (bit_pos >= NR_DENTRY_IN_BLOCK)
				break;

			de = &dentry_blk->dentry[bit_pos];
			if (de->file_type < F2FS_FT_MAX)
				d_type = f2fs_filetype_table[de->file_type];
			else
				d_type = DT_UNKNOWN;
			if (!dir_emit(ctx,
					dentry_blk->filename[bit_pos],
					le16_to_cpu(de->name_len),
					le32_to_cpu(de->ino), d_type))
				goto stop;

			bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
			ctx->pos = n * NR_DENTRY_IN_BLOCK + bit_pos;
		}
		bit_pos = 0;
		ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
		kunmap(dentry_page);
		f2fs_put_page(dentry_page, 1);
		dentry_page = NULL;
	}
stop:
	if (dentry_page && !IS_ERR(dentry_page)) {
		kunmap(dentry_page);
		f2fs_put_page(dentry_page, 1);
	}

	return 0;
}
/* Inspired by generic filldir in fs/readdir.c */
static int
ecryptfs_filldir(void *dirent, const char *lower_name, int lower_namelen,
		 loff_t offset, u64 ino, unsigned int d_type)
{
	struct ecryptfs_getdents_callback *buf =
	    (struct ecryptfs_getdents_callback *)dirent;
	size_t name_size;
	char *name;
	int rc;

	buf->filldir_called++;
	rc = ecryptfs_decode_and_decrypt_filename(&name, &name_size,
						  buf->sb, lower_name,
						  lower_namelen);
	if (rc) {
		printk(KERN_ERR "%s: Error attempting to decode and decrypt "
		       "filename [%s]; rc = [%d]\n", __func__, lower_name,
		       rc);
		goto out;
	}
	buf->caller->pos = buf->ctx.pos;
	rc = !dir_emit(buf->caller, name, name_size, ino, d_type);
	kfree(name);
	if (!rc)
		buf->entries_written++;
out:
	return rc;
}
static int sysfs_readdir(struct file *file, struct dir_context *ctx)
{
	struct dentry *dentry = file->f_path.dentry;
	struct sysfs_dirent *parent_sd = dentry->d_fsdata;
	struct sysfs_dirent *pos = file->private_data;
	enum kobj_ns_type type;
	const void *ns;

	type = sysfs_ns_type(parent_sd);
	ns = sysfs_info(dentry->d_sb)->ns[type];

	if (!dir_emit_dots(file, ctx))
		return 0;
	mutex_lock(&sysfs_mutex);
	for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos);
	     pos;
	     pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) {
		const char *name = pos->s_name;
		unsigned int type = dt_type(pos);
		int len = strlen(name);
		ino_t ino = pos->s_ino;
		ctx->pos = pos->s_hash;
		file->private_data = sysfs_get(pos);

		mutex_unlock(&sysfs_mutex);
		if (!dir_emit(ctx, name, len, ino, type))
			return 0;
		mutex_lock(&sysfs_mutex);
	}
	mutex_unlock(&sysfs_mutex);
	file->private_data = NULL;
	ctx->pos = INT_MAX;
	return 0;
}
Beispiel #8
0
/*
 * read the entries from a directory
 */
static int romfs_readdir(struct file *file, struct dir_context *ctx)
{
	struct inode *i = file_inode(file);
	struct romfs_inode ri;
	unsigned long offset, maxoff;
	int j, ino, nextfh;
	char fsname[ROMFS_MAXFN];	/* XXX dynamic? */
	int ret;

	maxoff = romfs_maxsize(i->i_sb);

	offset = ctx->pos;
	if (!offset) {
		offset = i->i_ino & ROMFH_MASK;
		ret = romfs_dev_read(i->i_sb, offset, &ri, ROMFH_SIZE);
		if (ret < 0)
			goto out;
		offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
	}

	/* Not really failsafe, but we are read-only... */
	for (;;) {
		if (!offset || offset >= maxoff) {
			offset = maxoff;
			ctx->pos = offset;
			goto out;
		}
		ctx->pos = offset;

		/* Fetch inode info */
		ret = romfs_dev_read(i->i_sb, offset, &ri, ROMFH_SIZE);
		if (ret < 0)
			goto out;

		j = romfs_dev_strnlen(i->i_sb, offset + ROMFH_SIZE,
				      sizeof(fsname) - 1);
		if (j < 0)
			goto out;

		ret = romfs_dev_read(i->i_sb, offset + ROMFH_SIZE, fsname, j);
		if (ret < 0)
			goto out;
		fsname[j] = '\0';

		ino = offset;
		nextfh = be32_to_cpu(ri.next);
		if ((nextfh & ROMFH_TYPE) == ROMFH_HRD)
			ino = be32_to_cpu(ri.spec);
		if (!dir_emit(ctx, fsname, j, ino,
			    romfs_dtype_table[nextfh & ROMFH_TYPE]))
			goto out;

		offset = nextfh & ROMFH_MASK;
	}
out:
	return 0;
}
Beispiel #9
0
static int simplefs_readdir(struct file *filp, void *dirent, filldir_t filldir)
#endif
{
    loff_t pos;
    struct inode *inode;
    struct super_block *sb;
    struct buffer_head *bh;
    struct simplefs_inode *sfs_inode;
    struct simplefs_dir_record *record;
    int i;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
    pos = ctx->pos;
#else
    pos = filp->f_pos;
#endif
    inode = filp->f_dentry->d_inode;
    sb = inode->i_sb;

    if (pos) {
        /* FIXME: We use a hack of reading pos to figure if we have filled in all data.
         * We should probably fix this to work in a cursor based model and
         * use the tokens correctly to not fill too many data in each cursor based call */
        return 0;
    }

    sfs_inode = SIMPLEFS_INODE(inode);

    if (unlikely(!S_ISDIR(sfs_inode->mode))) {
        printk(KERN_ERR
               "inode [%llu][%lu] for fs object [%s] not a directory\n",
               sfs_inode->inode_no, inode->i_ino,
               filp->f_dentry->d_name.name);
        return -ENOTDIR;
    }

    bh = sb_bread(sb, sfs_inode->data_block_number);
    BUG_ON(!bh);

    record = (struct simplefs_dir_record *)bh->b_data;
    for (i = 0; i < sfs_inode->dir_children_count; i++) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
        dir_emit(ctx, record->filename, SIMPLEFS_FILENAME_MAXLEN,
                 record->inode_no, DT_UNKNOWN);
        ctx->pos += sizeof(struct simplefs_dir_record);
#else
        filldir(dirent, record->filename, SIMPLEFS_FILENAME_MAXLEN, pos,
                record->inode_no, DT_UNKNOWN);
        filp->f_pos += sizeof(struct simplefs_dir_record);
#endif
        pos += sizeof(struct simplefs_dir_record);
        record++;
    }
    brelse(bh);

    return 0;
}
Beispiel #10
0
static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
{
	bool over;
	struct p9_wstat st;
	int err = 0;
	struct p9_fid *fid;
	int buflen;
	int reclen = 0;
	struct p9_rdir *rdir;
	struct kvec kvec;

	p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
	fid = file->private_data;

	buflen = fid->clnt->msize - P9_IOHDRSZ;

	rdir = v9fs_alloc_rdir_buf(file, buflen);
	if (!rdir)
		return -ENOMEM;
	kvec.iov_base = rdir->buf;
	kvec.iov_len = buflen;

	while (1) {
		if (rdir->tail == rdir->head) {
			struct iov_iter to;
			int n;
			iov_iter_kvec(&to, READ | ITER_KVEC, &kvec, 1, buflen);
			n = p9_client_read(file->private_data, ctx->pos, &to,
					   &err);
			if (err)
				return err;

			rdir->head = 0;
			rdir->tail = n;
		}
		while (rdir->head < rdir->tail) {
			p9stat_init(&st);
			err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
					  rdir->tail - rdir->head, &st);
			if (err) {
				p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
				p9stat_free(&st);
				return -EIO;
			}
			reclen = st.size+2;

			over = !dir_emit(ctx, st.name, strlen(st.name),
					 v9fs_qid2ino(&st.qid), dt_type(&st));
			p9stat_free(&st);
			if (over)
				return 0;

			rdir->head += reclen;
			ctx->pos += reclen;
		}
	}
}
Beispiel #11
0
static int dedupfs_iterate(struct file *filp,
						   struct dir_context *ctx)
{
	loff_t pos;
	struct inode *inode;
	struct super_block *sb;
	struct buffer_head *bh;
	struct dedupfs_inode *dfs_inode;
	struct dedupfs_file_record *record;

	pos = ctx->pos;

	inode = file_inode(filp);
	sb = inode->i_sb;

	printk(KERN_INFO
		"We are inside iterate. The pos[%lu], inode_number[%lu]\n",
		(long unsigned int)pos, inode->i_ino);

	if (pos) {
		printk(KERN_INFO "pos seem to be non-zero which means "
					"we have already filled in all the details\n");
		return 0;
	}

	dfs_inode = DEDUPFS_INODE(inode);

	if(!S_ISDIR(dfs_inode->mode)) {
		printk(KERN_ERR
			   "inode [%d] is not a directory\n",
			   dfs_inode->inode_no);
		return -ENOTDIR;
	}

	bh = (struct buffer_head *)sb_bread(sb, dfs_inode->data_block_number);

	record = (struct dedupfs_file_record *)bh->b_data;
	for(int i = 0; i < dfs_inode->dir_children_count; i++) {
		printk(KERN_INFO "Got filename: %s\n", record->filename);
		dir_emit(ctx, record->filename, DEDUPFS_FILENAME_MAXLEN,
				record->inode_no, DT_UNKNOWN);
		ctx->pos += sizeof(struct dedupfs_file_record);
		record++;
	}
	brelse(bh);

	return 0;

}
Beispiel #12
0
/**
 * v9fs_dir_readdir_dotl - iterate through a directory
 * @file: opened file structure
 * @ctx: actor we feed the entries to
 *
 */
static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
{
	int err = 0;
	struct p9_fid *fid;
	int buflen;
	struct p9_rdir *rdir;
	struct p9_dirent curdirent;

	p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
	fid = file->private_data;

	buflen = fid->clnt->msize - P9_READDIRHDRSZ;

	rdir = v9fs_alloc_rdir_buf(file, buflen);
	if (!rdir)
		return -ENOMEM;

	while (1) {
		if (rdir->tail == rdir->head) {
			err = p9_client_readdir(fid, rdir->buf, buflen,
						ctx->pos);
			if (err <= 0)
				return err;

			rdir->head = 0;
			rdir->tail = err;
		}

		while (rdir->head < rdir->tail) {

			err = p9dirent_read(fid->clnt, rdir->buf + rdir->head,
					    rdir->tail - rdir->head,
					    &curdirent);
			if (err < 0) {
				p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
				return -EIO;
			}

			if (!dir_emit(ctx, curdirent.d_name,
				      strlen(curdirent.d_name),
				      v9fs_qid2ino(&curdirent.qid),
				      curdirent.d_type))
				return 0;

			ctx->pos = curdirent.d_off;
			rdir->head += err;
		}
	}
}
Beispiel #13
0
/* Inspired by generic filldir in fs/readdir.c */
static int
tierfs_filldir(void *dirent, const char *lower_name, int lower_namelen,
		 loff_t offset, u64 ino, unsigned int d_type)
{
	struct tierfs_getdents_callback *buf =
	    (struct tierfs_getdents_callback *)dirent;
	int rc;

	TRACE_ENTRY();
	buf->filldir_called++;
	buf->caller->pos = buf->ctx.pos;
	rc = !dir_emit(buf->caller, lower_name, lower_namelen, ino, d_type);
	if (!rc)
		buf->entries_written++;
	TRACE_EXIT();
	return rc;
}
Beispiel #14
0
static int
nvmm_readdir(struct file *file, struct dir_context *ctx)
{
	loff_t pos = ctx->pos;
	int err = 0;
	struct inode *inode = file_inode(file);
	struct super_block *sb = inode->i_sb;
	unsigned long offset = pos && ~PAGE_CACHE_MASK;
	unsigned char *types = NULL;
	char *start_addr, *end_addr;
	struct nvmm_dir_entry *nde;

	types = nvmm_filetype_table;
	
	/*establish mapping*/
	err = nvmm_establish_mapping(inode);


	if(pos >= inode->i_size)
		goto final;

	if(file->f_version != inode->i_version){
		if(offset){
			offset = 0;
			ctx->pos = (loff_t)(NVMM_I(inode)->i_virt_addr);
		}
		file->f_version = inode->i_version;
	}
	start_addr = NVMM_I(inode)->i_virt_addr;
	end_addr = start_addr + inode->i_size;
	if(start_addr >= end_addr)
		goto final;
	nde = (struct nvmm_dir_entry *)start_addr;
	for(;(char *)nde < end_addr;nde =  nvmm_next_entry(nde)){
		if(nde->rec_len == 0){
			nvmm_error(sb, __FUNCTION__, "zero-length directory entry\n");
			err = -EIO;
			goto final;
		}
		if(nde->inode){
			unsigned char d_type = DT_UNKNOWN;
			if(types && nde->file_type < NVMM_FT_MAX)
				d_type = types[nde->file_type];
			if(!dir_emit(ctx, nde->name, nde->name_len, le64_to_cpu(nde->inode),d_type))
				goto final;
		}
Beispiel #15
0
static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
			     struct dir_context *ctx, u64 attr_version)
{
	struct fuse_direntplus *direntplus;
	struct fuse_dirent *dirent;
	size_t reclen;
	int over = 0;
	int ret;

	while (nbytes >= FUSE_NAME_OFFSET_DIRENTPLUS) {
		direntplus = (struct fuse_direntplus *) buf;
		dirent = &direntplus->dirent;
		reclen = FUSE_DIRENTPLUS_SIZE(direntplus);

		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
			return -EIO;
		if (reclen > nbytes)
			break;
		if (memchr(dirent->name, '/', dirent->namelen) != NULL)
			return -EIO;

		if (!over) {
			/* We fill entries into dstbuf only as much as
			   it can hold. But we still continue iterating
			   over remaining entries to link them. If not,
			   we need to send a FORGET for each of those
			   which we did not link.
			*/
			over = !dir_emit(ctx, dirent->name, dirent->namelen,
				       dirent->ino, dirent->type);
			ctx->pos = dirent->off;
		}

		buf += reclen;
		nbytes -= reclen;

		ret = fuse_direntplus_link(file, direntplus, attr_version);
		if (ret)
			fuse_force_forget(file, direntplus->entry_out.nodeid);
	}

	return 0;
}
Beispiel #16
0
static int sysv_readdir(struct file *file, struct dir_context *ctx)
{
	unsigned long pos = ctx->pos;
	struct inode *inode = file_inode(file);
	struct super_block *sb = inode->i_sb;
	unsigned long npages = dir_pages(inode);
	unsigned offset;
	unsigned long n;

	ctx->pos = pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1);
	if (pos >= inode->i_size)
		return 0;

	offset = pos & ~PAGE_MASK;
	n = pos >> PAGE_SHIFT;

	for ( ; n < npages; n++, offset = 0) {
		char *kaddr, *limit;
		struct sysv_dir_entry *de;
		struct page *page = dir_get_page(inode, n);

		if (IS_ERR(page))
			continue;
		kaddr = (char *)page_address(page);
		de = (struct sysv_dir_entry *)(kaddr+offset);
		limit = kaddr + PAGE_SIZE - SYSV_DIRSIZE;
		for ( ;(char*)de <= limit; de++, ctx->pos += sizeof(*de)) {
			char *name = de->name;

			if (!de->inode)
				continue;

			if (!dir_emit(ctx, name, strnlen(name,SYSV_NAMELEN),
					fs16_to_cpu(SYSV_SB(sb), de->inode),
					DT_UNKNOWN)) {
				dir_put_page(page);
				return 0;
			}
		}
		dir_put_page(page);
	}
	return 0;
}
Beispiel #17
0
/* FIXME: readdir currently has it's own dir_walk code.  I don't see a good
 * way to combine the two copies */
static int logfs_readdir(struct file *file, struct dir_context *ctx)
{
	struct inode *dir = file_inode(file);
	loff_t pos;
	struct page *page;
	struct logfs_disk_dentry *dd;

	if (ctx->pos < 0)
		return -EINVAL;

	if (!dir_emit_dots(file, ctx))
		return 0;

	pos = ctx->pos - 2;
	BUG_ON(pos < 0);
	for (;; pos++, ctx->pos++) {
		bool full;
		if (beyond_eof(dir, pos))
			break;
		if (!logfs_exist_block(dir, pos)) {
			/* deleted dentry */
			pos = dir_seek_data(dir, pos);
			continue;
		}
		page = read_cache_page(dir->i_mapping, pos,
				(filler_t *)logfs_readpage, NULL);
		if (IS_ERR(page))
			return PTR_ERR(page);
		dd = kmap(page);
		BUG_ON(dd->namelen == 0);

		full = !dir_emit(ctx, (char *)dd->name,
				be16_to_cpu(dd->namelen),
				be64_to_cpu(dd->ino), dd->type);
		kunmap(page);
		page_cache_release(page);
		if (full)
			break;
	}
	return 0;
}
Beispiel #18
0
static int
zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx)
{
	zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode);
	fstrans_cookie_t cookie;
	char snapname[MAXNAMELEN];
	boolean_t case_conflict;
	uint64_t id, pos;
	int error = 0;

	ZFS_ENTER(zsb);
	cookie = spl_fstrans_mark();

	if (!dir_emit_dots(filp, ctx))
		goto out;

	pos = ctx->pos;
	while (error == 0) {
		dsl_pool_config_enter(dmu_objset_pool(zsb->z_os), FTAG);
		error = -dmu_snapshot_list_next(zsb->z_os, MAXNAMELEN,
		    snapname, &id, &pos, &case_conflict);
		dsl_pool_config_exit(dmu_objset_pool(zsb->z_os), FTAG);
		if (error)
			goto out;

		if (!dir_emit(ctx, snapname, strlen(snapname),
		    ZFSCTL_INO_SHARES - id, DT_DIR))
			goto out;

		ctx->pos = pos;
	}
out:
	spl_fstrans_unmark(cookie);
	ZFS_EXIT(zsb);

	if (error == -ENOENT)
		return (0);

	return (error);
}
Beispiel #19
0
static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
			 struct dir_context *ctx)
{
	while (nbytes >= FUSE_NAME_OFFSET) {
		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
		size_t reclen = FUSE_DIRENT_SIZE(dirent);
		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
			return -EIO;
		if (reclen > nbytes)
			break;

		if (!dir_emit(ctx, dirent->name, dirent->namelen,
			       dirent->ino, dirent->type))
			break;

		buf += reclen;
		nbytes -= reclen;
		ctx->pos = dirent->off;
	}

	return 0;
}
Beispiel #20
0
static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
{
	struct dentry *dentry = file->f_path.dentry;
	struct kernfs_node *parent = dentry->d_fsdata;
	struct kernfs_node *pos = file->private_data;
	const void *ns = NULL;

	if (!dir_emit_dots(file, ctx))
		return 0;
	mutex_lock(&kernfs_mutex);

	if (kernfs_ns_enabled(parent))
		ns = kernfs_info(dentry->d_sb)->ns;

	for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos);
	     pos;
	     pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos)) {
		const char *name = pos->name;
		unsigned int type = dt_type(pos);
		int len = strlen(name);
		ino_t ino = pos->ino;

		ctx->pos = pos->hash;
		file->private_data = pos;
		kernfs_get(pos);

		mutex_unlock(&kernfs_mutex);
		if (!dir_emit(ctx, name, len, ino, type))
			return 0;
		mutex_lock(&kernfs_mutex);
	}
	mutex_unlock(&kernfs_mutex);
	file->private_data = NULL;
	ctx->pos = INT_MAX;
	return 0;
}
Beispiel #21
0
static int jffs2_readdir(struct file *file, struct dir_context *ctx)
{
    struct inode *inode = file_inode(file);
    struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
    struct jffs2_full_dirent *fd;
    unsigned long curofs = 1;

    jffs2_dbg(1, "jffs2_readdir() for dir_i #%lu\n", inode->i_ino);

    if (!dir_emit_dots(file, ctx))
        return 0;

    mutex_lock(&f->sem);
    for (fd = f->dents; fd; fd = fd->next) {
        curofs++;
        /* First loop: curofs = 2; pos = 2 */
        if (curofs < ctx->pos) {
            jffs2_dbg(2, "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
                      fd->name, fd->ino, fd->type, curofs, (unsigned long)ctx->pos);
            continue;
        }
        if (!fd->ino) {
            jffs2_dbg(2, "Skipping deletion dirent \"%s\"\n",
                      fd->name);
            ctx->pos++;
            continue;
        }
        jffs2_dbg(2, "Dirent %ld: \"%s\", ino #%u, type %d\n",
                  (unsigned long)ctx->pos, fd->name, fd->ino, fd->type);
        if (!dir_emit(ctx, fd->name, strlen(fd->name), fd->ino, fd->type))
            break;
        ctx->pos++;
    }
    mutex_unlock(&f->sem);
    return 0;
}
Beispiel #22
0
static int cifs_filldir(char *find_entry, struct file *file,
		struct dir_context *ctx,
		char *scratch_buf, unsigned int max_len)
{
	struct cifsFileInfo *file_info = file->private_data;
	struct super_block *sb = file_inode(file)->i_sb;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	struct cifs_dirent de = { NULL, };
	struct cifs_fattr fattr;
	struct qstr name;
	int rc = 0;
	ino_t ino;

	rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level,
			      file_info->srch_inf.unicode);
	if (rc)
		return rc;

	if (de.namelen > max_len) {
		cifs_dbg(VFS, "bad search response length %zd past smb end\n",
			 de.namelen);
		return -EINVAL;
	}

	/* skip . and .. since we added them first */
	if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode))
		return 0;

	if (file_info->srch_inf.unicode) {
		struct nls_table *nlt = cifs_sb->local_nls;
		int map_type;

		map_type = cifs_remap(cifs_sb);
		name.name = scratch_buf;
		name.len =
			cifs_from_utf16((char *)name.name, (__le16 *)de.name,
					UNICODE_NAME_MAX,
					min_t(size_t, de.namelen,
					      (size_t)max_len), nlt, map_type);
		name.len -= nls_nullsize(nlt);
	} else {
		name.name = de.name;
		name.len = de.namelen;
	}

	switch (file_info->srch_inf.info_level) {
	case SMB_FIND_FILE_UNIX:
		cifs_unix_basic_to_fattr(&fattr,
					 &((FILE_UNIX_INFO *)find_entry)->basic,
					 cifs_sb);
		break;
	case SMB_FIND_FILE_INFO_STANDARD:
		cifs_std_info_to_fattr(&fattr,
				       (FIND_FILE_STANDARD_INFO *)find_entry,
				       cifs_sb);
		break;
	default:
		cifs_dir_info_to_fattr(&fattr,
				       (FILE_DIRECTORY_INFO *)find_entry,
				       cifs_sb);
		break;
	}

	if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
		fattr.cf_uniqueid = de.ino;
	} else {
		fattr.cf_uniqueid = iunique(sb, ROOT_I);
		cifs_autodisable_serverino(cifs_sb);
	}

	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
	    couldbe_mf_symlink(&fattr))
		/*
		 * trying to get the type and mode can be slow,
		 * so just call those regular files for now, and mark
		 * for reval
		 */
		fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;

	cifs_prime_dcache(file->f_path.dentry, &name, &fattr);

	ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
	return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype);
}
Beispiel #23
0
/**
 * vxfs_readdir - read a directory
 * @fp:		the directory to read
 * @retp:	return buffer
 * @filler:	filldir callback
 *
 * Description:
 *   vxfs_readdir fills @retp with directory entries from @fp
 *   using the VFS supplied callback @filler.
 *
 * Returns:
 *   Zero.
 */
static int
vxfs_readdir(struct file *fp, struct dir_context *ctx)
{
	struct inode		*ip = file_inode(fp);
	struct super_block	*sbp = ip->i_sb;
	u_long			bsize = sbp->s_blocksize;
	loff_t			pos, limit;
	struct vxfs_sb_info	*sbi = VXFS_SBI(sbp);

	if (ctx->pos == 0) {
		if (!dir_emit_dot(fp, ctx))
			goto out;
		ctx->pos++;
	}
	if (ctx->pos == 1) {
		if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
			goto out;
		ctx->pos++;
	}

	limit = VXFS_DIRROUND(ip->i_size);
	if (ctx->pos > limit)
		goto out;

	pos = ctx->pos & ~3L;

	while (pos < limit) {
		struct page *pp;
		char *kaddr;
		int pg_ofs = pos & ~PAGE_MASK;
		int rc = 0;

		pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
		if (IS_ERR(pp))
			return -ENOMEM;

		kaddr = (char *)page_address(pp);

		while (pg_ofs < PAGE_SIZE && pos < limit) {
			struct vxfs_direct *de;

			if ((pos & (bsize - 1)) < 4) {
				struct vxfs_dirblk *dbp =
					(struct vxfs_dirblk *)
					 (kaddr + (pos & ~PAGE_MASK));
				int overhead = VXFS_DIRBLKOV(sbi, dbp);

				pos += overhead;
				pg_ofs += overhead;
			}
			de = (struct vxfs_direct *)(kaddr + pg_ofs);

			if (!de->d_reclen) {
				pos += bsize - 1;
				pos &= ~(bsize - 1);
				break;
			}

			pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
			pos += fs16_to_cpu(sbi, de->d_reclen);
			if (!de->d_ino)
				continue;

			rc = dir_emit(ctx, de->d_name,
					fs16_to_cpu(sbi, de->d_namelen),
					fs32_to_cpu(sbi, de->d_ino),
					DT_UNKNOWN);
			if (!rc) {
				/* the dir entry was not read, fix pos. */
				pos -= fs16_to_cpu(sbi, de->d_reclen);
				break;
			}
		}
		vxfs_put_page(pp);
		if (!rc)
			break;
	}

	ctx->pos = pos | 2;

out:
	return 0;
}
Beispiel #24
0
/*
 * deal with one block in an AFS directory
 */
static int afs_dir_iterate_block(struct dir_context *ctx,
				 union afs_dir_block *block,
				 unsigned blkoff)
{
	union afs_dirent *dire;
	unsigned offset, next, curr;
	size_t nlen;
	int tmp;

	_enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block);

	curr = (ctx->pos - blkoff) / sizeof(union afs_dirent);

	/* walk through the block, an entry at a time */
	for (offset = AFS_DIRENT_PER_BLOCK - block->pagehdr.nentries;
	     offset < AFS_DIRENT_PER_BLOCK;
	     offset = next
	     ) {
		next = offset + 1;

		/* skip entries marked unused in the bitmap */
		if (!(block->pagehdr.bitmap[offset / 8] &
		      (1 << (offset % 8)))) {
			_debug("ENT[%Zu.%u]: unused",
			       blkoff / sizeof(union afs_dir_block), offset);
			if (offset >= curr)
				ctx->pos = blkoff +
					next * sizeof(union afs_dirent);
			continue;
		}

		/* got a valid entry */
		dire = &block->dirents[offset];
		nlen = strnlen(dire->u.name,
			       sizeof(*block) -
			       offset * sizeof(union afs_dirent));

		_debug("ENT[%Zu.%u]: %s %Zu \"%s\"",
		       blkoff / sizeof(union afs_dir_block), offset,
		       (offset < curr ? "skip" : "fill"),
		       nlen, dire->u.name);

		/* work out where the next possible entry is */
		for (tmp = nlen; tmp > 15; tmp -= sizeof(union afs_dirent)) {
			if (next >= AFS_DIRENT_PER_BLOCK) {
				_debug("ENT[%Zu.%u]:"
				       " %u travelled beyond end dir block"
				       " (len %u/%Zu)",
				       blkoff / sizeof(union afs_dir_block),
				       offset, next, tmp, nlen);
				return -EIO;
			}
			if (!(block->pagehdr.bitmap[next / 8] &
			      (1 << (next % 8)))) {
				_debug("ENT[%Zu.%u]:"
				       " %u unmarked extension (len %u/%Zu)",
				       blkoff / sizeof(union afs_dir_block),
				       offset, next, tmp, nlen);
				return -EIO;
			}

			_debug("ENT[%Zu.%u]: ext %u/%Zu",
			       blkoff / sizeof(union afs_dir_block),
			       next, tmp, nlen);
			next++;
		}

		/* skip if starts before the current position */
		if (offset < curr)
			continue;

		/* found the next entry */
		if (!dir_emit(ctx, dire->u.name, nlen,
			      ntohl(dire->u.vnode),
			      ctx->actor == afs_lookup_filldir ?
			      ntohl(dire->u.unique) : DT_UNKNOWN)) {
			_leave(" = 0 [full]");
			return 0;
		}

		ctx->pos = blkoff + next * sizeof(union afs_dirent);
	}

	_leave(" = 1 [more]");
	return 1;
}
Beispiel #25
0
static int
affs_readdir(struct file *file, struct dir_context *ctx)
{
	struct inode		*inode = file_inode(file);
	struct super_block	*sb = inode->i_sb;
	struct buffer_head	*dir_bh = NULL;
	struct buffer_head	*fh_bh = NULL;
	unsigned char		*name;
	int			 namelen;
	u32			 i;
	int			 hash_pos;
	int			 chain_pos;
	u32			 ino;
	int			 error = 0;

	pr_debug("%s(ino=%lu,f_pos=%llx)\n", __func__, inode->i_ino, ctx->pos);

	if (ctx->pos < 2) {
		file->private_data = (void *)0;
		if (!dir_emit_dots(file, ctx))
			return 0;
	}

	affs_lock_dir(inode);
	chain_pos = (ctx->pos - 2) & 0xffff;
	hash_pos  = (ctx->pos - 2) >> 16;
	if (chain_pos == 0xffff) {
		affs_warning(sb, "readdir", "More than 65535 entries in chain");
		chain_pos = 0;
		hash_pos++;
		ctx->pos = ((hash_pos << 16) | chain_pos) + 2;
	}
	dir_bh = affs_bread(sb, inode->i_ino);
	if (!dir_bh)
		goto out_unlock_dir;

	/* If the directory hasn't changed since the last call to readdir(),
	 * we can jump directly to where we left off.
	 */
	ino = (u32)(long)file->private_data;
	if (ino && file->f_version == inode->i_version) {
		pr_debug("readdir() left off=%d\n", ino);
		goto inside;
	}

	ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
	for (i = 0; ino && i < chain_pos; i++) {
		fh_bh = affs_bread(sb, ino);
		if (!fh_bh) {
			affs_error(sb, "readdir","Cannot read block %d", i);
			error = -EIO;
			goto out_brelse_dir;
		}
		ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
		affs_brelse(fh_bh);
		fh_bh = NULL;
	}
	if (ino)
		goto inside;
	hash_pos++;

	for (; hash_pos < AFFS_SB(sb)->s_hashsize; hash_pos++) {
		ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
		if (!ino)
			continue;
		ctx->pos = (hash_pos << 16) + 2;
inside:
		do {
			fh_bh = affs_bread(sb, ino);
			if (!fh_bh) {
				affs_error(sb, "readdir",
					   "Cannot read block %d", ino);
				break;
			}

			namelen = min(AFFS_TAIL(sb, fh_bh)->name[0],
				      (u8)AFFSNAMEMAX);
			name = AFFS_TAIL(sb, fh_bh)->name + 1;
			pr_debug("readdir(): dir_emit(\"%.*s\", ino=%u), hash=%d, f_pos=%llx\n",
				 namelen, name, ino, hash_pos, ctx->pos);

			if (!dir_emit(ctx, name, namelen, ino, DT_UNKNOWN))
				goto done;
			ctx->pos++;
			ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
			affs_brelse(fh_bh);
			fh_bh = NULL;
		} while (ino);
	}
done:
	file->f_version = inode->i_version;
	file->private_data = (void *)(long)ino;
	affs_brelse(fh_bh);

out_brelse_dir:
	affs_brelse(dir_bh);

out_unlock_dir:
	affs_unlock_dir(inode);
	return error;
}
Beispiel #26
0
static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
			bool excl)
{
	struct inode *inode;
	struct ubifs_info *c = dir->i_sb->s_fs_info;
	int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
					.dirtied_ino = 1 };
	struct ubifs_inode *dir_ui = ubifs_inode(dir);

	/*
	 * Budget request settings: new inode, new direntry, changing the
	 * parent directory inode.
	 */

	dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
		dentry, mode, dir->i_ino);

	err = ubifs_budget_space(c, &req);
	if (err)
		return err;

	inode = ubifs_new_inode(c, dir, mode);
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
		goto out_budg;
	}

	err = ubifs_init_security(dir, inode, &dentry->d_name);
	if (err)
		goto out_inode;

	mutex_lock(&dir_ui->ui_mutex);
	dir->i_size += sz_change;
	dir_ui->ui_size = dir->i_size;
	dir->i_mtime = dir->i_ctime = inode->i_ctime;
	err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0);
	if (err)
		goto out_cancel;
	mutex_unlock(&dir_ui->ui_mutex);

	ubifs_release_budget(c, &req);
	insert_inode_hash(inode);
	d_instantiate(dentry, inode);
	return 0;

out_cancel:
	dir->i_size -= sz_change;
	dir_ui->ui_size = dir->i_size;
	mutex_unlock(&dir_ui->ui_mutex);
out_inode:
	make_bad_inode(inode);
	iput(inode);
out_budg:
	ubifs_release_budget(c, &req);
	ubifs_err(c, "cannot create regular file, error %d", err);
	return err;
}

/**
 * vfs_dent_type - get VFS directory entry type.
 * @type: UBIFS directory entry type
 *
 * This function converts UBIFS directory entry type into VFS directory entry
 * type.
 */
static unsigned int vfs_dent_type(uint8_t type)
{
	switch (type) {
	case UBIFS_ITYPE_REG:
		return DT_REG;
	case UBIFS_ITYPE_DIR:
		return DT_DIR;
	case UBIFS_ITYPE_LNK:
		return DT_LNK;
	case UBIFS_ITYPE_BLK:
		return DT_BLK;
	case UBIFS_ITYPE_CHR:
		return DT_CHR;
	case UBIFS_ITYPE_FIFO:
		return DT_FIFO;
	case UBIFS_ITYPE_SOCK:
		return DT_SOCK;
	default:
		BUG();
	}
	return 0;
}

/*
 * The classical Unix view for directory is that it is a linear array of
 * (name, inode number) entries. Linux/VFS assumes this model as well.
 * Particularly, 'readdir()' call wants us to return a directory entry offset
 * which later may be used to continue 'readdir()'ing the directory or to
 * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this
 * model because directory entries are identified by keys, which may collide.
 *
 * UBIFS uses directory entry hash value for directory offsets, so
 * 'seekdir()'/'telldir()' may not always work because of possible key
 * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work
 * properly by means of saving full directory entry name in the private field
 * of the file description object.
 *
 * This means that UBIFS cannot support NFS which requires full
 * 'seekdir()'/'telldir()' support.
 */
static int ubifs_readdir(struct file *file, struct dir_context *ctx)
{
	int err;
	struct qstr nm;
	union ubifs_key key;
	struct ubifs_dent_node *dent;
	struct inode *dir = file_inode(file);
	struct ubifs_info *c = dir->i_sb->s_fs_info;

	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos);

	if (ctx->pos > UBIFS_S_KEY_HASH_MASK || ctx->pos == 2)
		/*
		 * The directory was seek'ed to a senseless position or there
		 * are no more entries.
		 */
		return 0;

	if (file->f_version == 0) {
		/*
		 * The file was seek'ed, which means that @file->private_data
		 * is now invalid. This may also be just the first
		 * 'ubifs_readdir()' invocation, in which case
		 * @file->private_data is NULL, and the below code is
		 * basically a no-op.
		 */
		kfree(file->private_data);
		file->private_data = NULL;
	}

	/*
	 * 'generic_file_llseek()' unconditionally sets @file->f_version to
	 * zero, and we use this for detecting whether the file was seek'ed.
	 */
	file->f_version = 1;

	/* File positions 0 and 1 correspond to "." and ".." */
	if (ctx->pos < 2) {
		ubifs_assert(!file->private_data);
		if (!dir_emit_dots(file, ctx))
			return 0;

		/* Find the first entry in TNC and save it */
		lowest_dent_key(c, &key, dir->i_ino);
		nm.name = NULL;
		dent = ubifs_tnc_next_ent(c, &key, &nm);
		if (IS_ERR(dent)) {
			err = PTR_ERR(dent);
			goto out;
		}

		ctx->pos = key_hash_flash(c, &dent->key);
		file->private_data = dent;
	}

	dent = file->private_data;
	if (!dent) {
		/*
		 * The directory was seek'ed to and is now readdir'ed.
		 * Find the entry corresponding to @ctx->pos or the closest one.
		 */
		dent_key_init_hash(c, &key, dir->i_ino, ctx->pos);
		nm.name = NULL;
		dent = ubifs_tnc_next_ent(c, &key, &nm);
		if (IS_ERR(dent)) {
			err = PTR_ERR(dent);
			goto out;
		}
		ctx->pos = key_hash_flash(c, &dent->key);
		file->private_data = dent;
	}

	while (1) {
		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
			key_hash_flash(c, &dent->key));
		ubifs_assert(le64_to_cpu(dent->ch.sqnum) >
			     ubifs_inode(dir)->creat_sqnum);

		nm.len = le16_to_cpu(dent->nlen);
		if (!dir_emit(ctx, dent->name, nm.len,
			       le64_to_cpu(dent->inum),
			       vfs_dent_type(dent->type)))
			return 0;

		/* Switch to the next entry */
		key_read(c, &dent->key, &key);
		nm.name = dent->name;
		dent = ubifs_tnc_next_ent(c, &key, &nm);
		if (IS_ERR(dent)) {
			err = PTR_ERR(dent);
			goto out;
		}

		kfree(file->private_data);
		ctx->pos = key_hash_flash(c, &dent->key);
		file->private_data = dent;
		cond_resched();
	}

out:
	if (err != -ENOENT) {
		ubifs_err(c, "cannot find next direntry, error %d", err);
		return err;
	}

	kfree(file->private_data);
	file->private_data = NULL;
	/* 2 is a special value indicating that there are no more direntries */
	ctx->pos = 2;
	return 0;
}
Beispiel #27
0
/*
 * routine called when the VFS needs to read the directory contents
 *
 * @file: the VFS file structure of the directory
 * @ctx: directory context
 *
 * return: 0 on success, error code otherwise
 */
static int wtfs_iterate(struct file * file, struct dir_context * ctx)
{
	struct inode * dir_vi = file_inode(file);
	struct super_block * vsb = dir_vi->i_sb;
	struct wtfs_inode_info * info = WTFS_INODE_INFO(dir_vi);
	struct wtfs_dir_block * block = NULL;
	struct buffer_head * bh = NULL;
	uint64_t count, offset, next, inode_no;
	char * filename = NULL;
	int i, j, k;
	int ret = -EINVAL;

	/* calculate how many entries we have counted, including null entries */
	count = ctx->pos / sizeof(struct wtfs_dentry);
	offset = ctx->pos % sizeof(struct wtfs_dentry);
	if (offset != 0) {
		wtfs_error("bad position %llu at %s:%lu\n", ctx->pos,
			dir_vi->i_sb->s_id, dir_vi->i_ino);
		goto error;
	}

	/* do iterate */
	next = info->first_block;
	i = 0; /* valid entry counter */
	j = 0; /* total entry counter, including null ones */
	while (next != 0) {
		if ((bh = sb_bread(vsb, next)) == NULL) {
			wtfs_error("unable to read the block %llu\n", next);
			goto error;
		}
		block = (struct wtfs_dir_block *)bh->b_data;
		for (k = 0; k < WTFS_DENTRY_COUNT_PER_BLOCK; ++k) {
			inode_no = wtfs64_to_cpu(block->entries[k].inode_no);
			filename = block->entries[k].filename;
			if (inode_no != 0) {
				if (j >= count && i < info->dir_entry_count) {
					wtfs_debug("emitting entry '%s' of "
						"inode %llu\n",
						filename, inode_no);

					if (dir_emit(ctx, filename,
						strnlen(filename,
							WTFS_FILENAME_MAX),
						inode_no, DT_UNKNOWN) == 0) {
						brelse(bh);
						return 0;
					}
				}
				++i;
			}
			++j;
			ctx->pos += sizeof(struct wtfs_dentry);
		}
		next = wtfs64_to_cpu(block->next);
		brelse(bh);
	}
	return 0;

error:
	if (bh != NULL) {
		brelse(bh);
	}
	return ret;
}
Beispiel #28
0
static int sf_dir_read(struct file *dir, void *opaque, filldir_t filldir)
#endif
{
    TRACE();
    for (;;)
    {
        int err;
        ino_t fake_ino;
        loff_t sanity;
        char d_name[NAME_MAX];
        int d_type = DT_UNKNOWN;

        err = sf_getdent(dir, d_name, &d_type);
        switch (err)
        {
            case 1:
                return 0;

            case 0:
                break;

            case -1:
            default:
                /* skip erroneous entry and proceed */
                LogFunc(("sf_getdent error %d\n", err));
                dir->f_pos += 1;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
                ctx->pos += 1;
#endif
                continue;
        }

        /* d_name now contains a valid entry name */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
        sanity = ctx->pos + 0xbeef;
#else
        sanity = dir->f_pos + 0xbeef;
#endif
        fake_ino = sanity;
        if (sanity - fake_ino)
        {
            LogRelFunc(("can not compute ino\n"));
            return -EINVAL;
        }

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
        if (!dir_emit(ctx, d_name, strlen(d_name), fake_ino, d_type))
        {
            LogFunc(("dir_emit failed\n"));
            return 0;
        }
#else
        err = filldir(opaque, d_name, strlen(d_name), dir->f_pos, fake_ino, d_type);
        if (err)
        {
            LogFunc(("filldir returned error %d\n", err));
            /* Rely on the fact that filldir returns error
               only when it runs out of space in opaque */
            return 0;
        }
#endif

        dir->f_pos += 1;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
        ctx->pos += 1;
#endif
    }

    BUG();
}
Beispiel #29
0
/*
 * So this function is called when the volume is mkfsed with
 * dir_index disabled. In order to keep f_pos persistent
 * after we convert from an inlined dir to a blocked based,
 * we just pretend that we are a normal dir and return the
 * offset as if '.' and '..' really take place.
 *
 */
int ext4_read_inline_dir(struct file *file,
			 struct dir_context *ctx,
			 int *has_inline_data)
{
	unsigned int offset, parent_ino;
	int i;
	struct ext4_dir_entry_2 *de;
	struct super_block *sb;
	struct inode *inode = file_inode(file);
	int ret, inline_size = 0;
	struct ext4_iloc iloc;
	void *dir_buf = NULL;
	int dotdot_offset, dotdot_size, extra_offset, extra_size;

	ret = ext4_get_inode_loc(inode, &iloc);
	if (ret)
		return ret;

	down_read(&EXT4_I(inode)->xattr_sem);
	if (!ext4_has_inline_data(inode)) {
		up_read(&EXT4_I(inode)->xattr_sem);
		*has_inline_data = 0;
		goto out;
	}

	inline_size = ext4_get_inline_size(inode);
	dir_buf = kmalloc(inline_size, GFP_NOFS);
	if (!dir_buf) {
		ret = -ENOMEM;
		up_read(&EXT4_I(inode)->xattr_sem);
		goto out;
	}

	ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc);
	up_read(&EXT4_I(inode)->xattr_sem);
	if (ret < 0)
		goto out;

	ret = 0;
	sb = inode->i_sb;
	parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode);
	offset = ctx->pos;

	/*
	 * dotdot_offset and dotdot_size is the real offset and
	 * size for ".." and "." if the dir is block based while
	 * the real size for them are only EXT4_INLINE_DOTDOT_SIZE.
	 * So we will use extra_offset and extra_size to indicate them
	 * during the inline dir iteration.
	 */
	dotdot_offset = EXT4_DIR_REC_LEN(1);
	dotdot_size = dotdot_offset + EXT4_DIR_REC_LEN(2);
	extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE;
	extra_size = extra_offset + inline_size;

	/*
	 * If the version 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 inline
	 * dir to make sure.
	 */
	if (file->f_version != inode->i_version) {
		for (i = 0; i < extra_size && i < offset;) {
			/*
			 * "." is with offset 0 and
			 * ".." is dotdot_offset.
			 */
			if (!i) {
				i = dotdot_offset;
				continue;
			} else if (i == dotdot_offset) {
				i = dotdot_size;
				continue;
			}
			/* for other entry, the real offset in
			 * the buf has to be tuned accordingly.
			 */
			de = (struct ext4_dir_entry_2 *)
				(dir_buf + i - extra_offset);
			/* 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 (ext4_rec_len_from_disk(de->rec_len, extra_size)
				< EXT4_DIR_REC_LEN(1))
				break;
			i += ext4_rec_len_from_disk(de->rec_len,
						    extra_size);
		}
		offset = i;
		ctx->pos = offset;
		file->f_version = inode->i_version;
	}

	while (ctx->pos < extra_size) {
		if (ctx->pos == 0) {
			if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR))
				goto out;
			ctx->pos = dotdot_offset;
			continue;
		}

		if (ctx->pos == dotdot_offset) {
			if (!dir_emit(ctx, "..", 2, parent_ino, DT_DIR))
				goto out;
			ctx->pos = dotdot_size;
			continue;
		}

		de = (struct ext4_dir_entry_2 *)
			(dir_buf + ctx->pos - extra_offset);
		if (ext4_check_dir_entry(inode, file, de, iloc.bh, dir_buf,
					 extra_size, ctx->pos))
			goto out;
		if (le32_to_cpu(de->inode)) {
			if (!dir_emit(ctx, de->name, de->name_len,
				      le32_to_cpu(de->inode),
				      get_dtype(sb, de->file_type)))
				goto out;
		}
		ctx->pos += ext4_rec_len_from_disk(de->rec_len, extra_size);
	}
out:
	kfree(dir_buf);
	brelse(iloc.bh);
	return ret;
}
Beispiel #30
0
int						/* error */
xfs_dir2_sf_getdents(
	xfs_inode_t		*dp,		/* incore directory inode */
	struct dir_context	*ctx)
{
	int			i;		/* shortform entry number */
	xfs_mount_t		*mp;		/* filesystem mount point */
	xfs_dir2_dataptr_t	off;		/* current entry's offset */
	xfs_dir2_sf_entry_t	*sfep;		/* shortform directory entry */
	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
	xfs_dir2_dataptr_t	dot_offset;
	xfs_dir2_dataptr_t	dotdot_offset;
	xfs_ino_t		ino;

	mp = dp->i_mount;

	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
	/*
	 * Give up if the directory is way too short.
	 */
	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
		ASSERT(XFS_FORCED_SHUTDOWN(mp));
		return XFS_ERROR(EIO);
	}

	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
	ASSERT(dp->i_df.if_u1.if_data != NULL);

	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;

	ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));

	/*
	 * If the block number in the offset is out of range, we're done.
	 */
	if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
		return 0;

	/*
	 * Precalculate offsets for . and .. as we will always need them.
	 *
	 * XXX(hch): the second argument is sometimes 0 and sometimes
	 * mp->m_dirdatablk.
	 */
	dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
					     XFS_DIR3_DATA_DOT_OFFSET(mp));
	dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
						XFS_DIR3_DATA_DOTDOT_OFFSET(mp));

	/*
	 * Put . entry unless we're starting past it.
	 */
	if (ctx->pos <= dot_offset) {
		ctx->pos = dot_offset & 0x7fffffff;
		if (!dir_emit(ctx, ".", 1, dp->i_ino, DT_DIR))
			return 0;
	}

	/*
	 * Put .. entry unless we're starting past it.
	 */
	if (ctx->pos <= dotdot_offset) {
		ino = xfs_dir2_sf_get_parent_ino(sfp);
		ctx->pos = dotdot_offset & 0x7fffffff;
		if (!dir_emit(ctx, "..", 2, ino, DT_DIR))
			return 0;
	}

	/*
	 * Loop while there are more entries and put'ing works.
	 */
	sfep = xfs_dir2_sf_firstentry(sfp);
	for (i = 0; i < sfp->count; i++) {
		off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
				xfs_dir2_sf_get_offset(sfep));

		if (ctx->pos > off) {
			sfep = xfs_dir2_sf_nextentry(sfp, sfep);
			continue;
		}

		ino = xfs_dir2_sfe_get_ino(sfp, sfep);
		ctx->pos = off & 0x7fffffff;
		if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen,
			    ino, DT_UNKNOWN))
			return 0;
		sfep = xfs_dir2_sf_nextentry(sfp, sfep);
	}

	ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
			0x7fffffff;
	return 0;
}