Пример #1
0
/**
 * nameidata_to_filp - convert a nameidata to an open filp.
 * @nd: pointer to nameidata
 * @flags: open flags
 *
 * Note that this function destroys the original nameidata
 */
struct file *nameidata_to_filp(struct nameidata *nd)
{
	const struct cred *cred = current_cred();
	struct file *filp;

	/* Pick up the filp from the open intent */
	filp = nd->intent.open.file;

	/* Has the filesystem initialised the file for us? */
	if (filp->f_path.dentry != NULL) {
		nd->intent.open.file = NULL;
	} else {
		struct file *res;

		path_get(&nd->path);
		res = do_dentry_open(nd->path.dentry, nd->path.mnt,
				     filp, NULL, cred);
		if (!IS_ERR(res)) {
			int error;

			nd->intent.open.file = NULL;
			BUG_ON(res != filp);

			error = open_check_o_direct(filp);
			if (error) {
				fput(filp);
				filp = ERR_PTR(error);
			}
		} else {
			/* Allow nd->intent.open.file to be recycled */
			filp = res;
		}
	}
	return filp;
}
Пример #2
0
struct file *dentry_open(const struct path *path, int flags,
			 const struct cred *cred)
{
	int error;
	struct file *f;

	validate_creds(cred);

	/* We must always pass in a valid mount pointer. */
	BUG_ON(!path->mnt);

	f = get_empty_filp();
	if (!IS_ERR(f)) {
		f->f_flags = flags;
		f->f_path = *path;
		error = do_dentry_open(f, NULL, cred);
		if (!error) {
			/* from now on we need fput() to dispose of f */
			error = open_check_o_direct(f);
			if (error) {
				fput(f);
				f = ERR_PTR(error);
			}
		} else { 
			put_filp(f);
			f = ERR_PTR(error);
		}
	}
	return f;
}
Пример #3
0
struct file *dentry_open(const struct path *path, int flags,
			 const struct cred *cred)
{
	int error;
	struct file *f;

	validate_creds(cred);

	
	BUG_ON(!path->mnt);

	f = get_empty_filp();
	if (!IS_ERR(f)) {
		f->f_flags = flags;
		f->f_path = *path;
		error = do_dentry_open(f, NULL, cred);
		if (!error) {
			
			error = open_check_o_direct(f);
			if (error) {
				fput(f);
				f = ERR_PTR(error);
			}
		} else { 
			put_filp(f);
			f = ERR_PTR(error);
		}
	}
	return f;
}
Пример #4
0
struct file *dentry_open(const struct path *path, int flags,
			 const struct cred *cred)
{
	int error;
	struct file *f;

	validate_creds(cred);

	/* We must always pass in a valid mount pointer. */
	BUG_ON(!path->mnt);

	error = -ENFILE;
	f = get_empty_filp();
	if (f == NULL)
		return ERR_PTR(error);

	f->f_flags = flags;
	f->f_path = *path;
	error = do_dentry_open(f, NULL, cred);
	if (!error) {
		error = open_check_o_direct(f);
		if (error) {
			fput(f);
			f = ERR_PTR(error);
		}
	} else { 
		put_filp(f);
		f = ERR_PTR(error);
	}
	return f;
}
Пример #5
0
Файл: open.c Проект: krzk/linux
/**
 * vfs_open - open the file at the given path
 * @path: path to open
 * @file: newly allocated file with f_flag initialized
 * @cred: credentials to use
 */
int vfs_open(const struct path *path, struct file *file,
	     const struct cred *cred)
{
	struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags, 0);

	if (IS_ERR(dentry))
		return PTR_ERR(dentry);

	file->f_path = *path;
	return do_dentry_open(file, d_backing_inode(dentry), NULL, cred);
}
Пример #6
0
/**
 * vfs_open - open the file at the given path
 * @path: path to open
 * @filp: newly allocated file with f_flag initialized
 * @cred: credentials to use
 */
int vfs_open(const struct path *path, struct file *filp,
	     const struct cred *cred)
{
	struct inode *inode = path->dentry->d_inode;

	if (inode->i_op->dentry_open)
		return inode->i_op->dentry_open(path->dentry, filp, cred);
	else {
		filp->f_path = *path;
		return do_dentry_open(filp, NULL, cred);
	}
}
Пример #7
0
/**
 * finish_open - finish opening a file
 * @od: opaque open data
 * @dentry: pointer to dentry
 * @open: open callback
 *
 * This can be used to finish opening a file passed to i_op->atomic_open().
 *
 * If the open callback is set to NULL, then the standard f_op->open()
 * filesystem callback is substituted.
 */
