cifs: obtain file access during backup intent lookup (resend)
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>
Fri, 28 Sep 2012 17:21:14 +0000 (12:21 -0500)
committerSteve French <smfrench@gmail.com>
Fri, 28 Sep 2012 20:32:28 +0000 (15:32 -0500)
Rebased and resending the patch.

Path based queries can fail for lack of access, especially during lookup
during open.
open itself would actually succeed becasue of back up intent bit
but queries (either path or file handle based) do not have a means to
specifiy backup intent bit.
So query the file info during lookup using
 trans2 / findfirst / file_id_full_dir_info
to obtain file info as well as file_id/inode value.

Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Acked-by: Jeff Layton <jlayton@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/inode.c
fs/cifs/readdir.c
fs/cifs/smb1ops.c

index 09ea6321c55af4496392b2c9d73ddbde949477ad..5144e9fbeb8cc9d58682dac81b66da81a81a3329 100644 (file)
@@ -140,6 +140,8 @@ void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr);
 extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
                                     FILE_UNIX_BASIC_INFO *info,
                                     struct cifs_sb_info *cifs_sb);
+extern void cifs_dir_info_to_fattr(struct cifs_fattr *, FILE_DIRECTORY_INFO *,
+                                       struct cifs_sb_info *);
 extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
 extern struct inode *cifs_iget(struct super_block *sb,
                               struct cifs_fattr *fattr);
@@ -216,10 +218,10 @@ extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
                    const struct nls_table *);
 
 extern int CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
-               const char *searchName, const struct nls_table *nls_codepage,
+               const char *searchName, struct cifs_sb_info *cifs_sb,
                __u16 *searchHandle, __u16 search_flags,
                struct cifs_search_info *psrch_inf,
-               int map, const char dirsep);
+               bool msearch);
 
 extern int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
                __u16 searchHandle, __u16 search_flags,
index 88bbb3ef95b35ea2d3ba3d1cde66a4bd64a9e089..76d0d29988507625c4d679b00e2a7cf695e86630 100644 (file)
@@ -4214,10 +4214,9 @@ UnixQPathInfoRetry:
 /* xid, tcon, searchName and codepage are input parms, rest are returned */
 int
 CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
-             const char *searchName,
-             const struct nls_table *nls_codepage,
+             const char *searchName, struct cifs_sb_info *cifs_sb,
              __u16 *pnetfid, __u16 search_flags,
-             struct cifs_search_info *psrch_inf, int remap, const char dirsep)
+             struct cifs_search_info *psrch_inf, bool msearch)
 {
 /* level 257 SMB_ */
        TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -4225,8 +4224,9 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
        T2_FFIRST_RSP_PARMS *parms;
        int rc = 0;
        int bytes_returned = 0;
-       int name_len;
+       int name_len, remap;
        __u16 params, byte_count;
+       struct nls_table *nls_codepage;
 
        cFYI(1, "In FindFirst for %s", searchName);
 
@@ -4236,6 +4236,9 @@ findFirstRetry:
        if (rc)
                return rc;
 
+       nls_codepage = cifs_sb->local_nls;
+       remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
+
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
                    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
@@ -4244,24 +4247,29 @@ findFirstRetry:
                it got remapped to 0xF03A as if it were part of the
                directory name instead of a wildcard */
                name_len *= 2;
-               pSMB->FileName[name_len] = dirsep;
-               pSMB->FileName[name_len+1] = 0;
-               pSMB->FileName[name_len+2] = '*';
-               pSMB->FileName[name_len+3] = 0;
-               name_len += 4; /* now the trailing null */
-               pSMB->FileName[name_len] = 0; /* null terminate just in case */
-               pSMB->FileName[name_len+1] = 0;
-               name_len += 2;
+               if (msearch) {
+                       pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
+                       pSMB->FileName[name_len+1] = 0;
+                       pSMB->FileName[name_len+2] = '*';
+                       pSMB->FileName[name_len+3] = 0;
+                       name_len += 4; /* now the trailing null */
+                       /* null terminate just in case */
+                       pSMB->FileName[name_len] = 0;
+                       pSMB->FileName[name_len+1] = 0;
+                       name_len += 2;
+               }
        } else {        /* BB add check for overrun of SMB buf BB */
                name_len = strnlen(searchName, PATH_MAX);
 /* BB fix here and in unicode clause above ie
                if (name_len > buffersize-header)
                        free buffer exit; BB */
                strncpy(pSMB->FileName, searchName, name_len);
-               pSMB->FileName[name_len] = dirsep;
-               pSMB->FileName[name_len+1] = '*';
-               pSMB->FileName[name_len+2] = 0;
-               name_len += 3;
+               if (msearch) {
+                       pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
+                       pSMB->FileName[name_len+1] = '*';
+                       pSMB->FileName[name_len+2] = 0;
+                       name_len += 3;
+               }
        }
 
        params = 12 + name_len /* includes null */ ;
