diff options
-rw-r--r-- | fs/cifs/cifsglob.h | 3 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 12 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 60 | ||||
-rw-r--r-- | fs/cifs/connect.c | 31 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 25 |
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 | ||
220 | struct smb_version_values { | 223 | struct 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, | |||
208 | extern int CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, | 208 | extern int CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, |
209 | u16 netfid, FILE_ALL_INFO *pFindData); | 209 | u16 netfid, FILE_ALL_INFO *pFindData); |
210 | extern int CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, | 210 | extern 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); | ||
215 | extern int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon, | 214 | extern 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 | ||
220 | extern int CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, | 218 | extern 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 */ |
3856 | int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon, | 3856 | int |
3857 | const unsigned char *searchName, | 3857 | SMBQueryInformation(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); |
3868 | QInfRetry: | 3868 | QInfRetry: |
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 | ||
3991 | int | 3991 | int |
3992 | CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, | 3992 | CIFSSMBQPathInfo(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); */ |
4007 | QPathInfoRetry: | 4006 | QPathInfoRetry: |
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 | ||
3405 | static int | ||
3406 | is_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 | |||
3429 | static void | 3405 | static void |
3430 | cleanup_volume_info_contents(struct smb_vol *volume_info) | 3406 | cleanup_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 | ||
420 | static int | ||
421 | cifs_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 | |||
420 | struct smb_version_operations smb1_operations = { | 444 | struct 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 | ||
448 | struct smb_version_values smb1_values = { | 473 | struct smb_version_values smb1_values = { |