]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/cifs/dir.c
cifs: have find_readable/writable_file filter by fsuid
[mv-sheeva.git] / fs / cifs / dir.c
index 578d88c5b46e7eae539fb04aede8f59b7c9dac53..e249b561ce8f861d92e1f6dd46b244c50e709b51 100644 (file)
@@ -54,18 +54,18 @@ build_path_from_dentry(struct dentry *direntry)
        int dfsplen;
        char *full_path;
        char dirsep;
-       struct cifs_sb_info *cifs_sb;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
+       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
 
        if (direntry == NULL)
                return NULL;  /* not much we can do if dentry is freed and
                we need to reopen the file after it was closed implicitly
                when the server crashed */
 
-       cifs_sb = CIFS_SB(direntry->d_sb);
        dirsep = CIFS_DIR_SEP(cifs_sb);
        pplen = cifs_sb->prepathlen;
-       if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
-               dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
+       if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
+               dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
        else
                dfsplen = 0;
 cifs_bp_rename_retry:
@@ -117,7 +117,7 @@ cifs_bp_rename_retry:
        /* BB test paths to Windows with '/' in the midst of prepath */
 
        if (dfsplen) {
-               strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
+               strncpy(full_path, tcon->treeName, dfsplen);
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
                        int i;
                        for (i = 0; i < dfsplen; i++) {
@@ -131,28 +131,26 @@ cifs_bp_rename_retry:
 }
 
 struct cifsFileInfo *
-cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
-                 struct file *file, struct vfsmount *mnt, unsigned int oflags)
+cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file,
+                 struct vfsmount *mnt, struct tcon_link *tlink,
+                 unsigned int oflags, __u32 oplock)
 {
-       int oplock = 0;
        struct cifsFileInfo *pCifsFile;
        struct cifsInodeInfo *pCifsInode;
-       struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb);
 
        pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
        if (pCifsFile == NULL)
                return pCifsFile;
 
-       if (oplockEnabled)
-               oplock = REQ_OPLOCK;
-
        pCifsFile->netfid = fileHandle;
        pCifsFile->pid = current->tgid;
+       pCifsFile->uid = current_fsuid();
        pCifsFile->pInode = igrab(newinode);
        pCifsFile->mnt = mnt;
        pCifsFile->pfile = file;
        pCifsFile->invalidHandle = false;
        pCifsFile->closePend = false;
+       pCifsFile->tlink = cifs_get_tlink(tlink);
        mutex_init(&pCifsFile->fh_mutex);
        mutex_init(&pCifsFile->lock_mutex);
        INIT_LIST_HEAD(&pCifsFile->llist);
@@ -160,7 +158,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
        INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
 
        write_lock(&GlobalSMBSeslock);
-       list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
+       list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
        pCifsInode = CIFS_I(newinode);
        if (pCifsInode) {
                /* if readable file instance put first in list*/
@@ -193,6 +191,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
        __u32 posix_flags = 0;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        struct cifs_fattr fattr;
+       struct tcon_link *tlink;
+       struct cifsTconInfo *tcon;
 
        cFYI(1, "posix open %s", full_path);
 
@@ -227,10 +227,20 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
                posix_flags |= SMB_O_DIRECT;
 
        mode &= ~current_umask();
-       rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
-                       pnetfid, presp_data, poplock, full_path,
-                       cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink)) {
+               rc = PTR_ERR(tlink);
+               goto posix_open_ret;
+       }
+
+       tcon = tlink_tcon(tlink);
+       rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
+                            poplock, full_path, cifs_sb->local_nls,
+                            cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
+       cifs_put_tlink(tlink);
+
        if (rc)
                goto posix_open_ret;
 
@@ -291,6 +301,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        int desiredAccess = GENERIC_READ | GENERIC_WRITE;
        __u16 fileHandle;
        struct cifs_sb_info *cifs_sb;
+       struct tcon_link *tlink;
        struct cifsTconInfo *tcon;
        char *full_path = NULL;
        FILE_ALL_INFO *buf = NULL;
@@ -300,14 +311,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        xid = GetXid();
 
        cifs_sb = CIFS_SB(inode->i_sb);
-       tcon = cifs_sb->tcon;
-
-       full_path = build_path_from_dentry(direntry);
-       if (full_path == NULL) {
-               rc = -ENOMEM;
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink)) {
                FreeXid(xid);
-               return rc;
+               return PTR_ERR(tlink);
        }
+       tcon = tlink_tcon(tlink);
 
        if (oplockEnabled)
                oplock = REQ_OPLOCK;
@@ -317,6 +326,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        else
                oflags = FMODE_READ | SMB_O_CREAT;
 
