aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2005-09-22 01:05:57 -0400
committerSteve French <sfrench@us.ibm.com>2005-09-22 01:05:57 -0400
commit2096243885ee34b78cb57ce835e07c8536a67d2a (patch)
treecaae2d2535d33cca16f11da9a2d25e445bd30018 /fs/cifs
parente30dcf3a1905b4d2154f95db5fdfdf69691b4f0e (diff)
[CIFS] Add support for legacy servers part nine. statfs (df and du) is now
functional, and the length check is fixed so readdir does not throw a warning message when windows me messes up the response to FindFirst of an empty dir (with only . and ..). Signed-off-by: Steve French (sfrench@us.ibm.com)
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/CHANGES3
-rw-r--r--fs/cifs/cifsfs.c4
-rw-r--r--fs/cifs/cifspdu.h8
-rw-r--r--fs/cifs/cifsproto.h2
-rw-r--r--fs/cifs/cifssmb.c95
-rw-r--r--fs/cifs/misc.c3
-rw-r--r--fs/cifs/netmisc.c2
7 files changed, 107 insertions, 10 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 47ae68b51847..661b45906d09 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -3,7 +3,8 @@ Version 1.37
3Fix readdir caching when unlink removes file in current search buffer, 3Fix readdir caching when unlink removes file in current search buffer,
4and this is followed by a rewind search to just before the deleted entry. 4and this is followed by a rewind search to just before the deleted entry.
5Do not attempt to set ctime unless atime and/or mtime change requested 5Do not attempt to set ctime unless atime and/or mtime change requested
6(most servers throw it away anyway). 6(most servers throw it away anyway). Fix length check of received smbs
7to be more accurate.
7 8
8Version 1.36 9Version 1.36
9------------ 10------------
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index f738c8b19e3b..1f97d39100ee 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -205,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
205#endif /* CIFS_EXPERIMENTAL */ 205#endif /* CIFS_EXPERIMENTAL */
206 rc = CIFSSMBQFSInfo(xid, pTcon, buf); 206 rc = CIFSSMBQFSInfo(xid, pTcon, buf);
207 207
208 /* Old Windows servers do not support level 103, retry with level
209 one if old server failed the previous call */
210 if(rc)
211 rc = SMBOldQFSInfo(xid, pTcon, buf);
208 /* 212 /*
209 int f_type; 213 int f_type;
210 __fsid_t f_fsid; 214 __fsid_t f_fsid;
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index cf466595b0d4..3fa37790bea2 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1684,6 +1684,14 @@ typedef struct {
1684} FILE_SYSTEM_INFO; /* size info, level 0x103 */ 1684} FILE_SYSTEM_INFO; /* size info, level 0x103 */
1685 1685
1686typedef struct { 1686typedef struct {
1687 __le32 fsid;
1688 __le32 SectorsPerAllocationUnit;
1689 __le32 TotalAllocationUnits;
1690 __le32 FreeAllocationUnits;
1691 __le16 BytesPerSector;
1692} FILE_SYSTEM_ALLOC_INFO;
1693
1694typedef struct {
1687 __le16 MajorVersionNumber; 1695 __le16 MajorVersionNumber;
1688 __le16 MinorVersionNumber; 1696 __le16 MinorVersionNumber;
1689 __le64 Capability; 1697 __le64 Capability;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6943f7c6de08..0bace385e97a 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -133,6 +133,8 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
133 int remap); 133 int remap);
134extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, 134extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
135 struct kstatfs *FSData); 135 struct kstatfs *FSData);
136extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
137 struct kstatfs *FSData);
136extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, 138extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
137 __u64 cap); 139 __u64 cap);
138 140
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index f72a61df3c68..daf717e6b6eb 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3215,6 +3215,92 @@ GetDFSRefExit:
3215 return rc; 3215 return rc;
3216} 3216}
3217 3217
3218/* Query File System Info such as free space to old servers such as Win 9x */
3219int
3220SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3221{
3222/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3223 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3224 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3225 FILE_SYSTEM_ALLOC_INFO *response_data;
3226 int rc = 0;
3227 int bytes_returned = 0;
3228 __u16 params, byte_count;
3229
3230 cFYI(1, ("OldQFSInfo"));
3231oldQFSInfoRetry:
3232 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3233 (void **) &pSMBr);
3234 if (rc)
3235 return rc;
3236 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3237 (void **) &pSMBr);
3238 if (rc)
3239 return rc;
3240
3241 params = 2; /* level */
3242 pSMB->TotalDataCount = 0;
3243 pSMB->MaxParameterCount = cpu_to_le16(2);
3244 pSMB->MaxDataCount = cpu_to_le16(1000);
3245 pSMB->MaxSetupCount = 0;
3246 pSMB->Reserved = 0;
3247 pSMB->Flags = 0;
3248 pSMB->Timeout = 0;
3249 pSMB->Reserved2 = 0;
3250 byte_count = params + 1 /* pad */ ;
3251 pSMB->TotalParameterCount = cpu_to_le16(params);
3252 pSMB->ParameterCount = pSMB->TotalParameterCount;
3253 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3254 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3255 pSMB->DataCount = 0;
3256 pSMB->DataOffset = 0;
3257 pSMB->SetupCount = 1;
3258 pSMB->Reserved3 = 0;
3259 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3260 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3261 pSMB->hdr.smb_buf_length += byte_count;
3262 pSMB->ByteCount = cpu_to_le16(byte_count);
3263
3264 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3265 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3266 if (rc) {
3267 cFYI(1, ("Send error in QFSInfo = %d", rc));
3268 } else { /* decode response */
3269 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3270
3271 if (rc || (pSMBr->ByteCount < 18))
3272 rc = -EIO; /* bad smb */
3273 else {
3274 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3275 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3276 pSMBr->ByteCount, data_offset));
3277
3278 response_data =
3279 (FILE_SYSTEM_ALLOC_INFO *)
3280 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3281 FSData->f_bsize =
3282 le16_to_cpu(response_data->BytesPerSector) *
3283 le32_to_cpu(response_data->
3284 SectorsPerAllocationUnit);
3285 FSData->f_blocks =
3286 le32_to_cpu(response_data->TotalAllocationUnits);
3287 FSData->f_bfree = FSData->f_bavail =
3288 le32_to_cpu(response_data->FreeAllocationUnits);
3289 cFYI(1,
3290 ("Blocks: %lld Free: %lld Block size %ld",
3291 (unsigned long long)FSData->f_blocks,
3292 (unsigned long long)FSData->f_bfree,
3293 FSData->f_bsize));
3294 }
3295 }
3296 cifs_buf_release(pSMB);
3297
3298 if (rc == -EAGAIN)
3299 goto oldQFSInfoRetry;
3300
3301 return rc;
3302}
3303
3218int 3304int
3219CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) 3305CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3220{ 3306{
@@ -3236,7 +3322,7 @@ QFSInfoRetry:
3236 params = 2; /* level */ 3322 params = 2; /* level */
3237 pSMB->TotalDataCount = 0; 3323 pSMB->TotalDataCount = 0;
3238 pSMB->MaxParameterCount = cpu_to_le16(2); 3324 pSMB->MaxParameterCount = cpu_to_le16(2);
3239 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ 3325 pSMB->MaxDataCount = cpu_to_le16(1000);
3240 pSMB->MaxSetupCount = 0; 3326 pSMB->MaxSetupCount = 0;
3241 pSMB->Reserved = 0; 3327 pSMB->Reserved = 0;
3242 pSMB->Flags = 0; 3328 pSMB->Flags = 0;
@@ -3259,17 +3345,14 @@ QFSInfoRetry:
3259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 3345 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3260 (struct smb_hdr *) pSMBr, &bytes_returned, 0); 3346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3261 if (rc) { 3347 if (rc) {
3262 cERROR(1, ("Send error in QFSInfo = %d", rc)); 3348 cFYI(1, ("Send error in QFSInfo = %d", rc));
3263 } else { /* decode response */ 3349 } else { /* decode response */
3264 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 3350 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3265 3351
3266 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */ 3352 if (rc || (pSMBr->ByteCount < 24))
3267 rc = -EIO; /* bad smb */ 3353 rc = -EIO; /* bad smb */
3268 else { 3354 else {
3269 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 3355 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3270 cFYI(1,
3271 ("Decoding qfsinfo response. BCC: %d Offset %d",
3272 pSMBr->ByteCount, data_offset));
3273 3356
3274 response_data = 3357 response_data =
3275 (FILE_SYSTEM_INFO 3358 (FILE_SYSTEM_INFO
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index fafbdbfa63a1..26b35b55f31b 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -450,13 +450,12 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
450 450
451 if ((4 + len != smbCalcSize(smb)) 451 if ((4 + len != smbCalcSize(smb))
452 || (4 + len != (unsigned int)length)) { 452 || (4 + len != (unsigned int)length)) {
453 return 0;
454 } else {
455 cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); 453 cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
456 cERROR(1, 454 cERROR(1,
457 ("bad smb size detected. The Mid=%d", smb->Mid)); 455 ("bad smb size detected. The Mid=%d", smb->Mid));
458 return 1; 456 return 1;
459 } 457 }
458 return 0;
460} 459}
461int 460int
462is_valid_oplock_break(struct smb_hdr *buf) 461is_valid_oplock_break(struct smb_hdr *buf)
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 873b812c0f40..32efa32774d2 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -868,7 +868,7 @@ unsigned int
868smbCalcSize(struct smb_hdr *ptr) 868smbCalcSize(struct smb_hdr *ptr)
869{ 869{
870 return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + 870 return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
871 BCC(ptr)); 871 2 /* size of the bcc field itself */ + BCC(ptr));
872} 872}
873 873
874/* The following are taken from fs/ntfs/util.c */ 874/* The following are taken from fs/ntfs/util.c */