]> err.no Git - linux-2.6/commitdiff
[CIFS] Add support for legacy servers part nine. statfs (df and du) is now
authorSteve French <sfrench@us.ibm.com>
Thu, 22 Sep 2005 05:05:57 +0000 (22:05 -0700)
committerSteve French <sfrench@us.ibm.com>
Thu, 22 Sep 2005 05:05:57 +0000 (22:05 -0700)
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)
fs/cifs/CHANGES
fs/cifs/cifsfs.c
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/misc.c
fs/cifs/netmisc.c

index 47ae68b51847c34867eb2dc4b78377d97bdbd678..661b45906d0980e4669aa31e9dba25b9d55f1167 100644 (file)
@@ -3,7 +3,8 @@ Version 1.37
 Fix readdir caching when unlink removes file in current search buffer,
 and this is followed by a rewind search to just before the deleted entry.
 Do not attempt to set ctime unless atime and/or mtime change requested
-(most servers throw it away anyway).
+(most servers throw it away anyway). Fix length check of received smbs
+to be more accurate.
 
 Version 1.36
 ------------
index f738c8b19e3b197262efa8f35f2e337eb3c9003c..1f97d39100ee51ed707eb12d0353c09035cf23aa 100644 (file)
@@ -205,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
 #endif /* CIFS_EXPERIMENTAL */
        rc = CIFSSMBQFSInfo(xid, pTcon, buf);
 
+       /* Old Windows servers do not support level 103, retry with level 
+          one if old server failed the previous call */ 
+       if(rc)
+               rc = SMBOldQFSInfo(xid, pTcon, buf);
        /*     
           int f_type;
           __fsid_t f_fsid;
index cf466595b0d400b459dc23f0c18433f00495669d..3fa37790bea271bf1f7bc0e9bc1623a78a7962b9 100644 (file)
@@ -1683,6 +1683,14 @@ typedef struct {
        __le32 BytesPerSector;
 } FILE_SYSTEM_INFO;            /* size info, level 0x103 */
 
+typedef struct {
+       __le32 fsid;
+       __le32 SectorsPerAllocationUnit;
+       __le32 TotalAllocationUnits;
+       __le32 FreeAllocationUnits;
+       __le16  BytesPerSector;
+} FILE_SYSTEM_ALLOC_INFO;
+
 typedef struct {
        __le16 MajorVersionNumber;
        __le16 MinorVersionNumber;
index 6943f7c6de08468eb138ae41c833165ec8a67e69..0bace385e97a882d3f06a1b88436ebbb2016e516 100644 (file)
@@ -133,6 +133,8 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
                        int remap);
 extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
                        struct kstatfs *FSData);
+extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
+                       struct kstatfs *FSData);
 extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
                        __u64 cap);
 
index f72a61df3c68cb7cb6db3b7a5e740e5b923de47f..daf717e6b6eb2426366f03613a12038f74ec16f1 100644 (file)
@@ -3215,6 +3215,92 @@ GetDFSRefExit:
        return rc;
 }
 
+/* Query File System Info such as free space to old servers such as Win 9x */
+int
+SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
+{
+/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
+       TRANSACTION2_QFSI_REQ *pSMB = NULL;
+       TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+       FILE_SYSTEM_ALLOC_INFO *response_data;
+       int rc = 0;
+       int bytes_returned = 0;
+       __u16 params, byte_count;
+
+       cFYI(1, ("OldQFSInfo"));
+oldQFSInfoRetry:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+               (void **) &pSMBr);
+       if (rc)
+               return rc;
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       params = 2;     /* level */
+       pSMB->TotalDataCount = 0;
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       pSMB->MaxDataCount = cpu_to_le16(1000);
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       byte_count = params + 1 /* pad */ ;
+       pSMB->TotalParameterCount = cpu_to_le16(params);
+       pSMB->ParameterCount = pSMB->TotalParameterCount;
+       pSMB->ParameterOffset = cpu_to_le16(offsetof(
+       struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+       pSMB->DataCount = 0;
+       pSMB->DataOffset = 0;
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+       pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->ByteCount = cpu_to_le16(byte_count);
+
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+               (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc) {
+               cFYI(1, ("Send error in QFSInfo = %d", rc));
+       } else {                /* decode response */
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+               if (rc || (pSMBr->ByteCount < 18))
+                       rc = -EIO;      /* bad smb */
+               else {
+                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+                       cFYI(1,("qfsinf resp BCC: %d  Offset %d",
+                                pSMBr->ByteCount, data_offset));
+
+                       response_data =
+                               (FILE_SYSTEM_ALLOC_INFO *) 
+                               (((char *) &pSMBr->hdr.Protocol) + data_offset);
+                       FSData->f_bsize =
+                               le16_to_cpu(response_data->BytesPerSector) *
+                               le32_to_cpu(response_data->
+                                       SectorsPerAllocationUnit);
+                       FSData->f_blocks =
+                               le32_to_cpu(response_data->TotalAllocationUnits);
+                       FSData->f_bfree = FSData->f_bavail =
+                               le32_to_cpu(response_data->FreeAllocationUnits);
+                       cFYI(1,
+                            ("Blocks: %lld  Free: %lld Block size %ld",
+                             (unsigned long long)FSData->f_blocks,
+                             (unsigned long long)FSData->f_bfree,
+                             FSData->f_bsize));
+               }
+       }
+       cifs_buf_release(pSMB);
+
+       if (rc == -EAGAIN)
+               goto oldQFSInfoRetry;
+
+       return rc;
+}
+
 int
 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
 {
@@ -3236,7 +3322,7 @@ QFSInfoRetry:
        params = 2;     /* level */
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -3259,17 +3345,14 @@ QFSInfoRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
-               cERROR(1, ("Send error in QFSInfo = %d", rc));
+               cFYI(1, ("Send error in QFSInfo = %d", rc));
        } else {                /* decode response */
                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-               if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
+               if (rc || (pSMBr->ByteCount < 24))
                        rc = -EIO;      /* bad smb */
                else {
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       cFYI(1,
-                               ("Decoding qfsinfo response.  BCC: %d  Offset %d",
-                               pSMBr->ByteCount, data_offset));
 
                        response_data =
                            (FILE_SYSTEM_INFO
index fafbdbfa63a1382d0c98e2208bf27e1559692fa1..26b35b55f31b99b752201e19c31446550ab90c50 100644 (file)
@@ -450,13 +450,12 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
 
        if ((4 + len != smbCalcSize(smb))
            || (4 + len != (unsigned int)length)) {
-               return 0;
-       } else {
                cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
                cERROR(1,
                       ("bad smb size detected. The Mid=%d", smb->Mid));
                return 1;
        }
+       return 0;
 }
 int
 is_valid_oplock_break(struct smb_hdr *buf)
index 873b812c0f408e450421fcba274a6cbbc19854b9..32efa32774d22a73e48dd6c1773322d6caaf0cb9 100644 (file)
@@ -868,7 +868,7 @@ unsigned int
 smbCalcSize(struct smb_hdr *ptr)
 {
        return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
-               BCC(ptr));
+               2 /* size of the bcc field itself */ + BCC(ptr));
 }
 
 /* The following are taken from fs/ntfs/util.c */