int finish_open(struct file *file, struct dentry *dentry,
		int (*open)(struct inode *, struct file *),
		int *opened)
{
	int error;
	BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */

	file->f_path.dentry = dentry;
	error = do_dentry_open(file, open, current_cred());
	if (!error)
		*opened |= FILE_OPENED;

	return error;
}
Пример #8
0
/**
 * vfs_open - open the file at the given path
 * @path: path to open
 * @file: newly allocated file with f_flag initialized
 * @cred: credentials to use
 */
int vfs_open(const struct path *path, struct file *file,
	     const struct cred *cred)
{
	struct dentry *dentry = path->dentry;
	struct inode *inode = dentry->d_inode;

	file->f_path = *path;
	if (dentry->d_flags & DCACHE_OP_SELECT_INODE) {
		inode = dentry->d_op->d_select_inode(dentry, file->f_flags);
		if (IS_ERR(inode))
			return PTR_ERR(inode);
	}

	return do_dentry_open(file, inode, NULL, cred);
}
Пример #9
0
static struct file *__dentry_open(struct path *path, struct file *f,
				int (*open)(struct inode *, struct file *),
				const struct cred *cred)
{
	struct file *res = do_dentry_open(path, f, open, cred);
	if (!IS_ERR(res)) {
		int error = open_check_o_direct(f);
		if (error) {
			fput(res);
			res = ERR_PTR(error);
		}
	} else {
		put_filp(f);
	}
	return res;
}
Пример #10
0
/**
 * vfs_open - open the file at the given path
 * @path: path to open
 * @filp: newly allocated file with f_flag initialized
 * @cred: credentials to use
 */
int vfs_open(const struct path *path, struct file *filp,
	     const struct cred *cred)
{
	struct inode *inode = path->dentry->d_inode;
	int err;

	if (inode->i_op->dentry_open) {
		err = inode->i_op->dentry_open(path->dentry, filp, cred);
		if (!err && filp->f_path.dentry != path->dentry) {
			filp->f_covering_path = *path;
			path_get(&filp->f_covering_path);
		}
	} else {
		filp->f_path = *path;
		err = do_dentry_open(filp, NULL, cred);
	}
	return err;
}
Пример #11
0
/**
 * lookup_instantiate_filp - instantiates the open intent filp
 * @nd: pointer to nameidata
 * @dentry: pointer to dentry
 * @open: open callback
 *
 * Helper for filesystems that want to use lookup open intents and pass back
 * a fully instantiated struct file to the caller.
 * This function is meant to be called from within a filesystem's
 * lookup method.
 * Beware of calling it for non-regular files! Those ->open methods might block
 * (e.g. in fifo_open), leaving you with parent locked (and in case of fifo,
 * leading to a deadlock, as nobody can open that fifo anymore, because
 * another process to open fifo will block on locked parent when doing lookup).
 * Note that in case of error, nd->intent.open.file is destroyed, but the
 * path information remains valid.
 * If the open callback is set to NULL, then the standard f_op->open()
 * filesystem callback is substituted.
 */
struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
		int (*open)(struct inode *, struct file *))
{
	struct path path = { .dentry = dentry, .mnt = nd->path.mnt };
	const struct cred *cred = current_cred();

	if (IS_ERR(nd->intent.open.file))
		goto out;
	if (IS_ERR(dentry))
		goto out_err;
	nd->intent.open.file = __dentry_open(&path, nd->intent.open.file,
					     open, cred);
out:
	return nd->intent.open.file;
out_err:
	release_open_intent(nd);
	nd->intent.open.file = ERR_CAST(dentry);
	goto out;
}
EXPORT_SYMBOL_GPL(lookup_instantiate_filp);

/**
 * nameidata_to_filp - convert a nameidata to an open filp.
 * @nd: pointer to nameidata
 * @flags: open flags
 *
 * Note that this function destroys the original nameidata
 */
struct file *nameidata_to_filp(struct nameidata *nd)
{
	const struct cred *cred = current_cred();
	struct file *filp;

	/* Pick up the filp from the open intent */
	filp = nd->intent.open.file;

	/* Has the filesystem initialised the file for us? */
	if (filp->f_path.dentry != NULL) {
		nd->intent.open.file = NULL;
	} else {
		struct file *res;
		struct inode *inode = nd->path.dentry->d_inode;

		if (inode->i_op->open) {
			res = inode->i_op->open(nd->path.dentry, filp, cred);
			if (!IS_ERR(res)) {
				nd->intent.open.file = NULL;
			}
			return res;
		}

		res = do_dentry_open(&nd->path, filp, NULL, cred);
		if (!IS_ERR(res)) {
			int error;

			nd->intent.open.file = NULL;
			BUG_ON(res != filp);

			error = open_check_o_direct(filp);
			if (error) {
				fput(filp);
				filp = ERR_PTR(error);
			}
		} else {
			/* Allow nd->intent.open.file to be recycled */
			filp = res;
		}
	}
	return filp;
}

