[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)
This commit is contained in:
parent
e30dcf3a19
commit
2096243885
@ -3,7 +3,8 @@ Version 1.37
|
|||||||
Fix readdir caching when unlink removes file in current search buffer,
|
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.
|
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
|
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
|
Version 1.36
|
||||||
------------
|
------------
|
||||||
|
@ -205,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
|
|||||||
#endif /* CIFS_EXPERIMENTAL */
|
#endif /* CIFS_EXPERIMENTAL */
|
||||||
rc = CIFSSMBQFSInfo(xid, pTcon, buf);
|
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;
|
int f_type;
|
||||||
__fsid_t f_fsid;
|
__fsid_t f_fsid;
|
||||||
|
@ -1683,6 +1683,14 @@ typedef struct {
|
|||||||
__le32 BytesPerSector;
|
__le32 BytesPerSector;
|
||||||
} FILE_SYSTEM_INFO; /* size info, level 0x103 */
|
} 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 {
|
typedef struct {
|
||||||
__le16 MajorVersionNumber;
|
__le16 MajorVersionNumber;
|
||||||
__le16 MinorVersionNumber;
|
__le16 MinorVersionNumber;
|
||||||
|
@ -133,6 +133,8 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
|
|||||||
int remap);
|
int remap);
|
||||||
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
|
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
|
||||||
struct kstatfs *FSData);
|
struct kstatfs *FSData);
|
||||||
|
extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
|
||||||
|
struct kstatfs *FSData);
|
||||||
extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
|
extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
|
||||||
__u64 cap);
|
__u64 cap);
|
||||||
|
|
||||||
|
@ -3215,6 +3215,92 @@ GetDFSRefExit:
|
|||||||
return rc;
|
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
|
int
|
||||||
CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
|
CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
|
||||||
{
|
{
|
||||||
@ -3236,7 +3322,7 @@ QFSInfoRetry:
|
|||||||
params = 2; /* level */
|
params = 2; /* level */
|
||||||
pSMB->TotalDataCount = 0;
|
pSMB->TotalDataCount = 0;
|
||||||
pSMB->MaxParameterCount = cpu_to_le16(2);
|
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->MaxSetupCount = 0;
|
||||||
pSMB->Reserved = 0;
|
pSMB->Reserved = 0;
|
||||||
pSMB->Flags = 0;
|
pSMB->Flags = 0;
|
||||||
@ -3259,17 +3345,14 @@ QFSInfoRetry:
|
|||||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cERROR(1, ("Send error in QFSInfo = %d", rc));
|
cFYI(1, ("Send error in QFSInfo = %d", rc));
|
||||||
} else { /* decode response */
|
} else { /* decode response */
|
||||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
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 */
|
rc = -EIO; /* bad smb */
|
||||||
else {
|
else {
|
||||||
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||||
cFYI(1,
|
|
||||||
("Decoding qfsinfo response. BCC: %d Offset %d",
|
|
||||||
pSMBr->ByteCount, data_offset));
|
|
||||||
|
|
||||||
response_data =
|
response_data =
|
||||||
(FILE_SYSTEM_INFO
|
(FILE_SYSTEM_INFO
|
||||||
|
@ -450,13 +450,12 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
|
|||||||
|
|
||||||
if ((4 + len != smbCalcSize(smb))
|
if ((4 + len != smbCalcSize(smb))
|
||||||
|| (4 + len != (unsigned int)length)) {
|
|| (4 + len != (unsigned int)length)) {
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
|
cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
|
||||||
cERROR(1,
|
cERROR(1,
|
||||||
("bad smb size detected. The Mid=%d", smb->Mid));
|
("bad smb size detected. The Mid=%d", smb->Mid));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
int
|
int
|
||||||
is_valid_oplock_break(struct smb_hdr *buf)
|
is_valid_oplock_break(struct smb_hdr *buf)
|
||||||
|
@ -868,7 +868,7 @@ unsigned int
|
|||||||
smbCalcSize(struct smb_hdr *ptr)
|
smbCalcSize(struct smb_hdr *ptr)
|
||||||
{
|
{
|
||||||
return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
|
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 */
|
/* The following are taken from fs/ntfs/util.c */
|
||||||
|
Loading…
Reference in New Issue
Block a user