aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsglob.h3
-rw-r--r--fs/cifs/cifsproto.h12
-rw-r--r--fs/cifs/cifssmb.c60
-rw-r--r--fs/cifs/connect.c31
-rw-r--r--fs/cifs/smb1ops.c25
5 files changed, 69 insertions, 62 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index acfa68569f3d..f711d666e3db 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -215,6 +215,9 @@ struct smb_version_operations {
215 unsigned int *, const struct nls_table *, int); 215 unsigned int *, const struct nls_table *, int);
216 /* informational QFS call */ 216 /* informational QFS call */
217 void (*qfs_tcon)(const unsigned int, struct cifs_tcon *); 217 void (*qfs_tcon)(const unsigned int, struct cifs_tcon *);
218 /* check if a path is accessible or not */
219 int (*is_path_accessible)(const unsigned int, struct cifs_tcon *,
220 struct cifs_sb_info *, const char *);
218}; 221};
219 222
220struct smb_version_values { 223struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 4857965b22db..b9967adeaa9e 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -208,14 +208,12 @@ extern int CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
208extern int CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, 208extern int CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
209 u16 netfid, FILE_ALL_INFO *pFindData); 209 u16 netfid, FILE_ALL_INFO *pFindData);
210extern int CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, 210extern int CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
211 const unsigned char *searchName, 211 const char *search_Name, FILE_ALL_INFO *data,
212 FILE_ALL_INFO *findData, 212 int legacy /* whether to use old info level */,
213 int legacy /* whether to use old info level */, 213 const struct nls_table *nls_codepage, int remap);
214 const struct nls_table *nls_codepage, int remap);
215extern int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon, 214extern int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
216 const unsigned char *searchName, 215 const char *search_name, FILE_ALL_INFO *data,
217 FILE_ALL_INFO *findData, 216 const struct nls_table *nls_codepage, int remap);
218 const struct nls_table *nls_codepage, int remap);
219 217
220extern int CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, 218extern int CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
221 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData); 219 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index af859c325db1..84a53380e124 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3853,10 +3853,10 @@ setCifsAclRetry:
3853 3853
3854/* Legacy Query Path Information call for lookup to old servers such 3854/* Legacy Query Path Information call for lookup to old servers such
3855 as Win9x/WinME */ 3855 as Win9x/WinME */
3856int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon, 3856int
3857 const unsigned char *searchName, 3857SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3858 FILE_ALL_INFO *pFinfo, 3858 const char *search_name, FILE_ALL_INFO *data,
3859 const struct nls_table *nls_codepage, int remap) 3859 const struct nls_table *nls_codepage, int remap)
3860{ 3860{
3861 QUERY_INFORMATION_REQ *pSMB; 3861 QUERY_INFORMATION_REQ *pSMB;
3862 QUERY_INFORMATION_RSP *pSMBr; 3862 QUERY_INFORMATION_RSP *pSMBr;
@@ -3864,7 +3864,7 @@ int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3864 int bytes_returned; 3864 int bytes_returned;
3865 int name_len; 3865 int name_len;
3866 3866
3867 cFYI(1, "In SMBQPath path %s", searchName); 3867 cFYI(1, "In SMBQPath path %s", search_name);
3868QInfRetry: 3868QInfRetry:
3869 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB, 3869 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3870 (void **) &pSMBr); 3870 (void **) &pSMBr);
@@ -3874,14 +3874,14 @@ QInfRetry:
3874 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 3874 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3875 name_len = 3875 name_len =
3876 cifsConvertToUTF16((__le16 *) pSMB->FileName, 3876 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3877 searchName, PATH_MAX, nls_codepage, 3877 search_name, PATH_MAX, nls_codepage,
3878 remap); 3878 remap);
3879 name_len++; /* trailing null */ 3879 name_len++; /* trailing null */
3880 name_len *= 2; 3880 name_len *= 2;
3881 } else { 3881 } else {
3882 name_len = strnlen(searchName, PATH_MAX); 3882 name_len = strnlen(search_name, PATH_MAX);
3883 name_len++; /* trailing null */ 3883 name_len++; /* trailing null */
3884 strncpy(pSMB->FileName, searchName, name_len); 3884 strncpy(pSMB->FileName, search_name, name_len);
3885 } 3885 }
3886 pSMB->BufferFormat = 0x04; 3886 pSMB->BufferFormat = 0x04;
3887 name_len++; /* account for buffer type byte */ 3887 name_len++; /* account for buffer type byte */
@@ -3892,23 +3892,23 @@ QInfRetry:
3892 (struct smb_hdr *) pSMBr, &bytes_returned, 0); 3892 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3893 if (rc) { 3893 if (rc) {
3894 cFYI(1, "Send error in QueryInfo = %d", rc); 3894 cFYI(1, "Send error in QueryInfo = %d", rc);
3895 } else if (pFinfo) { 3895 } else if (data) {
3896 struct timespec ts; 3896 struct timespec ts;
3897 __u32 time = le32_to_cpu(pSMBr->last_write_time); 3897 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3898 3898
3899 /* decode response */ 3899 /* decode response */
3900 /* BB FIXME - add time zone adjustment BB */ 3900 /* BB FIXME - add time zone adjustment BB */
3901 memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); 3901 memset(data, 0, sizeof(FILE_ALL_INFO));
3902 ts.tv_nsec = 0; 3902 ts.tv_nsec = 0;
3903 ts.tv_sec = time; 3903 ts.tv_sec = time;
3904 /* decode time fields */ 3904 /* decode time fields */
3905 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts)); 3905 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3906 pFinfo->LastWriteTime = pFinfo->ChangeTime; 3906 data->LastWriteTime = data->ChangeTime;
3907 pFinfo->LastAccessTime = 0; 3907 data->LastAccessTime = 0;
3908 pFinfo->AllocationSize = 3908 data->AllocationSize =
3909 cpu_to_le64(le32_to_cpu(pSMBr->size)); 3909 cpu_to_le64(le32_to_cpu(pSMBr->size));
3910 pFinfo->EndOfFile = pFinfo->AllocationSize; 3910 data->EndOfFile = data->AllocationSize;
3911 pFinfo->Attributes = 3911 data->Attributes =
3912 cpu_to_le32(le16_to_cpu(pSMBr->attr)); 3912 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3913 } else 3913 } else
3914 rc = -EIO; /* bad buffer passed in */ 3914 rc = -EIO; /* bad buffer passed in */
@@ -3990,12 +3990,11 @@ QFileInfoRetry:
3990 3990
3991int 3991int
3992CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, 3992CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
3993 const unsigned char *searchName, 3993 const char *search_name, FILE_ALL_INFO *data,
3994 FILE_ALL_INFO *pFindData,
3995 int legacy /* old style infolevel */, 3994 int legacy /* old style infolevel */,
3996 const struct nls_table *nls_codepage, int remap) 3995 const struct nls_table *nls_codepage, int remap)
3997{ 3996{
3998/* level 263 SMB_QUERY_FILE_ALL_INFO */ 3997 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3999 TRANSACTION2_QPI_REQ *pSMB = NULL; 3998 TRANSACTION2_QPI_REQ *pSMB = NULL;
4000 TRANSACTION2_QPI_RSP *pSMBr = NULL; 3999 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4001 int rc = 0; 4000 int rc = 0;
@@ -4003,7 +4002,7 @@ CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
4003 int name_len; 4002 int name_len;
4004 __u16 params, byte_count; 4003 __u16 params, byte_count;
4005 4004
4006/* cFYI(1, "In QPathInfo path %s", searchName); */ 4005 /* cFYI(1, "In QPathInfo path %s", search_name); */
4007QPathInfoRetry: 4006QPathInfoRetry:
4008 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 4007 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4009 (void **) &pSMBr); 4008 (void **) &pSMBr);
@@ -4012,14 +4011,14 @@ QPathInfoRetry:
4012 4011
4013 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 4012 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4014 name_len = 4013 name_len =
4015 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, 4014 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
4016 PATH_MAX, nls_codepage, remap); 4015 PATH_MAX, nls_codepage, remap);
4017 name_len++; /* trailing null */ 4016 name_len++; /* trailing null */
4018 name_len *= 2; 4017 name_len *= 2;
4019 } else { /* BB improve the check for buffer overruns BB */ 4018 } else { /* BB improve the check for buffer overruns BB */
4020 name_len = strnlen(searchName, PATH_MAX); 4019 name_len = strnlen(search_name, PATH_MAX);
4021 name_len++; /* trailing null */ 4020 name_len++; /* trailing null */
4022 strncpy(pSMB->FileName, searchName, name_len); 4021 strncpy(pSMB->FileName, search_name, name_len);
4023 } 4022 }
4024 4023
4025 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; 4024 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
@@ -4064,20 +4063,21 @@ QPathInfoRetry:
4064 else if (legacy && get_bcc(&pSMBr->hdr) < 24) 4063 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
4065 rc = -EIO; /* 24 or 26 expected but we do not read 4064 rc = -EIO; /* 24 or 26 expected but we do not read
4066 last field */ 4065 last field */
4067 else if (pFindData) { 4066 else if (data) {
4068 int size; 4067 int size;
4069 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 4068 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4070 4069
4071 /* On legacy responses we do not read the last field, 4070 /*
4072 EAsize, fortunately since it varies by subdialect and 4071 * On legacy responses we do not read the last field,
4073 also note it differs on Set vs. Get, ie two bytes or 4 4072 * EAsize, fortunately since it varies by subdialect and
4074 bytes depending but we don't care here */ 4073 * also note it differs on Set vs Get, ie two bytes or 4
4074 * bytes depending but we don't care here.
4075 */
4075 if (legacy) 4076 if (legacy)
4076 size = sizeof(FILE_INFO_STANDARD); 4077 size = sizeof(FILE_INFO_STANDARD);
4077 else 4078 else
4078 size = sizeof(FILE_ALL_INFO); 4079 size = sizeof(FILE_ALL_INFO);
4079 memcpy((char *) pFindData, 4080 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
4080 (char *) &pSMBr->hdr.Protocol +
4081 data_offset, size); 4081 data_offset, size);
4082 } else 4082 } else
4083 rc = -ENOMEM; 4083 rc = -ENOMEM;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 80807923a545..34588fe11c57 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3402,30 +3402,6 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
3402 return rsize; 3402 return rsize;
3403} 3403}
3404 3404
3405static int
3406is_path_accessible(unsigned int xid, struct cifs_tcon *tcon,
3407 struct cifs_sb_info *cifs_sb, const char *full_path)
3408{
3409 int rc;
3410 FILE_ALL_INFO *pfile_info;
3411
3412 pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
3413 if (pfile_info == NULL)
3414 return -ENOMEM;
3415
3416 rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
3417 0 /* not legacy */, cifs_sb->local_nls,
3418 cifs_sb->mnt_cifs_flags &
3419 CIFS_MOUNT_MAP_SPECIAL_CHR);
3420
3421 if (rc == -EOPNOTSUPP || rc == -EINVAL)
3422 rc = SMBQueryInformation(xid, tcon, full_path, pfile_info,
3423 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
3424 CIFS_MOUNT_MAP_SPECIAL_CHR);
3425 kfree(pfile_info);
3426 return rc;
3427}
3428
3429static void 3405static void
3430cleanup_volume_info_contents(struct smb_vol *volume_info) 3406cleanup_volume_info_contents(struct smb_vol *volume_info)
3431{ 3407{
@@ -3703,13 +3679,18 @@ remote_path_check:
3703 3679
3704 /* check if a whole path is not remote */ 3680 /* check if a whole path is not remote */
3705 if (!rc && tcon) { 3681 if (!rc && tcon) {
3682 if (!server->ops->is_path_accessible) {
3683 rc = -ENOSYS;
3684 goto mount_fail_check;
3685 }
3706 /* build_path_to_root works only when we have a valid tcon */ 3686 /* build_path_to_root works only when we have a valid tcon */
3707 full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon); 3687 full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon);
3708 if (full_path == NULL) { 3688 if (full_path == NULL) {
3709 rc = -ENOMEM; 3689 rc = -ENOMEM;
3710 goto mount_fail_check; 3690 goto mount_fail_check;
3711 } 3691 }
3712 rc = is_path_accessible(xid, tcon, cifs_sb, full_path); 3692 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
3693 full_path);
3713 if (rc != 0 && rc != -EREMOTE) { 3694 if (rc != 0 && rc != -EREMOTE) {
3714 kfree(full_path); 3695 kfree(full_path);
3715 goto mount_fail_check; 3696 goto mount_fail_check;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 96eb06ff9dd1..43f3881ad3b8 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -417,6 +417,30 @@ cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
417 CIFSSMBQFSAttributeInfo(xid, tcon); 417 CIFSSMBQFSAttributeInfo(xid, tcon);
418} 418}
419 419
420static int
421cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
422 struct cifs_sb_info *cifs_sb, const char *full_path)
423{
424 int rc;
425 FILE_ALL_INFO *file_info;
426
427 file_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
428 if (file_info == NULL)
429 return -ENOMEM;
430
431 rc = CIFSSMBQPathInfo(xid, tcon, full_path, file_info,
432 0 /* not legacy */, cifs_sb->local_nls,
433 cifs_sb->mnt_cifs_flags &
434 CIFS_MOUNT_MAP_SPECIAL_CHR);
435
436 if (rc == -EOPNOTSUPP || rc == -EINVAL)
437 rc = SMBQueryInformation(xid, tcon, full_path, file_info,
438 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
439 CIFS_MOUNT_MAP_SPECIAL_CHR);
440 kfree(file_info);
441 return rc;
442}
443
420struct smb_version_operations smb1_operations = { 444struct smb_version_operations smb1_operations = {
421 .send_cancel = send_nt_cancel, 445 .send_cancel = send_nt_cancel,
422 .compare_fids = cifs_compare_fids, 446 .compare_fids = cifs_compare_fids,
@@ -443,6 +467,7 @@ struct smb_version_operations smb1_operations = {
443 .tree_disconnect = CIFSSMBTDis, 467 .tree_disconnect = CIFSSMBTDis,
444 .get_dfs_refer = CIFSGetDFSRefer, 468 .get_dfs_refer = CIFSGetDFSRefer,
445 .qfs_tcon = cifs_qfs_tcon, 469 .qfs_tcon = cifs_qfs_tcon,
470 .is_path_accessible = cifs_is_path_accessible,
446}; 471};
447 472
448struct smb_version_values smb1_values = { 473struct smb_version_values smb1_values = {