+       full_path = build_path_from_dentry(direntry);
+       if (full_path == NULL) {
+               rc = -ENOMEM;
+               goto cifs_create_out;
+       }
+
        if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
            (CIFS_UNIX_POSIX_PATH_OPS_CAP &
                        le64_to_cpu(tcon->fsUnixInfo.Capability))) {
@@ -365,9 +380,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 
        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
        if (buf == NULL) {
-               kfree(full_path);
-               FreeXid(xid);
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto cifs_create_out;
        }
 
        /*
@@ -377,7 +391,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
                create_options |= CREATE_OPTION_READONLY;
 
-       if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
+       if (tcon->ses->capabilities & CAP_NT_SMBS)
                rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
                         desiredAccess, create_options,
                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
@@ -470,7 +484,8 @@ cifs_create_set_dentry:
                }
 
                pfile_info = cifs_new_fileinfo(newinode, fileHandle, filp,
-                                              nd->path.mnt, oflags);
+                                               nd->path.mnt, tlink, oflags,
+                                               oplock);
                if (pfile_info == NULL) {
                        fput(filp);
                        CIFSSMBClose(xid, tcon, fileHandle);
@@ -483,6 +498,7 @@ cifs_create_set_dentry:
 cifs_create_out:
        kfree(buf);
        kfree(full_path);
+       cifs_put_tlink(tlink);
        FreeXid(xid);
        return rc;
 }
@@ -493,22 +509,35 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
        int rc = -EPERM;
        int xid;
        struct cifs_sb_info *cifs_sb;
+       struct tcon_link *tlink;
        struct cifsTconInfo *pTcon;
        char *full_path = NULL;
        struct inode *newinode = NULL;
+       int oplock = 0;
+       u16 fileHandle;
+       FILE_ALL_INFO *buf = NULL;
+       unsigned int bytes_written;
+       struct win_dev *pdev;
 
        if (!old_valid_dev(device_number))
                return -EINVAL;
 
-       xid = GetXid();
-
        cifs_sb = CIFS_SB(inode->i_sb);
-       pTcon = cifs_sb->tcon;
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+
+       pTcon = tlink_tcon(tlink);
+
+       xid = GetXid();
 
        full_path = build_path_from_dentry(direntry);
-       if (full_path == NULL)
+       if (full_path == NULL) {
                rc = -ENOMEM;
-       else if (pTcon->unix_ext) {
+               goto mknod_out;
+       }
+
+       if (pTcon->unix_ext) {
                struct cifs_unix_set_info_args args = {
                        .mode   = mode & ~current_umask(),
                        .ctime  = NO_CHANGE_64,
@@ -527,88 +556,80 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
                                            cifs_sb->local_nls,
                                            cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
+               if (rc)
+                       goto mknod_out;
 
-               if (!rc) {
-                       rc = cifs_get_inode_info_unix(&newinode, full_path,
+               rc = cifs_get_inode_info_unix(&newinode, full_path,
                                                inode->i_sb, xid);
-                       if (pTcon->nocase)
-                               direntry->d_op = &cifs_ci_dentry_ops;
-                       else
-                               direntry->d_op = &cifs_dentry_ops;
-                       if (rc == 0)
-                               d_instantiate(direntry, newinode);
-               }
-       } else {
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
-                       int oplock = 0;
-                       u16 fileHandle;
-                       FILE_ALL_INFO *buf;
+               if (pTcon->nocase)
+                       direntry->d_op = &cifs_ci_dentry_ops;
+               else
+                       direntry->d_op = &cifs_dentry_ops;
 
-                       cFYI(1, "sfu compat create special file");
+               if (rc == 0)
+                       d_instantiate(direntry, newinode);
+               goto mknod_out;
+       }
 
-                       buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
-                       if (buf == NULL) {
-                               kfree(full_path);
-                               rc = -ENOMEM;
-                               FreeXid(xid);
-                               return rc;
-                       }
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
+               goto mknod_out;
 
-                       rc = CIFSSMBOpen(xid, pTcon, full_path,
-                                        FILE_CREATE, /* fail if exists */
-                                        GENERIC_WRITE /* BB would
-                                         WRITE_OWNER | WRITE_DAC be better? */,
-                                        /* Create a file and set the
-                                           file attribute to SYSTEM */
-                                        CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
-                                        &fileHandle, &oplock, buf,
-                                        cifs_sb->local_nls,
-                                        cifs_sb->mnt_cifs_flags &
-                                           CIFS_MOUNT_MAP_SPECIAL_CHR);
-
-                       /* BB FIXME - add handling for backlevel servers
-                          which need legacy open and check for all
-                          calls to SMBOpen for fallback to SMBLeagcyOpen */
-                       if (!rc) {
-                               /* BB Do not bother to decode buf since no
-                                  local inode yet to put timestamps in,
-                                  but we can reuse it safely */
-                               unsigned int bytes_written;
-                               struct win_dev *pdev;
-                               pdev = (struct win_dev *)buf;
-                               if (S_ISCHR(mode)) {
-                                       memcpy(pdev->type, "IntxCHR", 8);
-                                       pdev->major =
-                                             cpu_to_le64(MAJOR(device_number));
-                                       pdev->minor =
-                                             cpu_to_le64(MINOR(device_number));
-                                       rc = CIFSSMBWrite(xid, pTcon,
-                                               fileHandle,
-                                               sizeof(struct win_dev),
-                                               0, &bytes_written, (char *)pdev,
-                                               NULL, 0);
-                               } else if (S_ISBLK(mode)) {
-                                       memcpy(pdev->type, "IntxBLK", 8);
-                                       pdev->major =
-                                             cpu_to_le64(MAJOR(device_number));
-                                       pdev->minor =
-                                             cpu_to_le64(MINOR(device_number));
-                                       rc = CIFSSMBWrite(xid, pTcon,
-                                               fileHandle,
-                                               sizeof(struct win_dev),
-                                               0, &bytes_written, (char *)pdev,
-                                               NULL, 0);
-                               } /* else if(S_ISFIFO */
-                               CIFSSMBClose(xid, pTcon, fileHandle);
-                               d_drop(direntry);
-                       }
-                       kfree(buf);
-                       /* add code here to set EAs */
-               }
+
+       cFYI(1, "sfu compat create special file");
+
+       buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+       if (buf == NULL) {
+               kfree(full_path);
+               rc = -ENOMEM;
+               FreeXid(xid);
+               return rc;
        }
 
