summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsproto.h6
-rw-r--r--fs/cifs/cifssmb.c43
-rw-r--r--fs/cifs/inode.c64
-rw-r--r--fs/cifs/readdir.c2
-rw-r--r--fs/cifs/smb1ops.c6
5 files changed, 80 insertions, 41 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 09ea6321c55a..5144e9fbeb8c 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -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,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 88bbb3ef95b3..76d0d2998850 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -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);
}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 3d155875f446..afdff79651f1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -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 &&
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index b0f4a428398d..f9b5d3d6cf33 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -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)
{
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 42dccbb57c40..56cc4be87807 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -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