Esempio n. 1
0
/* 向文件发送一个命令,如获取文件信息的命令,
 * 将文件的信息拷贝到arg所指向的内存,如关于文件的flag和版本等信息
 */
int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
		unsigned long arg)
{

	ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg);

	switch (cmd) {
	case EXT2_IOC_GETFLAGS:
		put_fs_long (inode->u.ext2_i.i_flags, (long *) arg);
		return 0;
	case EXT2_IOC_SETFLAGS:
		if ((current->euid != inode->i_uid) && !suser())
			return -EPERM;
		if (IS_RDONLY(inode))
			return -EROFS;
		inode->u.ext2_i.i_flags = get_fs_long ((long *) arg);
		inode->i_ctime = CURRENT_TIME;
		inode->i_dirt = 1;
		return 0;
	case EXT2_IOC_GETVERSION:
		put_fs_long (inode->u.ext2_i.i_version, (long *) arg);
		return 0;
	case EXT2_IOC_SETVERSION:
		if ((current->euid != inode->i_uid) && !suser())
			return -EPERM;
		if (IS_RDONLY(inode))
			return -EROFS;
		inode->u.ext2_i.i_version = get_fs_long ((long *) arg);
		inode->i_ctime = CURRENT_TIME;
		inode->i_dirt = 1;
		return 0;
	default:
		return -EINVAL;
	}
}
Esempio n. 2
0
static int xiafs_readdir(struct inode * inode, 
		       struct file * filp, struct dirent * dirent, int count)
{
    u_int offset, i;
    struct buffer_head * bh;
    struct xiafs_direct * de;

    if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode))
        return -EBADF;
    if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb) - 1) )
        return -EBADF;
    while (filp->f_pos < inode->i_size) {
        offset = filp->f_pos & (XIAFS_ZSIZE(inode->i_sb) - 1);
	bh = xiafs_bread(inode, filp->f_pos >> XIAFS_ZSIZE_BITS(inode->i_sb),0);
	if (!bh) {
	    filp->f_pos += XIAFS_ZSIZE(inode->i_sb)-offset;
	    continue;
	}
	de = (struct xiafs_direct *) (offset + bh->b_data);
	while (offset < XIAFS_ZSIZE(inode->i_sb) && filp->f_pos < inode->i_size) {
	    if (de->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes ||
		de->d_rec_len < 12 || 
		(char *)de+de->d_rec_len > XIAFS_ZSIZE(inode->i_sb)+bh->b_data ||
		de->d_name_len < 1 || de->d_name_len + 8 > de->d_rec_len ||
		de->d_name_len > _XIAFS_NAME_LEN ||
		de->d_name[de->d_name_len] ) {
	        printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR);
		brelse(bh);
		return 0;
	    }  
	    offset += de->d_rec_len;
	    filp->f_pos += de->d_rec_len;
	    if (de->d_ino) {
	        for (i = 0; i < de->d_name_len ; i++)
		    put_fs_byte(de->d_name[i],i+dirent->d_name);
		put_fs_byte(0,i+dirent->d_name);
		put_fs_long(de->d_ino,&dirent->d_ino);
		put_fs_word(i,&dirent->d_reclen);
		brelse(bh);
		if (!IS_RDONLY (inode)) {
		    inode->i_atime=CURRENT_TIME;		    
		    inode->i_dirt=1;
		}
		return i;
	    }
	    de = (struct xiafs_direct *) (offset + bh->b_data);
	}
	brelse(bh);
	if (offset > XIAFS_ZSIZE(inode->i_sb)) {
	    printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
	    return 0;
	}
    }
    if (!IS_RDONLY (inode)) {
	inode->i_atime=CURRENT_TIME;		    
	inode->i_dirt=1;
    }
    return 0;
}
Esempio n. 3
0
int sys_chmod(char *filename, mode_t mode)
{
    struct inode *inode;
    register struct inode *inodep;
    int error = namei(filename, &inode, 0, 0);

#ifdef USE_NOTIFY_CHANGE
    struct iattr newattrs;
    register struct iattr *nap = &newattrs;

    inodep = inode;
    if (error)
	return error;
    if (IS_RDONLY(inodep)) {
	iput(inodep);
	return -EROFS;
    }
    if (mode == (mode_t) - 1)
	mode = inodep->i_mode;
    nap->ia_mode = (mode & S_IALLUGO) | (inodep->i_mode & ~S_IALLUGO);
    nap->ia_valid = ATTR_MODE | ATTR_CTIME;
    inodep->i_dirt = 1;
    error = notify_change(inodep, nap);
    iput(inodep);
#else
    if (!error) {
	inodep = inode;
	if (IS_RDONLY(inodep)) {
	    iput(inodep);
	    return -EROFS;
	}
	if (mode == (mode_t) - 1)
	    mode = inodep->i_mode;
	mode = (mode & S_IALLUGO) | (inodep->i_mode & ~S_IALLUGO);
	if ((current->euid != inodep->i_uid) && !suser()) {
/* FIXME - Should we iput(inodep); at this point? */
	    return -EPERM;
	}
	if (!suser() && !in_group_p(inodep->i_gid)) {
	    mode &= ~S_ISGID;
	}
	inodep->i_mode = mode;
	inodep->i_dirt = 1;
	iput(inodep);
    }
#endif
    return error;
}
Esempio n. 4
0
asmlinkage int sys_chmod(const char * filename, mode_t mode)
{
	struct inode * inode;
	int error;
	struct iattr newattrs;

	error = namei(filename,&inode);
	if (error)
		return error;
	if (IS_RDONLY(inode)) {
		iput(inode);
		return -EROFS;
	}
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
		iput(inode);
		return -EPERM;
	}
	if (mode == (mode_t) -1)
		mode = inode->i_mode;
	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
	inode->i_dirt = 1;
	error = notify_change(inode, &newattrs);
	iput(inode);
	return error;
}
Esempio n. 5
0
/* If times==NULL, set access and modification to current time,
 * must be owner or have write permission.
 * Else, update from *times, must be owner or super user.
 */