+       /* FIXME: would WRITE_OWNER | WRITE_DAC be better? */
+       rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
+                        GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
+                        &fileHandle, &oplock, buf, cifs_sb->local_nls,
+                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (rc)
+               goto mknod_out;
+
+       /* BB Do not bother to decode buf since no local inode yet to put
+        * timestamps in, but we can reuse it safely */
+
+       pdev = (struct win_dev *)buf;
+       if (S_ISCHR(mode)) {
+               memcpy(pdev->type, "IntxCHR", 8);
+               pdev->major =
+                     cpu_to_le64(MAJOR(device_number));
+               pdev->minor =
+                     cpu_to_le64(MINOR(device_number));
+               rc = CIFSSMBWrite(xid, pTcon,
+                       fileHandle,
+                       sizeof(struct win_dev),
+                       0, &bytes_written, (char *)pdev,
+                       NULL, 0);
+       } else if (S_ISBLK(mode)) {
+               memcpy(pdev->type, "IntxBLK", 8);
+               pdev->major =
+                     cpu_to_le64(MAJOR(device_number));
+               pdev->minor =
+                     cpu_to_le64(MINOR(device_number));
+               rc = CIFSSMBWrite(xid, pTcon,
+                       fileHandle,
+                       sizeof(struct win_dev),
+                       0, &bytes_written, (char *)pdev,
+                       NULL, 0);
+       } /* else if (S_ISFIFO) */
+       CIFSSMBClose(xid, pTcon, fileHandle);
+       d_drop(direntry);
+
+       /* FIXME: add code here to set EAs */
+
+mknod_out:
        kfree(full_path);
+       kfree(buf);
        FreeXid(xid);
+       cifs_put_tlink(tlink);
        return rc;
 }
 
@@ -622,6 +643,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
        __u16 fileHandle = 0;
        bool posix_open = false;
        struct cifs_sb_info *cifs_sb;
+       struct tcon_link *tlink;
        struct cifsTconInfo *pTcon;
        struct cifsFileInfo *cfile;
        struct inode *newInode = NULL;
@@ -636,7 +658,12 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
        /* check whether path exists */
 
        cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
-       pTcon = cifs_sb->tcon;
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink)) {
+               FreeXid(xid);
+               return (struct dentry *)tlink;
+       }
+       pTcon = tlink_tcon(tlink);
 
        /*
         * Don't allow the separator character in a path component.
@@ -647,8 +674,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
                for (i = 0; i < direntry->d_name.len; i++)
                        if (direntry->d_name.name[i] == '\\') {
                                cFYI(1, "Invalid file name");
-                               FreeXid(xid);
-                               return ERR_PTR(-EINVAL);
+                               rc = -EINVAL;
+                               goto lookup_out;
                        }
        }
 
@@ -658,7 +685,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
         */
        if (nd && (nd->flags & LOOKUP_EXCL)) {
                d_instantiate(direntry, NULL);
-               return NULL;
+               rc = 0;
+               goto lookup_out;
        }
 
        /* can not grab the rename sem here since it would
@@ -666,8 +694,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
        in which we already have the sb rename sem */
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
-               FreeXid(xid);
-               return ERR_PTR(-ENOMEM);
+               rc = -ENOMEM;
+               goto lookup_out;
        }
 
        if (direntry->d_inode != NULL) {
@@ -731,8 +759,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
                        }
 
                        cfile = cifs_new_fileinfo(newInode, fileHandle, filp,
-                                                 nd->path.mnt,
-                                                 nd->intent.open.flags);
+                                                 nd->path.mnt, tlink,
+                                                 nd->intent.open.flags,
+                                                 oplock);
                        if (cfile == NULL) {
                                fput(filp);
                                CIFSSMBClose(xid, pTcon, fileHandle);
@@ -762,6 +791,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 
 lookup_out:
        kfree(full_path);
+       cifs_put_tlink(tlink);
        FreeXid(xid);
        return ERR_PTR(rc);
 }