コード例 #1
0
ファイル: checker.cpp プロジェクト: scoiatael/Czero
 int check_statement(ast::abstract::Statement* statement) {
     assert(statement != nullptr);
     switch(*statement) {
     case ast::ReturnNode:
         return check_return(dynamic_cast<ast::Return*>(statement));
         break;
     case ast::BranchNode:
         return check_branch(dynamic_cast<ast::Branch*>(statement));
         break;
     case ast::AssignmentNode:
         return check_assignment(dynamic_cast<ast::Assignment*>(statement));
         break;
     case ast::WhileNode:
         return check_while(dynamic_cast<ast::While*>(statement));
         break;
     case ast::VoidContextNode:
         return check_void_context(dynamic_cast<ast::VoidContext*>(statement));
         break;
     }
     assert(false);
     return EXIT_SUCCESS;
 }
コード例 #2
0
ファイル: branchman.c プロジェクト: BackupTheBerlios/dss-svn
int unionfs_ioctl_addbranch(struct inode *inode, unsigned int cmd,
			    unsigned long arg)
{
	int err;
	struct unionfs_addbranch_args *addargs = NULL;
	struct nameidata nd;
	char *path = NULL;
	int gen;
	int i;
	int count;

	int pobjects;

	struct vfsmount **new_hidden_mnt = NULL;
	struct inode **new_uii_inode = NULL;
	struct dentry **new_udi_dentry = NULL;
	struct super_block **new_usi_sb = NULL;
	int *new_branchperms = NULL;
	atomic_t *new_counts = NULL;

	print_entry_location();

	err = -ENOMEM;
	addargs = KMALLOC(sizeof(struct unionfs_addbranch_args), GFP_UNIONFS);
	if (!addargs)
		goto out;

	err = -EFAULT;
	if (copy_from_user
	    (addargs, (void *)arg, sizeof(struct unionfs_addbranch_args)))
		goto out;

	err = -EINVAL;
	if (addargs->ab_perms & ~(MAY_READ | MAY_WRITE))
		goto out;
	if (!(addargs->ab_perms & MAY_READ))
		goto out;

	err = -E2BIG;
	if (sbend(inode->i_sb) > FD_SETSIZE)
		goto out;

	err = -ENOMEM;
	if (!(path = getname(addargs->ab_path)))
		goto out;

	err = path_lookup(path, LOOKUP_FOLLOW, &nd);

	RECORD_PATH_LOOKUP(&nd);
	if (err)
		goto out;
	if ((err = check_branch(&nd))) {
		path_release(&nd);
		RECORD_PATH_RELEASE(&nd);
		goto out;
	}

	unionfs_write_lock(inode->i_sb);
	lock_dentry(inode->i_sb->s_root);

	err = -EINVAL;
	if (addargs->ab_branch < 0
	    || (addargs->ab_branch > (sbend(inode->i_sb) + 1)))
		goto out;

	if ((err = newputmap(inode->i_sb)))
		goto out;

	stopd(inode->i_sb)->b_end++;
	dtopd(inode->i_sb->s_root)->udi_bcount++;
	set_dbend(inode->i_sb->s_root, dbend(inode->i_sb->s_root) + 1);
	itopd(inode->i_sb->s_root->d_inode)->b_end++;

	atomic_inc(&stopd(inode->i_sb)->usi_generation);
	gen = atomic_read(&stopd(inode->i_sb)->usi_generation);

	pobjects = (sbend(inode->i_sb) + 1) - UNIONFS_INLINE_OBJECTS;
	if (pobjects > 0) {
		/* Reallocate the dynamic structures. */
		new_hidden_mnt =
		    KMALLOC(sizeof(struct vfsmount *) * pobjects, GFP_UNIONFS);
		new_udi_dentry =
		    KMALLOC(sizeof(struct dentry *) * pobjects, GFP_UNIONFS);
		new_uii_inode =
		    KMALLOC(sizeof(struct inode *) * pobjects, GFP_UNIONFS);
		new_usi_sb =
		    KMALLOC(sizeof(struct super_block *) * pobjects,
			    GFP_UNIONFS);
		new_counts = KMALLOC(sizeof(atomic_t) * pobjects, GFP_UNIONFS);
		new_branchperms = KMALLOC(sizeof(int) * pobjects, GFP_UNIONFS);
		if (!new_hidden_mnt || !new_udi_dentry || !new_uii_inode
		    || !new_counts || !new_usi_sb || !new_branchperms) {
			err = -ENOMEM;
			goto out;
		}
		memset(new_hidden_mnt, 0, sizeof(struct vfsmount *) * pobjects);
		memset(new_udi_dentry, 0, sizeof(struct dentry *) * pobjects);
		memset(new_uii_inode, 0, sizeof(struct inode *) * pobjects);
		memset(new_usi_sb, 0, sizeof(struct super_block *) * pobjects);
		memset(new_branchperms, 0, sizeof(int) * pobjects);
	}

	/* Copy the in-place values to our new structure. */
	for (i = UNIONFS_INLINE_OBJECTS; i < addargs->ab_branch; i++) {
		int j = i - UNIONFS_INLINE_OBJECTS;

		count = branch_count(inode->i_sb, i);
		atomic_set(&(new_counts[j]), count);

		new_branchperms[j] = branchperms(inode->i_sb, i);
		new_hidden_mnt[j] = stohiddenmnt_index(inode->i_sb, i);

		new_usi_sb[j] = stohs_index(inode->i_sb, i);
		new_udi_dentry[j] = dtohd_index(inode->i_sb->s_root, i);
		new_uii_inode[j] = itohi_index(inode->i_sb->s_root->d_inode, i);
	}

	/* Shift the ends to the right (only handle reallocated bits). */
	for (i = sbend(inode->i_sb) - 1; i >= (int)addargs->ab_branch; i--) {
		int j = i + 1;
		int perms;
		struct vfsmount *hm;
		struct super_block *hs;
		struct dentry *hd;
		struct inode *hi;
		int pmindex;

		count = branch_count(inode->i_sb, i);
		perms = branchperms(inode->i_sb, i);
		hm = stohiddenmnt_index(inode->i_sb, i);
		hs = stohs_index(inode->i_sb, i);
		hd = dtohd_index(inode->i_sb->s_root, i);
		hi = itohi_index(inode->i_sb->s_root->d_inode, i);

		/* Update the newest putmap, so it is correct for later. */
		pmindex = stopd(inode->i_sb)->usi_lastputmap;
		pmindex -= stopd(inode->i_sb)->usi_firstputmap;
		stopd(inode->i_sb)->usi_putmaps[pmindex]->map[i] = j;

		if (j >= UNIONFS_INLINE_OBJECTS) {
			j -= UNIONFS_INLINE_OBJECTS;
			atomic_set(&(new_counts[j]), count);
			new_branchperms[j] = perms;
			new_hidden_mnt[j] = hm;
			new_usi_sb[j] = hs;
			new_udi_dentry[j] = hd;
			new_uii_inode[j] = hi;
		} else {
			set_branch_count(inode->i_sb, j, count);
			set_branchperms(inode->i_sb, j, perms);
			set_stohiddenmnt_index(inode->i_sb, j, hm);
			set_stohs_index(inode->i_sb, j, hs);
			set_dtohd_index(inode->i_sb->s_root, j, hd);
			set_itohi_index(inode->i_sb->s_root->d_inode, j, hi);
		}
	}

	/* Now we can free the old ones. */
	KFREE(dtopd(inode->i_sb->s_root)->udi_dentry_p);
	KFREE(itopd(inode->i_sb->s_root->d_inode)->uii_inode_p);
	KFREE(stopd(inode->i_sb)->usi_hidden_mnt_p);
	KFREE(stopd(inode->i_sb)->usi_sb_p);
	KFREE(stopd(inode->i_sb)->usi_sbcount_p);
	KFREE(stopd(inode->i_sb)->usi_branchperms_p);

	/* Update the real pointers. */
	dtohd_ptr(inode->i_sb->s_root) = new_udi_dentry;
	itohi_ptr(inode->i_sb->s_root->d_inode) = new_uii_inode;
	stohiddenmnt_ptr(inode->i_sb) = new_hidden_mnt;
	stohs_ptr(inode->i_sb) = new_usi_sb;
	stopd(inode->i_sb)->usi_sbcount_p = new_counts;
	stopd(inode->i_sb)->usi_branchperms_p = new_branchperms;

	/* Re-NULL the new ones so we don't try to free them. */
	new_hidden_mnt = NULL;
	new_udi_dentry = NULL;
	new_usi_sb = NULL;
	new_uii_inode = NULL;
	new_counts = NULL;
	new_branchperms = NULL;

	/* Put the new dentry information into it's slot. */
	set_dtohd_index(inode->i_sb->s_root, addargs->ab_branch, nd.dentry);
	set_itohi_index(inode->i_sb->s_root->d_inode, addargs->ab_branch,
			igrab(nd.dentry->d_inode));
	set_branchperms(inode->i_sb, addargs->ab_branch, addargs->ab_perms);
	set_branch_count(inode->i_sb, addargs->ab_branch, 0);
	set_stohiddenmnt_index(inode->i_sb, addargs->ab_branch, nd.mnt);
	set_stohs_index(inode->i_sb, addargs->ab_branch, nd.dentry->d_sb);

	atomic_set(&dtopd(inode->i_sb->s_root)->udi_generation, gen);
	atomic_set(&itopd(inode->i_sb->s_root->d_inode)->uii_generation, gen);

	fixputmaps(inode->i_sb);

      out:
	unlock_dentry(inode->i_sb->s_root);
	unionfs_write_unlock(inode->i_sb);

	KFREE(new_hidden_mnt);
	KFREE(new_udi_dentry);
	KFREE(new_uii_inode);
	KFREE(new_usi_sb);
	KFREE(new_counts);
	KFREE(new_branchperms);
	KFREE(addargs);
	if (path)
		putname(path);

	print_exit_status(err);

	return err;
}
コード例 #3
0
ファイル: main.c プロジェクト: mrtos/Logitech-Revue
/*
 * parse the dirs= mount argument
 *
 * We don't need to lock the superblock private data's rwsem, as we get
 * called only by unionfs_read_super - it is still a long time before anyone
 * can even get a reference to us.
 */
