Exemple #1
0
/* support routines */
static int coda_venus_readdir(struct file *coda_file, void *buf,
			      filldir_t filldir)
{
	int result = 0; /* # of entries returned */
	struct coda_file_info *cfi;
	struct coda_inode_info *cii;
	struct file *host_file;
	struct dentry *de;
	struct venus_dirent *vdir;
	unsigned long vdir_size =
	    (unsigned long)(&((struct venus_dirent *)0)->d_name);
	unsigned int type;
	struct qstr name;
	ino_t ino;
	int ret;

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	host_file = cfi->cfi_container;

	de = coda_file->f_path.dentry;
	cii = ITOC(de->d_inode);

	vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
	if (!vdir) return -ENOMEM;

	if (coda_file->f_pos == 0) {
		ret = filldir(buf, ".", 1, 0, de->d_inode->i_ino, DT_DIR);
		if (ret < 0)
			goto out;
		result++;
		coda_file->f_pos++;
	}
	if (coda_file->f_pos == 1) {
		ret = filldir(buf, "..", 2, 1, de->d_parent->d_inode->i_ino, DT_DIR);
		if (ret < 0)
			goto out;
		result++;
		coda_file->f_pos++;
	}
	while (1) {
		/* read entries from the directory file */
		ret = kernel_read(host_file, coda_file->f_pos - 2, (char *)vdir,
				  sizeof(*vdir));
		if (ret < 0) {
			printk(KERN_ERR "coda readdir: read dir %s failed %d\n",
			       coda_f2s(&cii->c_fid), ret);
			break;
		}
		if (ret == 0) break; /* end of directory file reached */

		/* catch truncated reads */
		if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
			printk(KERN_ERR "coda readdir: short read on %s\n",
			       coda_f2s(&cii->c_fid));
			ret = -EBADF;
			break;
		}
		/* validate whether the directory file actually makes sense */
		if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
			printk(KERN_ERR "coda readdir: invalid dir %s\n",
			       coda_f2s(&cii->c_fid));
			ret = -EBADF;
			break;
		}

		name.len = vdir->d_namlen;
		name.name = vdir->d_name;

		/* Make sure we skip '.' and '..', we already got those */
		if (name.name[0] == '.' && (name.len == 1 ||
		    (vdir->d_name[1] == '.' && name.len == 2)))
			vdir->d_fileno = name.len = 0;

		/* skip null entries */
		if (vdir->d_fileno && name.len) {
			/* try to look up this entry in the dcache, that way
			 * userspace doesn't have to worry about breaking
			 * getcwd by having mismatched inode numbers for
			 * internal volume mountpoints. */
			ino = find_inode_number(de, &name);
			if (!ino) ino = vdir->d_fileno;

			type = CDT2DT(vdir->d_type);
			ret = filldir(buf, name.name, name.len,
				      coda_file->f_pos, ino, type);
			/* failure means no space for filling in this round */
			if (ret < 0) break;
			result++;
		}
		/* we'll always have progress because d_reclen is unsigned and
		 * we've already established it is non-zero. */
		coda_file->f_pos += vdir->d_reclen;
	}
out:
	kfree(vdir);
	return result ? result : ret;
}
Exemple #2
0
/* support routines */
static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
{
    struct coda_file_info *cfi;
    struct coda_inode_info *cii;
    struct file *host_file;
    struct venus_dirent *vdir;
    unsigned long vdir_size = offsetof(struct venus_dirent, d_name);
    unsigned int type;
    struct qstr name;
    ino_t ino;
    int ret;

    cfi = CODA_FTOC(coda_file);
    BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
    host_file = cfi->cfi_container;

    cii = ITOC(file_inode(coda_file));

    vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
    if (!vdir) return -ENOMEM;

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

    while (1) {
        /* read entries from the directory file */
        ret = kernel_read(host_file, ctx->pos - 2, (char *)vdir,
                          sizeof(*vdir));
        if (ret < 0) {
            pr_err("%s: read dir %s failed %d\n",
                   __func__, coda_f2s(&cii->c_fid), ret);
            break;
        }
        if (ret == 0) break; /* end of directory file reached */

        /* catch truncated reads */
        if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
            pr_err("%s: short read on %s\n",
                   __func__, coda_f2s(&cii->c_fid));
            ret = -EBADF;
            break;
        }
        /* validate whether the directory file actually makes sense */
        if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
            pr_err("%s: invalid dir %s\n",
                   __func__, coda_f2s(&cii->c_fid));
            ret = -EBADF;
            break;
        }

        name.len = vdir->d_namlen;
        name.name = vdir->d_name;

        /* Make sure we skip '.' and '..', we already got those */
        if (name.name[0] == '.' && (name.len == 1 ||
                                    (name.name[1] == '.' && name.len == 2)))
            vdir->d_fileno = name.len = 0;

        /* skip null entries */
        if (vdir->d_fileno && name.len) {
            ino = vdir->d_fileno;
            type = CDT2DT(vdir->d_type);
            if (!dir_emit(ctx, name.name, name.len, ino, type))
                break;
        }
        /* we'll always have progress because d_reclen is unsigned and
         * we've already established it is non-zero. */
        ctx->pos += vdir->d_reclen;
    }