@@ -4349,7 +4357,8 @@ findFirstRetry:
                        psrch_inf->last_entry = psrch_inf->srch_entries_start +
                                                        lnoff;
 
-                       *pnetfid = parms->SearchHandle;
+                       if (pnetfid)
+                               *pnetfid = parms->SearchHandle;
                } else {
                        cifs_buf_release(pSMB);
                }
index 3d155875f44627d22009639f31493eba0a0daaf3..afdff79651f1362c697d8f5d755aa4d3a6c66655 100644 (file)
@@ -607,7 +607,9 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
                    FILE_ALL_INFO *data, struct super_block *sb, int xid,
                    const __u16 *fid)
 {
-       int rc = 0, tmprc;
+       bool validinum = false;
+       __u16 srchflgs;
+       int rc = 0, tmprc = ENOSYS;
        struct cifs_tcon *tcon;
        struct TCP_Server_Info *server;
        struct tcon_link *tlink;
@@ -615,6 +617,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
        char *buf = NULL;
        bool adjust_tz = false;
        struct cifs_fattr fattr;
+       struct cifs_search_info *srchinf = NULL;
 
        tlink = cifs_sb_tlink(cifs_sb);
        if (IS_ERR(tlink))
@@ -653,9 +656,38 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
        } else if (rc == -EREMOTE) {
                cifs_create_dfs_fattr(&fattr, sb);
                rc = 0;
-       } else {
+       } else if (rc == -EACCES && backup_cred(cifs_sb)) {
+                       srchinf = kzalloc(sizeof(struct cifs_search_info),
+                                               GFP_KERNEL);
+                       if (srchinf == NULL) {
+                               rc = -ENOMEM;
+                               goto cgii_exit;
+                       }
+
+                       srchinf->endOfSearch = false;
+                       srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
+
+                       srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
+                                       CIFS_SEARCH_CLOSE_AT_END |
+                                       CIFS_SEARCH_BACKUP_SEARCH;
+
+                       rc = CIFSFindFirst(xid, tcon, full_path,
+                               cifs_sb, NULL, srchflgs, srchinf, false);
+                       if (!rc) {
+                               data =
+                               (FILE_ALL_INFO *)srchinf->srch_entries_start;
+
+                               cifs_dir_info_to_fattr(&fattr,
+                               (FILE_DIRECTORY_INFO *)data, cifs_sb);
+                               fattr.cf_uniqueid = le64_to_cpu(
+                               ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
+                               validinum = true;
+
+                               cifs_buf_release(srchinf->ntwrk_buf_start);
+                       }
+                       kfree(srchinf);
+       } else
                goto cgii_exit;
-       }
 
        /*
         * If an inode wasn't passed in, then get the inode number
@@ -666,23 +698,21 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
         */
        if (*inode == NULL) {
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
-                       if (server->ops->get_srv_inum)
-                               tmprc = server->ops->get_srv_inum(xid, tcon,
-                                       cifs_sb, full_path, &fattr.cf_uniqueid,
-                                       data);
-                       else
-                               tmprc = -ENOSYS;
-                       if (tmprc || !fattr.cf_uniqueid) {
-                               cFYI(1, "GetSrvInodeNum rc %d", tmprc);
-                               fattr.cf_uniqueid = iunique(sb, ROOT_I);
-                               cifs_autodisable_serverino(cifs_sb);
+                       if (validinum == false) {
+                               if (server->ops->get_srv_inum)
+                                       tmprc = server->ops->get_srv_inum(xid,
+                                               tcon, cifs_sb, full_path,
+                                               &fattr.cf_uniqueid, data);
+                               if (tmprc) {
+                                       cFYI(1, "GetSrvInodeNum rc %d", tmprc);
+                                       fattr.cf_uniqueid = iunique(sb, ROOT_I);
+                                       cifs_autodisable_serverino(cifs_sb);
+                               }
                        }
-               } else {
+               } else
                        fattr.cf_uniqueid = iunique(sb, ROOT_I);
-               }
-       } else {
+       } else
                fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
-       }
 
        /* query for SFU type info if supported and needed */
        if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
index b0f4a428398de6dbd8f6b47118361dd1e257e4bc..f9b5d3d6cf33461081f4945d61a5d604fe2ef468 100644 (file)
@@ -151,7 +151,7 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
        }
 }
 
-static void
+void
 cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
                       struct cifs_sb_info *cifs_sb)
 {
index 42dccbb57c40e46d00ee57a9c900664a5822328e..56cc4be87807ae2c734b647c5c78d5480d234e7b 100644 (file)
@@ -837,10 +837,8 @@ cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
                     struct cifs_fid *fid, __u16 search_flags,
                     struct cifs_search_info *srch_inf)
 {
-       return CIFSFindFirst(xid, tcon, path, cifs_sb->local_nls,
-                            &fid->netfid, search_flags, srch_inf,
-                            cifs_sb->mnt_cifs_flags &
-                            CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
+       return CIFSFindFirst(xid, tcon, path, cifs_sb,
+                            &fid->netfid, search_flags, srch_inf, true);
 }
 
 static int