asmlinkage int sys_utime(char * filename, struct utimbuf * times)
{
	int error;
	struct inode * inode;
	struct iattr newattrs;

	error = namei(filename,&inode);
	if (error)
		return error;
	if (IS_RDONLY(inode)) {
		iput(inode);
		return -EROFS;
	}
	/* Don't worry, the checks are done in inode_change_ok() */
	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
	if (times) {
		error = verify_area(VERIFY_READ, times, sizeof(*times));
		if (error) {
			iput(inode);
			return error;
		}
		newattrs.ia_atime = get_user(&times->actime);
		newattrs.ia_mtime = get_user(&times->modtime);
		newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
	} else {
		if (current->fsuid != inode->i_uid &&
		    (error = permission(inode,MAY_WRITE)) != 0) {
			iput(inode);
			return error;
		}
	}
	error = notify_change(inode, &newattrs);
	iput(inode);
	return error;
}
Esempio n. 6
0
int sys_truncate(char *path, loff_t length)
{
    struct inode *inode;
    register struct inode *inodep;
    int error;

    error = namei(path, &inode, NOT_DIR, MAY_WRITE);
    inodep = inode;
    if (error)
	return error;
    if (IS_RDONLY(inodep)) {
	iput(inodep);
	return -EROFS;
    }
#ifdef BLOAT_FS
    error = get_write_access(inodep);
    if (error) {
	iput(inodep);
	return error;
    }
#endif
    error = do_truncate(inodep, length);
    put_write_access(inodep);
    iput(inodep);
    return error;
}
Esempio n. 7
0
static int do_chown(register struct inode *inode, uid_t user, gid_t group)
{
    struct iattr newattrs;
    register struct iattr *nap = &newattrs;

    if (IS_RDONLY(inode))
	return -EROFS;
    if (user == (uid_t) - 1)
	user = inode->i_uid;
    if (group == (gid_t) - 1)
	group = inode->i_gid;
    nap->ia_mode = inode->i_mode;
    nap->ia_uid = user;
    nap->ia_gid = group;
    nap->ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;

    /*
     * If the owner has been changed, remove the setuid bit
     */
    if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
	nap->ia_mode &= ~S_ISUID;
	nap->ia_valid |= ATTR_MODE;
    }

    /*
     * If the group has been changed, remove the setgid bit
     */
    if (group != inode->i_gid && (inode->i_mode & S_ISGID)) {
	nap->ia_mode &= ~S_ISGID;
	nap->ia_valid |= ATTR_MODE;
    }

    inode->i_dirt = 1;
    return notify_change(inode, nap);
}
Esempio n. 8
0
static int chown_common(struct _dentry * dentry, uid_t user, gid_t group)
{
	struct _inode * inode;
	int error;
	struct iattr newattrs;

	error = -ENOENT;
	if (!(inode = d_get_inode(dentry))) {
		printk(KERN_ERR "chown_common: NULL inode\n");
		goto out;
	}
	error = -EROFS;
	if (IS_RDONLY(inode))
		goto out;
	error = -EPERM;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		goto out;
	newattrs.ia_valid =  ATTR_CTIME;
	if (user != (uid_t) -1) {
		newattrs.ia_valid |= ATTR_UID;
		newattrs.ia_uid = user;
	}
	if (group != (gid_t) -1) {
		newattrs.ia_valid |= ATTR_GID;
		newattrs.ia_gid = group;
	}
	if (!S_ISDIR(inode->i_mode))
		newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID;
	imutex_lock(parent(inode));
	error = notify_change(dentry, &newattrs);
	imutex_unlock(parent(inode));
out:
	return error;
}
Esempio n. 9
0
STATIC int
xfs_attrmulti_attr_set(
	struct inode		*inode,
	char			*name,
	const char		__user *ubuf,
	__uint32_t		len,
	__uint32_t		flags)
{
	char			*kbuf;
	int			error = EFAULT;

	if (IS_RDONLY(inode))
		return -EROFS;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		return EPERM;
	if (len > XATTR_SIZE_MAX)
		return EINVAL;

	kbuf = memdup_user(ubuf, len);
	if (IS_ERR(kbuf))
		return PTR_ERR(kbuf);

	error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);

	return error;
}
Esempio n. 10
0
struct chan *devopen(struct chan *c, int omode, struct dirtab *tab, int ntab,
                     Devgen * gen)
{
    int i;
    struct dir dir;

    dir.qid.path = 0;
    for (i = 0;; i++) {
        switch ((*gen) (c, NULL, tab, ntab, i, &dir)) {
        case -1:
            goto Return;
        case 0:
            break;
        case 1:
            if (c->qid.path == dir.qid.path) {
                devpermcheck(dir.uid, dir.mode, omode);
                goto Return;
            }
            break;
        }
    }
Return:
    c->offset = 0;
    if ((c->qid.type & QTDIR) && !IS_RDONLY(omode))
        error("Tried opening dir with non-read-only mode %o", omode);
    c->mode = openmode(omode);
    c->flag |= COPEN;
    return c;
}
Esempio n. 11
0
asmlinkage long sys_chmod(const char * filename, mode_t mode)
{
	struct nameidata nd;
	struct inode * inode;
	int error;
	struct iattr newattrs;

	error = user_path_walk(filename, &nd);
	if (error)
		goto out;
	inode = nd.dentry->d_inode;

	error = -EROFS;
	if (IS_RDONLY(inode))
		goto dput_and_out;

	error = -EPERM;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		goto dput_and_out;

	if (mode == (mode_t) -1)
		mode = inode->i_mode;
	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
	error = notify_change(nd.dentry, &newattrs);

dput_and_out:
	path_release(&nd);
out:
	return error;
}
Esempio n. 12
0
int sys_utimes(char *filename, struct timeval *utimes)
{
    int error;
    struct inode *inode;
    register struct inode *inodep;
    struct iattr newattrs;

    error = namei(filename, &inode, 0, 0);
    inodep = inode;
    if (error)
	return error;
    if (IS_RDONLY(inodep)) {
	iput(inodep);
	return -EROFS;
    }
    /* Don't worry, the checks are done in inode_change_ok() */
    newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
    if (utimes) {
	struct timeval times[2];
	if (error = verified_memcpy_fromfs(&times, utimes, sizeof(times))) {
	    iput(inodep);
	    return error;
	}
	newattrs.ia_atime = times[0].tv_sec;
	newattrs.ia_mtime = times[1].tv_sec;
	newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
    } else if ((error = permission(inodep, MAY_WRITE)) != 0) {
	iput(inodep);
	return error;
    }
    error = notify_change(inodep, &newattrs);
    iput(inodep);
    return error;
}
Esempio n. 13
0
STATIC int
xfs_attrmulti_attr_set(
	struct vnode		*vp,
	char			*name,
	const char		__user *ubuf,
	__uint32_t		len,
	__uint32_t		flags)
{
	char			*kbuf;
	int			error = EFAULT;

	if (IS_RDONLY(&vp->v_inode))
		return -EROFS;
	if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode))
		return EPERM;
	if (len > XATTR_SIZE_MAX)
		return EINVAL;

	kbuf = kmalloc(len, GFP_KERNEL);
	if (!kbuf)
		return ENOMEM;

	if (copy_from_user(kbuf, ubuf, len))
		goto out_kfree;
			
	VOP_ATTR_SET(vp, name, kbuf, len, flags, NULL, error);

 out_kfree:
	kfree(kbuf);
	return error;
}
Esempio n. 14
0
asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
			     mode_t mode)
{
	struct nameidata nd;
	struct _inode * inode;
	int error;
	struct iattr newattrs;

	error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
	if (error)
		goto out;
	inode = d_get_inode(nd.dentry);

	error = -EROFS;
	if (IS_RDONLY(inode))
		goto dput_and_out;

	error = -EPERM;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		goto dput_and_out;

	imutex_lock(parent(inode));
	if (mode == (mode_t) -1)
		mode = inode->i_mode;
	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
	error = notify_change(nd.dentry, &newattrs);
	imutex_unlock(parent(inode));

dput_and_out:
	path_release(&nd);
out:
	return error;
}
Esempio n. 15
0
static inline long do_sys_truncate(const char * path, loff_t length)
{
    struct nameidata nd;
    struct inode * inode;
    int error;

    error = -EINVAL;
    if (length < 0)	/* sorry, but loff_t says... */
        goto out;

    error = user_path_walk(path, &nd);
    if (error)
        goto out;
    inode = nd.dentry->d_inode;

    /* For directories it's -EISDIR, for other non-regulars - -EINVAL */
    error = -EISDIR;
    if (S_ISDIR(inode->i_mode))
        goto dput_and_out;

    error = -EINVAL;
    if (!S_ISREG(inode->i_mode))
        goto dput_and_out;

    error = permission(inode,MAY_WRITE);
    if (error)
        goto dput_and_out;

    error = -EROFS;
    if (IS_RDONLY(inode))
        goto dput_and_out;

    error = -EPERM;
    if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
        goto dput_and_out;

    /*
     * Make sure that there are no leases.
     */
    error = get_lease(inode, FMODE_WRITE);
    if (error)
        goto dput_and_out;

    error = get_write_access(inode);
    if (error)
        goto dput_and_out;

    error = locks_verify_truncate(inode, NULL, length);
    if (!error)
    {
        DQUOT_INIT(inode);
        error = do_truncate(nd.dentry, length);
    }
    put_write_access(inode);

dput_and_out:
    path_release(&nd);
out:
    return error;
}
Esempio n. 16
0
asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
{
	struct inode * inode;
	struct dentry * dentry;
	struct file * file;
	int err = -EBADF;
	struct iattr newattrs;

	file = fget(fd);
	if (!file)
		goto out;

	dentry = file->f_dentry;
	inode = dentry->d_inode;

	err = -EROFS;
	if (IS_RDONLY(inode))
		goto out_putf;
	err = -EPERM;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		goto out_putf;
	if (mode == (mode_t) -1)
		mode = inode->i_mode;
	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
	err = notify_change(dentry, &newattrs);

out_putf:
	fput(file);
out:
	return err;
}
Esempio n. 17
0
static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
{
	struct inode * inode;
	int error;
	struct iattr newattrs;

	error = -ENOENT;
	if (!(inode = dentry->d_inode)) {
		printk("chown_common: NULL inode\n");
		goto out;
	}
	error = -EROFS;
	if (IS_RDONLY(inode))
		goto out;
	error = -EPERM;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		goto out;
	if (user == (uid_t) -1)
		user = inode->i_uid;
	if (group == (gid_t) -1)
		group = inode->i_gid;
	newattrs.ia_mode = inode->i_mode;
	newattrs.ia_uid = user;
	newattrs.ia_gid = group;
	newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
	/*
	 * If the user or group of a non-directory has been changed by a
	 * non-root user, remove the setuid bit.
	 * 19981026	David C Niemi <*****@*****.**>
	 *
	 * Changed this to apply to all users, including root, to avoid
	 * some races. This is the behavior we had in 2.0. The check for
	 * non-root was definitely wrong for 2.2 anyway, as it should
	 * have been using CAP_FSETID rather than fsuid -- 19990830 SD.
	 */
	if ((inode->i_mode & S_ISUID) == S_ISUID &&
		!S_ISDIR(inode->i_mode))
	{
		newattrs.ia_mode &= ~S_ISUID;
		newattrs.ia_valid |= ATTR_MODE;
	}
	/*
	 * Likewise, if the user or group of a non-directory has been changed
	 * by a non-root user, remove the setgid bit UNLESS there is no group
	 * execute bit (this would be a file marked for mandatory locking).
	 * 19981026	David C Niemi <*****@*****.**>
	 *
	 * Removed the fsuid check (see the comment above) -- 19990830 SD.
	 */
	if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) 
		&& !S_ISDIR(inode->i_mode))
	{
		newattrs.ia_mode &= ~S_ISGID;
		newattrs.ia_valid |= ATTR_MODE;
	}
	error = DQUOT_TRANSFER(dentry, &newattrs);