out:
    kfree(vdir);
    return 0;
}
Exemple #3
0
/* support routines */
static int coda_venus_readdir(struct file *filp, filldir_t filldir,
			      void *dirent, struct dentry *dir)
{
	int result = 0; /* # of entries returned */
	struct venus_dirent *vdir;
	unsigned long vdir_size =
	    (unsigned long)(&((struct venus_dirent *)0)->d_name);
	unsigned int type;
	struct qstr name;
	ino_t ino;
	int ret, i;

	vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
	if (!vdir) return -ENOMEM;

	i = filp->f_pos;
	switch(i) {
	case 0:
		ret = filldir(dirent, ".", 1, 0, dir->d_inode->i_ino, DT_DIR);
		if (ret < 0) break;
		result++;
		filp->f_pos++;
		/* fallthrough */
	case 1:
		ret = filldir(dirent, "..", 2, 1, dir->d_parent->d_inode->i_ino, DT_DIR);
		if (ret < 0) break;
		result++;
		filp->f_pos++;
		/* fallthrough */
	default:
	while (1) {
		/* read entries from the directory file */
		ret = kernel_read(filp, filp->f_pos - 2, (char *)vdir,
				  sizeof(*vdir));
		if (ret < 0) {
			printk("coda_venus_readdir: read dir failed %d\n", ret);
			break;
		}
		if (ret == 0) break; /* end of directory file reached */

		/* catch truncated reads */
		if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
			printk("coda_venus_readdir: short read: %ld\n",
			       filp->f_path.dentry->d_inode->i_ino);
			ret = -EBADF;
			break;
		}
		/* validate whether the directory file actually makes sense */
		if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
			printk("coda_venus_readdir: Invalid dir: %ld\n",
			       filp->f_path.dentry->d_inode->i_ino);
			ret = -EBADF;
			break;
		}

		name.len = vdir->d_namlen;
		name.name = vdir->d_name;

		/* Make sure we skip '.' and '..', we already got those */
		if (name.name[0] == '.' && (name.len == 1 ||
		    (vdir->d_name[1] == '.' && name.len == 2)))
			vdir->d_fileno = name.len = 0;

		/* skip null entries */
		if (vdir->d_fileno && name.len) {
			/* try to look up this entry in the dcache, that way
			 * userspace doesn't have to worry about breaking
			 * getcwd by having mismatched inode numbers for
			 * internal volume mountpoints. */
			ino = find_inode_number(dir, &name);
			if (!ino) ino = vdir->d_fileno;

			type = CDT2DT(vdir->d_type);
			ret = filldir(dirent, name.name, name.len, filp->f_pos,
				      ino, type); 
			/* failure means no space for filling in this round */
			if (ret < 0) break;
			result++;
		}
		/* we'll always have progress because d_reclen is unsigned and
		 * we've already established it is non-zero. */
		filp->f_pos += vdir->d_reclen;
	}
	} 
	kfree(vdir);
	return result ? result : ret;
}
static int coda_venus_readdir(struct file *coda_file, void *buf,
			      filldir_t filldir)
{
	int result = 0; 
	struct coda_file_info *cfi;
	struct coda_inode_info *cii;
	struct file *host_file;
	struct dentry *de;
	struct venus_dirent *vdir;
	unsigned long vdir_size = offsetof(struct venus_dirent, d_name);
	unsigned int type;
	struct qstr name;
	ino_t ino;
	int ret;

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	host_file = cfi->cfi_container;

	de = coda_file->f_path.dentry;
	cii = ITOC(de->d_inode);

	vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
	if (!vdir) return -ENOMEM;

	if (coda_file->f_pos == 0) {
		ret = filldir(buf, ".", 1, 0, de->d_inode->i_ino, DT_DIR);
		if (ret < 0)
			goto out;
		result++;
		coda_file->f_pos++;
	}
	if (coda_file->f_pos == 1) {
		ret = filldir(buf, "..", 2, 1, parent_ino(de), DT_DIR);
		if (ret < 0)
			goto out;
		result++;
		coda_file->f_pos++;
	}
	while (1) {
		
		ret = kernel_read(host_file, coda_file->f_pos - 2, (char *)vdir,
				  sizeof(*vdir));
		if (ret < 0) {
			printk(KERN_ERR "coda readdir: read dir %s failed %d\n",
			       coda_f2s(&cii->c_fid), ret);
			break;
		}
		if (ret == 0) break; 

		
		if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
			printk(KERN_ERR "coda readdir: short read on %s\n",
			       coda_f2s(&cii->c_fid));
			ret = -EBADF;
			break;
		}
		
		if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
			printk(KERN_ERR "coda readdir: invalid dir %s\n",
			       coda_f2s(&cii->c_fid));
			ret = -EBADF;
			break;
		}

		name.len = vdir->d_namlen;
		name.name = vdir->d_name;

		
		if (name.name[0] == '.' && (name.len == 1 ||
		    (vdir->d_name[1] == '.' && name.len == 2)))
			vdir->d_fileno = name.len = 0;

		
		if (vdir->d_fileno && name.len) {
			ino = find_inode_number(de, &name);
			if (!ino) ino = vdir->d_fileno;

			type = CDT2DT(vdir->d_type);
			ret = filldir(buf, name.name, name.len,
				      coda_file->f_pos, ino, type);
			
			if (ret < 0) break;
			result++;
		}
		coda_file->f_pos += vdir->d_reclen;
	}
out:
	kfree(vdir);
	return result ? result : ret;
}