/*
 * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an
 * error.
 */
struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
			 const struct cred *cred)
{
	struct file *f;
	struct file *ret;
	struct path path = { .dentry = dentry, .mnt = mnt };

	validate_creds(cred);

	/* We must always pass in a valid mount pointer. */
	BUG_ON(!mnt);

	ret = ERR_PTR(-ENFILE);
	f = get_empty_filp();
	if (f != NULL) {
		f->f_flags = flags;
		ret = vfs_open(&path, f, cred);
	}
	path_put(&path);

	return ret;
}
EXPORT_SYMBOL(dentry_open);

/**
 * vfs_open - open the file at the given path
 * @path: path to open
 * @filp: newly allocated file with f_flag initialized
 * @cred: credentials to use
 *
 * Open the file.  If successful, the returned file will have acquired
 * an additional reference for path.
 */
struct file *vfs_open(struct path *path, struct file *filp,
		      const struct cred *cred)
{
	struct inode *inode = path->dentry->d_inode;

	if (inode->i_op->open)
		return inode->i_op->open(path->dentry, filp, cred);
	else
		return __dentry_open(path, filp, NULL, cred);
}
EXPORT_SYMBOL(vfs_open);

static void __put_unused_fd(struct files_struct *files, unsigned int fd)
{
	struct fdtable *fdt = files_fdtable(files);
	__clear_open_fd(fd, fdt);
	if (fd < files->next_fd)
		files->next_fd = fd;
}

void put_unused_fd(unsigned int fd)
{
	struct files_struct *files = current->files;
	spin_lock(&files->file_lock);
	__put_unused_fd(files, fd);
	spin_unlock(&files->file_lock);
}

EXPORT_SYMBOL(put_unused_fd);

/*
 * Install a file pointer in the fd array.
 *
 * The VFS is full of places where we drop the files lock between
 * setting the open_fds bitmap and installing the file in the file
 * array.  At any such point, we are vulnerable to a dup2() race
 * installing a file in the array before us.  We need to detect this and
 * fput() the struct file we are about to overwrite in this case.
 *
 * It should never happen - if we allow dup2() do it, _really_ bad things
 * will follow.
 */

void fd_install(unsigned int fd, struct file *file)
{
	struct files_struct *files = current->files;
	struct fdtable *fdt;
	spin_lock(&files->file_lock);
	fdt = files_fdtable(files);
	BUG_ON(fdt->fd[fd] != NULL);
	rcu_assign_pointer(fdt->fd[fd], file);
	spin_unlock(&files->file_lock);
}

EXPORT_SYMBOL(fd_install);

static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op)
{
	int lookup_flags = 0;
	int acc_mode;

	if (flags & O_CREAT)
		op->mode = (mode & S_IALLUGO) | S_IFREG;
	else
		op->mode = 0;

	/* Must never be set by userspace */
	flags &= ~FMODE_NONOTIFY;

	/*
	 * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only
	 * check for O_DSYNC if the need any syncing at all we enforce it's
	 * always set instead of having to deal with possibly weird behaviour
	 * for malicious applications setting only __O_SYNC.
	 */
	if (flags & __O_SYNC)
		flags |= O_DSYNC;

	/*
	 * If we have O_PATH in the open flag. Then we
	 * cannot have anything other than the below set of flags
	 */
	if (flags & O_PATH) {
		flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;
		acc_mode = 0;
	} else {
		acc_mode = MAY_OPEN | ACC_MODE(flags);
	}

	op->open_flag = flags;

	/* O_TRUNC implies we need access checks for write permissions */
	if (flags & O_TRUNC)
		acc_mode |= MAY_WRITE;

	/* Allow the LSM permission hook to distinguish append
	   access from general write access. */
	if (flags & O_APPEND)
		acc_mode |= MAY_APPEND;

	op->acc_mode = acc_mode;

	op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN;

	if (flags & O_CREAT) {
		op->intent |= LOOKUP_CREATE;
		if (flags & O_EXCL)
			op->intent |= LOOKUP_EXCL;
	}

	if (flags & O_DIRECTORY)
		lookup_flags |= LOOKUP_DIRECTORY;
	if (!(flags & O_NOFOLLOW))
		lookup_flags |= LOOKUP_FOLLOW;
	return lookup_flags;
}