out:
	return error;
}
Esempio n. 18
0
/*
 * Truncate a file to 0 length.
 */
static void UMSDOS_truncate (struct inode *inode)
{
    Printk (("UMSDOS_truncate\n"));
    if (!IS_RDONLY (inode)) {
        fat_truncate (inode);
        inode->i_ctime = inode->i_mtime = CURRENT_TIME;
        mark_inode_dirty(inode);
    }
}
Esempio n. 19
0
asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
{
	struct inode * inode;
	int error;
	struct iattr newattrs;

	error = lnamei(filename,&inode);
	if (error)
		return error;
	if (IS_RDONLY(inode)) {
		iput(inode);
		return -EROFS;
	}
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
		iput(inode);
		return -EPERM;
	}
	if (user == (uid_t) -1)
		user = inode->i_uid;
	if (group == (gid_t) -1)
		group = inode->i_gid;
	newattrs.ia_mode = inode->i_mode;
	newattrs.ia_uid = user;
	newattrs.ia_gid = group;
	newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
	/*
	 * If the owner has been changed, remove the setuid bit
	 */
	if (inode->i_mode & S_ISUID) {
		newattrs.ia_mode &= ~S_ISUID;
		newattrs.ia_valid |= ATTR_MODE;
	}
	/*
	 * If the group has been changed, remove the setgid bit
	 *
	 * Don't remove the setgid bit if no group execute bit.
	 * This is a file marked for mandatory locking.
	 */
	if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
		newattrs.ia_mode &= ~S_ISGID;
		newattrs.ia_valid |= ATTR_MODE;
	}
	inode->i_dirt = 1;
	if (inode->i_sb->dq_op) {
		inode->i_sb->dq_op->initialize(inode, -1);
		if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
			return -EDQUOT;
		error = notify_change(inode, &newattrs);
		if (error)
			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
	} else
		error = notify_change(inode, &newattrs);
	iput(inode);
	return(error);
}
Esempio n. 20
0
/*
 * access() needs to use the real uid/gid, not the effective uid/gid.
 * We do this by temporarily clearing all FS-related capabilities and
 * switching the fsuid/fsgid around to the real ones.
 */
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
{
	struct nameidata nd;
	int old_fsuid, old_fsgid;
	kernel_cap_t old_cap;
	int res;
	const struct _inode *inode;

	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
		return -EINVAL;

	old_fsuid = current->fsuid;
	old_fsgid = current->fsgid;
	old_cap = current->cap_effective;

	current->fsuid = current->uid;
	current->fsgid = current->gid;

	/*
	 * Clear the capabilities if we switch to a non-root user
	 *
	 * FIXME: There is a race here against sys_capset.  The
	 * capabilities can change yet we will restore the old
	 * value below.  We should hold task_capabilities_lock,
	 * but we cannot because user_path_walk can sleep.
	 */
	if (current->uid)
		cap_clear(current->cap_effective);
	else
		current->cap_effective = current->cap_permitted;
	
	res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
	if (res)
		goto out;

	inode = d_get_inode_ro(nd.dentry);
	res = vfs_permission(inode, &nd, mode);
	/* SuS v2 requires we report a read only fs too */
	if(res || !(mode & S_IWOTH) ||
	   special_file(inode->i_mode))
		goto out_path_release;

	if(IS_RDONLY(inode))
		res = -EROFS;

out_path_release:
	path_release(&nd);
out:
	current->fsuid = old_fsuid;
	current->fsgid = old_fsgid;
	current->cap_effective = old_cap;
	
	return res;
}
Esempio n. 21
0
STATIC int
xfs_attrmulti_attr_remove(
	struct inode		*inode,
	char			*name,
	__uint32_t		flags)
{
	if (IS_RDONLY(inode))
		return -EROFS;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		return EPERM;
	return xfs_attr_remove(XFS_I(inode), name, flags);
}
Esempio n. 22
0
int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd,
		unsigned long arg)
{
	struct jfs_inode_info *jfs_inode = JFS_IP(inode);
	unsigned int flags;

	switch (cmd) {
	case JFS_IOC_GETFLAGS:
		flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE;
		flags = jfs_map_ext2(flags, 0);
		return put_user(flags, (int __user *) arg);
	case JFS_IOC_SETFLAGS: {
		unsigned int oldflags;

		if (IS_RDONLY(inode))
			return -EROFS;

		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
			return -EACCES;

		if (get_user(flags, (int __user *) arg))
			return -EFAULT;

		flags = jfs_map_ext2(flags, 1);
		if (!S_ISDIR(inode->i_mode))
			flags &= ~JFS_DIRSYNC_FL;

		oldflags = jfs_inode->mode2;

		/*
		 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
		 * the relevant capability.
		 */
		if ((oldflags & JFS_IMMUTABLE_FL) ||
			((flags ^ oldflags) &
			(JFS_APPEND_FL | JFS_IMMUTABLE_FL))) {
			if (!capable(CAP_LINUX_IMMUTABLE))
				return -EPERM;
		}

		flags = flags & JFS_FL_USER_MODIFIABLE;
		flags |= oldflags & ~JFS_FL_USER_MODIFIABLE;
		jfs_inode->mode2 = flags;

		jfs_set_inode_flags(inode);
		inode->i_ctime = CURRENT_TIME_SEC;
		mark_inode_dirty(inode);
		return 0;
	}
	default:
		return -ENOTTY;
	}
}
Esempio n. 23
0
static int
report_statvfs(struct vfsmount *mnt, struct inode *ip, struct sco_statvfs *bufp)
{
	struct sco_statvfs buf;
	struct kstatfs s;
	int error;

#if _KSL < 18
	error = vfs_statfs(mnt->mnt_sb, &s);
#else
	error = vfs_statfs(mnt->mnt_sb->s_root, &s);
#endif
	if (error)
		return error;

	memset(&buf, 0, sizeof(struct sco_statvfs));

	buf.f_bsize	= s.f_bsize;
	buf.f_frsize	= s.f_bsize;
	buf.f_blocks	= s.f_blocks;
	buf.f_bfree	= s.f_bfree;
	buf.f_bavail	= s.f_bavail;
	buf.f_files	= s.f_files;
	buf.f_free	= s.f_ffree;
	buf.f_favail	= s.f_ffree; /* SCO addition in the middle! */
	buf.f_sid	= ip->i_sb->s_dev;

	/*
	 * Get the name of the filesystem.
	 *
	 * Sadly, some code "in the wild" actually checks the name
	 * against a hard coded list to see if it is a "real" fs or not.
	 *
	 * I believe Informix Dynamic Server for SCO is one such.
	 */
	if (strncmp(ip->i_sb->s_type->name, "ext2", 4) == 0)
		strcpy(buf.f_basetype, "HTFS");
	else
		strcpy(buf.f_basetype, ip->i_sb->s_type->name);

	/* Check for a few flags statvfs wants but statfs doesn't have. */
	if (IS_RDONLY(ip))
		buf.f_flag |= 1;
	if (mnt->mnt_flags & MNT_NOSUID)
		buf.f_flag |= 2;

	buf.f_namemax	= s.f_namelen;

	if (copy_to_user(bufp, &buf, sizeof(struct sco_statvfs)))
		return -EFAULT;
	return 0;
}
Esempio n. 24
0
asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
{
	struct inode * inode;
	struct file * file;
	struct iattr newattrs;
	int error;

	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
		return -EBADF;
	if (!(inode = file->f_inode))
		return -ENOENT;
	if (IS_RDONLY(inode))
		return -EROFS;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		return -EPERM;
	if (user == (uid_t) -1)
		user = inode->i_uid;
	if (group == (gid_t) -1)
		group = inode->i_gid;
	newattrs.ia_mode = inode->i_mode;
	newattrs.ia_uid = user;
	newattrs.ia_gid = group;
	newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
	/*
	 * If the owner has been changed, remove the setuid bit
	 */
	if (inode->i_mode & S_ISUID) {
		newattrs.ia_mode &= ~S_ISUID;
		newattrs.ia_valid |= ATTR_MODE;
	}
	/*
	 * If the group has been changed, remove the setgid bit
	 *
	 * Don't remove the setgid bit if no group execute bit.
	 * This is a file marked for mandatory locking.
	 */
	if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
		newattrs.ia_mode &= ~S_ISGID;
		newattrs.ia_valid |= ATTR_MODE;
	}
	inode->i_dirt = 1;
	if (inode->i_sb && inode->i_sb->dq_op) {
		inode->i_sb->dq_op->initialize(inode, -1);
		if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
			return -EDQUOT;
		error = notify_change(inode, &newattrs);
		if (error)
			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
	} else
		error = notify_change(inode, &newattrs);
	return error;
}
Esempio n. 25
0
static long do_write(struct file *file, char *buf, size_t count,
		unsigned long *pos)
{
	if (!(file->f_mode & O_WRITE))
		return -EBADF;
	if (file->f_inode && IS_RDONLY(file->f_inode))
		return -ENOSPC;
	if (!count)
		return 0;
	if (file->f_op && file->f_op->write)
		return file->f_op->write(file, buf, count, pos);
	return -EINVAL;
}
Esempio n. 26
0
struct chan *netifopen(struct ether *nif, struct chan *c, int omode)
{
	int id;
	struct netfile *f;