static int parse_dirs_option(struct super_block *sb, struct unionfs_dentry_info
                             *lower_root_info, char *options)
{
    struct nameidata nd;
    char *name;
    int err = 0;
    int branches = 1;
    int bindex = 0;
    int i = 0;
    int j = 0;
    struct dentry *dent1;
    struct dentry *dent2;

    if (options[0] == '\0') {
        printk(KERN_ERR "unionfs: no branches specified\n");
        err = -EINVAL;
        goto out;
    }

    /*
     * Each colon means we have a separator, this is really just a rough
     * guess, since strsep will handle empty fields for us.
     */
    for (i = 0; options[i]; i++)
        if (options[i] == ':')
            branches++;

    /* allocate space for underlying pointers to lower dentry */
    UNIONFS_SB(sb)->data =
        kcalloc(branches, sizeof(struct unionfs_data), GFP_KERNEL);
    if (unlikely(!UNIONFS_SB(sb)->data)) {
        err = -ENOMEM;
        goto out;
    }

    lower_root_info->lower_paths =
        kcalloc(branches, sizeof(struct path), GFP_KERNEL);
    if (unlikely(!lower_root_info->lower_paths)) {
        err = -ENOMEM;
        goto out;
    }

    /* now parsing a string such as "b1:b2=rw:b3=ro:b4" */
    branches = 0;
    while ((name = strsep(&options, ":")) != NULL) {
        int perms;
        char *mode = strchr(name, '=');

        if (!name)
            continue;
        if (!*name) {	/* bad use of ':' (extra colons) */
            err = -EINVAL;
            goto out;
        }

        branches++;

        /* strip off '=' if any */
        if (mode)
            *mode++ = '\0';

        err = parse_branch_mode(mode, &perms);
        if (err) {
            printk(KERN_ERR "unionfs: invalid mode \"%s\" for "
                   "branch %d\n", mode, bindex);
            goto out;
        }
        /* ensure that leftmost branch is writeable */
        if (!bindex && !(perms & MAY_WRITE)) {
            printk(KERN_ERR "unionfs: leftmost branch cannot be "
                   "read-only (use \"-o ro\" to create a "
                   "read-only union)\n");
            err = -EINVAL;
            goto out;
        }

        err = path_lookup(name, LOOKUP_FOLLOW, &nd);
        if (err) {
            printk(KERN_ERR "unionfs: error accessing "
                   "lower directory '%s' (error %d)\n",
                   name, err);
            goto out;
        }

        err = check_branch(&nd);
        if (err) {
            printk(KERN_ERR "unionfs: lower directory "
                   "'%s' is not a valid branch\n", name);
            path_release(&nd);
            goto out;
        }

        lower_root_info->lower_paths[bindex].dentry = nd.dentry;
        lower_root_info->lower_paths[bindex].mnt = nd.mnt;

        set_branchperms(sb, bindex, perms);
        set_branch_count(sb, bindex, 0);
        new_branch_id(sb, bindex);

        if (lower_root_info->bstart < 0)
            lower_root_info->bstart = bindex;
        lower_root_info->bend = bindex;
        bindex++;
    }

    if (branches == 0) {
        printk(KERN_ERR "unionfs: no branches specified\n");
        err = -EINVAL;
        goto out;
    }

    BUG_ON(branches != (lower_root_info->bend + 1));

    /*
     * Ensure that no overlaps exist in the branches.
     *
     * This test is required because the Linux kernel has no support
     * currently for ensuring coherency between stackable layers and
     * branches.  If we were to allow overlapping branches, it would be
     * possible, for example, to delete a file via one branch, which
     * would not be reflected in another branch.  Such incoherency could
     * lead to inconsistencies and even kernel oopses.  Rather than
     * implement hacks to work around some of these cache-coherency
     * problems, we prevent branch overlapping, for now.  A complete
     * solution will involve proper kernel/VFS support for cache
     * coherency, at which time we could safely remove this
     * branch-overlapping test.
     */
    for (i = 0; i < branches; i++) {
        dent1 = lower_root_info->lower_paths[i].dentry;
        for (j = i + 1; j < branches; j++) {
            dent2 = lower_root_info->lower_paths[j].dentry;
            if (is_branch_overlap(dent1, dent2)) {
                printk(KERN_ERR "unionfs: branches %d and "
                       "%d overlap\n", i, j);
                err = -EINVAL;
                goto out;
            }
        }
    }

out:
    if (err) {
        for (i = 0; i < branches; i++)
            if (lower_root_info->lower_paths[i].dentry) {
                dput(lower_root_info->lower_paths[i].dentry);
                /* initialize: can't use unionfs_mntput here */
                mntput(lower_root_info->lower_paths[i].mnt);
            }

        kfree(lower_root_info->lower_paths);
        kfree(UNIONFS_SB(sb)->data);

        /*
         * MUST clear the pointers to prevent potential double free if
         * the caller dies later on
         */
        lower_root_info->lower_paths = NULL;
        UNIONFS_SB(sb)->data = NULL;
    }
    return err;
}
コード例 #4
0
static struct wrapfs_dentry_info *wrapfs_parse_options(struct super_block *sb,
							char *options)
{
	struct wrapfs_dentry_info *lower_root_info;
	struct path path;
	struct dentry *dent1, *dent2;
	char *optname;
	int err = 0, branches = 2;
	int dirsfound = 0;
	int i = 0;
	bool is_ldir_present = false;
	bool is_rdir_present = false;

	lower_root_info =
		kzalloc(sizeof(struct wrapfs_dentry_info), GFP_KERNEL);
	if (unlikely(!lower_root_info))
		goto out_error;

	WRAPFS_SB(sb)->data = kcalloc(branches,
				sizeof(struct wrapfs_data), GFP_KERNEL);

	if (unlikely(!WRAPFS_SB(sb)->data)) {
		err = -ENOMEM;
		goto out_return;
	}
	lower_root_info->lower_paths = kcalloc(branches,
				sizeof(struct path), GFP_KERNEL);

	if (unlikely(!lower_root_info->lower_paths)) {
		err = -ENOMEM;
		kfree(WRAPFS_SB(sb)->data);
		WRAPFS_SB(sb)->data = NULL;
		goto out_return;
	}

	while ((optname = strsep(&options, ",")) != NULL) {
		char *optarg;
		if (!optname || !*optname)
			continue;
		optarg = strchr(optname, '=');
		if (optarg)
			*optarg++ = '\0';
		if (!optarg) {
			printk(KERN_ERR "u2fs: %s requires an argument\n",
				optname);
			err = -EINVAL;
			goto out_error;
		}
		if (!strcmp("ldir", optname)) {
			if (++dirsfound > 1) {
				printk(KERN_ERR
					"u2fs: multiple ldirs specified\n");
				err = -EINVAL;
				goto out_error;
			}
			err = kern_path(optarg,
					LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
					&path);
			if (err) {
				printk(KERN_ERR "u2fs: error accessing "
						"lower directory '%s'\n",
					optarg);
				goto out_error;
			}

			err = check_branch(&path);
			if (err) {
				printk(KERN_ERR "u2fs: lower directory "
						"'%s' is not a valid branch\n",
						optarg);
				path_put(&path);
				goto out_error;
			}

			lower_root_info->lower_paths[0].dentry = path.dentry;
			lower_root_info->lower_paths[0].mnt = path.mnt;

			WRAPFS_SB(sb)->data[0].branchperms =
					MAY_READ|MAY_WRITE;
			set_branch_count(sb, 0, 0);
			new_branch_id(sb, 0);

			is_ldir_present = true;
			continue;
		}
		if (!strcmp("rdir", optname)) {
			if (!is_ldir_present)
				printk(KERN_ERR "u2fs: ldir not specified\n");
			if (++dirsfound > 2) {
				printk(KERN_ERR
					"u2fs: multiple rdirs specified\n");
				err = -EINVAL;
				goto out_error;
			}
			err = kern_path(optarg,
				LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
				&path);
			if (err) {
				printk(KERN_ERR "u2fs: error accessing "
						"lower directory '%s'\n",
						optarg);
				goto out_error;
			}
			lower_root_info->lower_paths[1].dentry = path.dentry;
			lower_root_info->lower_paths[1].mnt = path.mnt;

			WRAPFS_SB(sb)->data[1].branchperms = MAY_READ;
			set_branch_count(sb, 1, 0);
			new_branch_id(sb, 1);

			is_rdir_present = true;
			continue;
		}
		err = -EINVAL;
		printk(KERN_ERR "u2fs: unrecognized options '%s'\n", optname);
		goto out_error;
	}
	if (is_ldir_present && is_rdir_present) {
		/* Ensuring no overlaps */
		dent1 = lower_root_info->lower_paths[0].dentry;
		dent2 = lower_root_info->lower_paths[1].dentry;
		if (is_branch_overlap(dent1, dent2)) {
			printk(KERN_ERR "u2fs:"
			"branches ldir and rdir overlap\n");
			err = -EINVAL;
			goto out_error;
		}
	} else {
		printk(KERN_ERR "u2fs: no branches specified\n");
		err = -EINVAL;
		goto out_error;
		}
	goto out_return;
out_error:
	if (lower_root_info && lower_root_info->lower_paths) {
		for (i = 0; i < branches; i++)
			path_put(&lower_root_info->lower_paths[i]);

		kfree(lower_root_info->lower_paths);
		kfree(lower_root_info);
		kfree(WRAPFS_SB(sb)->data);
		lower_root_info->lower_paths = NULL;
		WRAPFS_SB(sb)->data = NULL;
		lower_root_info = ERR_PTR(err);
	}
out_return:
	return lower_root_info;
}
コード例 #5
0
int unionfs_ioctl_addbranch(struct inode *inode, unsigned int cmd,
			    unsigned long arg)
{
	int err;
	struct unionfs_addbranch_args *addargs = NULL;
	struct nameidata nd;
	char *path = NULL;
	int gen;
	int i;

	int pobjects;

	struct unionfs_usi_data *new_data = NULL;
	struct dentry **new_udi_dentry = NULL;
	struct inode **new_uii_inode = NULL;

	struct dentry *root = NULL;
	struct dentry *hidden_root = NULL;

	print_entry_location();

	err = -ENOMEM;
	addargs = KMALLOC(sizeof(struct unionfs_addbranch_args), GFP_KERNEL);
	if (!addargs)
		goto out;

	err = -EFAULT;
	if (copy_from_user
	    (addargs, (const void __user *)arg,
	     sizeof(struct unionfs_addbranch_args)))
		goto out;

	err = -EINVAL;
	if (addargs->ab_perms & ~(MAY_READ | MAY_WRITE | MAY_NFSRO))
		goto out;
	if (!(addargs->ab_perms & MAY_READ))
		goto out;

	err = -E2BIG;
	if (sbend(inode->i_sb) > FD_SETSIZE)
		goto out;

	err = -ENOMEM;
	if (!(path = getname((const char __user *)addargs->ab_path)))
		goto out;

	err = path_lookup(path, LOOKUP_FOLLOW, &nd);

	RECORD_PATH_LOOKUP(&nd);
	if (err)
		goto out;
	if ((err = check_branch(&nd))) {
		path_release(&nd);
		RECORD_PATH_RELEASE(&nd);
		goto out;
	}

	unionfs_write_lock(inode->i_sb);
	lock_dentry(inode->i_sb->s_root);

	root = inode->i_sb->s_root;
	for (i = dbstart(inode->i_sb->s_root); i <= dbend(inode->i_sb->s_root);
	     i++) {
		hidden_root = dtohd_index(root, i);
		if (is_branch_overlap(hidden_root, nd.dentry)) {
			err = -EINVAL;
			goto out;
		}
	}

	err = -EINVAL;
	if (addargs->ab_branch < 0
	    || (addargs->ab_branch > (sbend(inode->i_sb) + 1)))
		goto out;

	if ((err = newputmap(inode->i_sb)))
		goto out;

	stopd(inode->i_sb)->b_end++;
	dtopd(inode->i_sb->s_root)->udi_bcount++;
	set_dbend(inode->i_sb->s_root, dbend(inode->i_sb->s_root) + 1);
	itopd(inode->i_sb->s_root->d_inode)->b_end++;

	atomic_inc(&stopd(inode->i_sb)->usi_generation);
	gen = atomic_read(&stopd(inode->i_sb)->usi_generation);

	pobjects = sbend(inode->i_sb) + 1;

	/* Reallocate the dynamic structures. */
	new_data = alloc_new_data(pobjects);
	new_udi_dentry = alloc_new_dentries(pobjects);
	new_uii_inode = KZALLOC(sizeof(struct inode *) * pobjects, GFP_KERNEL);

	if (!new_udi_dentry || !new_uii_inode || !new_data) {
		err = -ENOMEM;
		goto out;
	}

	/* Copy the in-place values to our new structure. */
	for (i = 0; i < addargs->ab_branch; i++) {
		atomic_set(&(new_data[i].sbcount),
			   branch_count(inode->i_sb, i));

		new_data[i].branchperms = branchperms(inode->i_sb, i);
		new_data[i].hidden_mnt = stohiddenmnt_index(inode->i_sb, i);
		new_data[i].sb = stohs_index(inode->i_sb, i);

		new_udi_dentry[i] = dtohd_index(inode->i_sb->s_root, i);
		new_uii_inode[i] = itohi_index(inode->i_sb->s_root->d_inode, i);
	}

	/* Shift the ends to the right (only handle reallocated bits). */
	for (i = sbend(inode->i_sb) - 1; i >= (int)addargs->ab_branch; i--) {
		int j = i + 1;
		int pmindex;

		atomic_set(&new_data[j].sbcount, branch_count(inode->i_sb, i));

		new_data[j].branchperms = branchperms(inode->i_sb, i);
		new_data[j].hidden_mnt = stohiddenmnt_index(inode->i_sb, i);
		new_data[j].sb = stohs_index(inode->i_sb, i);
		new_udi_dentry[j] = dtohd_index(inode->i_sb->s_root, i);
		new_uii_inode[j] = itohi_index(inode->i_sb->s_root->d_inode, i);

		/* Update the newest putmap, so it is correct for later. */
		pmindex = stopd(inode->i_sb)->usi_lastputmap;
		pmindex -= stopd(inode->i_sb)->usi_firstputmap;
		stopd(inode->i_sb)->usi_putmaps[pmindex]->map[i] = j;

	}

	/* Now we can free the old ones. */
	KFREE(dtopd(inode->i_sb->s_root)->udi_dentry);
	KFREE(itopd(inode->i_sb->s_root->d_inode)->uii_inode);
	KFREE(stopd(inode->i_sb)->usi_data);

	/* Update the real pointers. */
	dtohd_ptr(inode->i_sb->s_root) = new_udi_dentry;
	itohi_ptr(inode->i_sb->s_root->d_inode) = new_uii_inode;
	stopd(inode->i_sb)->usi_data = new_data;

	/* Re-NULL the new ones so we don't try to free them. */
	new_data = NULL;
	new_udi_dentry = NULL;
	new_uii_inode = NULL;

	/* Put the new dentry information into it's slot. */
	set_dtohd_index(inode->i_sb->s_root, addargs->ab_branch, nd.dentry);
	set_itohi_index(inode->i_sb->s_root->d_inode, addargs->ab_branch,
			IGRAB(nd.dentry->d_inode));
	set_branchperms(inode->i_sb, addargs->ab_branch, addargs->ab_perms);
	set_branch_count(inode->i_sb, addargs->ab_branch, 0);
	set_stohiddenmnt_index(inode->i_sb, addargs->ab_branch, nd.mnt);
	set_stohs_index(inode->i_sb, addargs->ab_branch, nd.dentry->d_sb);

	atomic_set(&dtopd(inode->i_sb->s_root)->udi_generation, gen);
	atomic_set(&itopd(inode->i_sb->s_root->d_inode)->uii_generation, gen);

	fixputmaps(inode->i_sb);

      out:
	unlock_dentry(inode->i_sb->s_root);
	unionfs_write_unlock(inode->i_sb);

	KFREE(new_udi_dentry);
	KFREE(new_uii_inode);
	KFREE(new_data);
	KFREE(addargs);
	if (path)
		putname(path);

	print_exit_status(err);

	return err;
}
コード例 #6
0
static int parse_dirs_option(struct super_block *sb, struct unionfs_dentry_info
			     *hidden_root_info, char *options)
{
	struct nameidata nd;
	char *name;
	int err = 0;
	int branches = 1;
	int bindex = 0;
	int i = 0;
	int j = 0;

	struct dentry *dent1 = NULL;
	struct dentry *dent2 = NULL;

	if (options[0] == '\0') {
		printk(KERN_WARNING "unionfs: no branches specified\n");
		err = -EINVAL;
		goto out;
	}

	/* Each colon means we have a separator, this is really just a rough
	 * guess, since strsep will handle empty fields for us. */
	for (i = 0; options[i]; i++) {
		if (options[i] == ':')
			branches++;
	}

	/* allocate space for underlying pointers to hidden dentry */
	if (!(stopd(sb)->usi_data = alloc_new_data(branches))) {
		err = -ENOMEM;
		goto out;
	}

	if (!(hidden_root_info->udi_dentry = alloc_new_dentries(branches))) {
		err = -ENOMEM;
		goto out;
	}

	/* now parsing the string b1:b2=rw:b3=ro:b4 */
	branches = 0;
	while ((name = strsep(&options, ":")) != NULL) {
		int perms;

		if (!*name)
			continue;

		branches++;

		/* strip off =rw or =ro if it is specified. */
		perms = parse_branch_mode(name);
		if (!bindex && !(perms & MAY_WRITE)) {
			err = -EINVAL;
			goto out;
		}

		fist_dprint(4, "unionfs: using directory: %s (%c%c%c)\n",
			    name, perms & MAY_READ ? 'r' : '-',
			    perms & MAY_WRITE ? 'w' : '-',
			    perms & MAY_NFSRO ? 'n' : '-');

		err = path_lookup(name, LOOKUP_FOLLOW, &nd);
		RECORD_PATH_LOOKUP(&nd);
		if (err) {
			printk(KERN_WARNING "unionfs: error accessing "
			       "hidden directory '%s' (error %d)\n", name, err);
			goto out;
		}

		if ((err = check_branch(&nd))) {
			printk(KERN_WARNING "unionfs: hidden directory "
			       "'%s' is not a valid branch\n", name);
			path_release(&nd);
			RECORD_PATH_RELEASE(&nd);
			goto out;
		}

		hidden_root_info->udi_dentry[bindex] = nd.dentry;

		set_stohiddenmnt_index(sb, bindex, nd.mnt);
		set_branchperms(sb, bindex, perms);
		set_branch_count(sb, bindex, 0);

		if (hidden_root_info->udi_bstart < 0)
			hidden_root_info->udi_bstart = bindex;
		hidden_root_info->udi_bend = bindex;
		bindex++;
	}

	if (branches == 0) {
		printk(KERN_WARNING "unionfs: no branches specified\n");
		err = -EINVAL;
		goto out;
	}

	BUG_ON(branches != (hidden_root_info->udi_bend + 1));

	/* ensure that no overlaps exist in the branches */
	for (i = 0; i < branches; i++) {
		for (j = i + 1; j < branches; j++) {
			dent1 = hidden_root_info->udi_dentry[i];
			dent2 = hidden_root_info->udi_dentry[j];

			if (is_branch_overlap(dent1, dent2)) {
				goto out_overlap;
			}
		}
	}

      out_overlap:

	if (i != branches) {
		printk(KERN_WARNING "unionfs: branches %d and %d overlap\n", i,
		       j);
		err = -EINVAL;
		goto out;
	}

      out:
	if (err) {
		for (i = 0; i < branches; i++) {
			if (hidden_root_info->udi_dentry[i])
				DPUT(hidden_root_info->udi_dentry[i]);
		}

		KFREE(hidden_root_info->udi_dentry);
		KFREE(stopd(sb)->usi_data);

		/* MUST clear the pointers to prevent potential double free if
		 * the caller dies later on
		 */
		hidden_root_info->udi_dentry = NULL;
		stopd(sb)->usi_data = NULL;
	}
	return err;
}