	id = 0;
	if (c->qid.type & QTDIR) {
		if (!IS_RDONLY(omode))
			error(Eperm);
	} else {
		switch (NETTYPE(c->qid.path)) {
			case Ndataqid:
			case Nctlqid:
				id = NETID(c->qid.path);
				openfile(nif, id);
				break;
			case Ncloneqid:
				id = openfile(nif, -1);
				c->qid.path = NETQID(id, Nctlqid);
				break;
			default:
				if (!IS_RDONLY(omode))
					error(Ebadarg);
		}
		switch (NETTYPE(c->qid.path)) {
			case Ndataqid:
			case Nctlqid:
				f = nif->f[id];
				if (netown(f, current->user, omode & 7) < 0)
					error(Eperm);
				break;
		}
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	c->iounit = qiomaxatomic;
	return c;
}
Esempio n. 27
0
int handle_permission(struct inode *inode, int mask)
{
	int submask;
	umode_t mode = inode->i_mode;

	if (mask & MAY_WRITE) {

		/*
		 * Nobody gets write access to a read-only fs.
		 */
		if (IS_RDONLY(inode) &&
		    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
			return -EROFS;

		/*
		 * Nobody gets write access to an immutable file.
		 */
		if (IS_IMMUTABLE(inode))
			return -EACCES;
	}

	/*
	 * MAY_EXEC on regular files requires special handling: We override
	 * filesystem execute permissions if the mode bits aren't set.
	 */
	if ((mask & MAY_EXEC) && S_ISREG(mode) && !(mode & S_IXUGO))
		return -EACCES;

	/* Ordinary permission routines do not understand MAY_APPEND. */
	submask = mask & ~MAY_APPEND;
#ifdef IN_KERNEL_CHANGE_NOT_SUPP

	/* FIXME! we don't have nameidata for handle lookup. So not sure how
         * we can check for inode->permissions. We already limit the call
         * to CAP_DAC_OVERRIDE. So we should be able to skip the ACL check.
         * But we also skip security_inode_permission below.
         */

	if (inode->i_op && inode->i_op->permission)
		retval = inode->i_op->permission(inode, submask, nd);
	else
		retval = generic_permission(inode, submask, NULL);
	if (retval)
		return retval;

	return security_inode_permission(inode, mask, nd);
#else
        return generic_permission(inode, submask, NULL);
#endif

}
/*
 * test if the branch permission is legal or not.
 */
static int test_br(struct inode *inode, int brperm, char *path)
{
	int err;

	err = (au_br_writable(brperm) && IS_RDONLY(inode));
	if (!err)
		goto out;

	err = -EINVAL;
	pr_err("write permission for readonly mount or inode, %s\n", path);

out:
	return err;
}
Esempio n. 29
0
struct chan *fdtochan(struct fgrp *f, int fd, int mode, int chkmnt, int iref)
{
	
	struct chan *c;

	c = 0;

	spin_lock(&f->lock);
	if (f->closed) {
		spin_unlock(&f->lock);
		error("File group closed");
	}
	if (fd < 0 || f->maxfd < fd || (c = f->fd[fd]) == 0) {
		spin_unlock(&f->lock);
		set_errno(EBADF);
		error("Bad FD %d\n", fd);
	}
	if (iref)
		chan_incref(c);
	spin_unlock(&f->lock);

	if (chkmnt && (c->flag & CMSG)) {
		if (iref)
			cclose(c);
		error(Ebadusefd);
	}

	if (mode < 0 || c->mode == ORDWR) {
		return c;
	}

	if ((mode & OTRUNC) && IS_RDONLY(c->mode)) {
		if (iref)
			cclose(c);
		error(Ebadusefd);
	}

	/* TODO: this is probably wrong.  if you get this from a dev, in the dev's
	 * open, you are probably saving mode directly, without passing it through
	 * openmode. */
	if ((mode & ~OTRUNC) != c->mode) {
		warn("Trunc mode issue: mode %o, mode minus trunc %o, chan mode %o\n",
			 mode, mode & ~OTRUNC, c->mode);
		if (iref)
			cclose(c);
		error(Ebadusefd);
	}

	return c;
}
Esempio n. 30
0
/*
	Read a file into user space memory
*/
static int UMSDOS_file_read(
	struct inode *inode,
	struct file *filp,
	char *buf,
    int count)
{
	/* We have to set the access time because msdos don't care */
	int ret = msdos_file_read(inode,filp,buf,count);
	if (!IS_RDONLY(inode)){
		inode->i_atime = CURRENT_TIME;
		inode->i_dirt = 1;
	}
	return ret;
}