diff options
-rw-r--r-- | fs/cifs/CHANGES | 7 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 40 | ||||
-rw-r--r-- | fs/cifs/connect.c | 97 | ||||
-rw-r--r-- | fs/cifs/file.c | 12 |
6 files changed, 140 insertions, 20 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 1a27ecb..7271bb0 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,10 @@ +Version 1.43 +------------ +POSIX locking to servers which support CIFS POSIX Extensions +(disabled by default controlled by proc/fs/cifs/Experimental). +Handle conversion of long share names (especially Asian languages) +to Unicode during mount. + Version 1.42 ------------ Fix slow oplock break when mounted to different servers at the same time and diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 4e829dc..c98755d 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -99,5 +99,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg); -#define CIFS_VERSION "1.42" +#define CIFS_VERSION "1.43" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 2879ba3..310ea2f 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -267,7 +267,7 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, const int waitFlag); extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, const __u16 smb_file_id, const int get_flag, - const __u64 len, const __u64 offset, + const __u64 len, struct file_lock *, const __u16 lock_type, const int waitFlag); extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index fd36892..925881e 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1355,7 +1355,8 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, const __u16 smb_file_id, const int get_flag, const __u64 len, - const __u64 lkoffset, const __u16 lock_type, const int waitFlag) + struct file_lock *pLockData, const __u16 lock_type, + const int waitFlag) { struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; @@ -1366,6 +1367,10 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, __u16 params, param_offset, offset, byte_count, count; cFYI(1, ("Posix Lock")); + + if(pLockData == NULL) + return EINVAL; + rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); if (rc) @@ -1404,10 +1409,10 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, parm_data->lock_type = cpu_to_le16(lock_type); if(waitFlag) - parm_data->lock_flags = 1; + parm_data->lock_flags = cpu_to_le16(1); parm_data->pid = cpu_to_le32(current->tgid); - parm_data->start = lkoffset; - parm_data->length = len; /* normalize negative numbers */ + parm_data->start = cpu_to_le64(pLockData->fl_start); + parm_data->length = cpu_to_le64(len); /* normalize negative numbers */ pSMB->DataOffset = cpu_to_le16(offset); pSMB->Fid = smb_file_id; @@ -1419,8 +1424,33 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cFYI(1, ("Send error in Posix Lock = %d", rc)); - } + } else if (get_flag) { + /* lock structure can be returned on get */ + __u16 data_offset; + __u16 data_count; + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) { + rc = -EIO; /* bad smb */ + goto plk_err_exit; + } + if(pLockData == NULL) { + rc = -EINVAL; + goto plk_err_exit; + } + data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + data_count = le16_to_cpu(pSMBr->t2.DataCount); + if(data_count < sizeof(struct cifs_posix_lock)) { + rc = -EIO; + goto plk_err_exit; + } + parm_data = (struct cifs_posix_lock *) + ((char *)&pSMBr->hdr.Protocol + data_offset); + if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK)) + pLockData->fl_type = F_UNLCK; + } + +plk_err_exit: if (pSMB) cifs_small_buf_release(pSMB); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d2ec806..bae1479 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2148,6 +2148,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ + if(ses->serverOS) + kfree(ses->serverOS); ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); if(ses->serverOS == NULL) goto sesssetup_nomem; @@ -2160,6 +2162,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (remaining_words > 0) { len = UniStrnlen((wchar_t *)bcc_ptr, remaining_words-1); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL); if(ses->serverNOS == NULL) goto sesssetup_nomem; @@ -2177,6 +2181,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL); if(ses->serverDomain == NULL) @@ -2187,15 +2193,22 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ses->serverDomain[2*len] = 0; ses->serverDomain[1+(2*len)] = 0; } /* else no more room so create dummy domain string */ - else + else { + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); + } } else { /* no room so create dummy domain and NOS string */ /* if these kcallocs fail not much we can do, but better to not fail the sesssetup itself */ + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } @@ -2204,6 +2217,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { + if(ses->serverOS) + kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1,GFP_KERNEL); if(ses->serverOS == NULL) goto sesssetup_nomem; @@ -2214,6 +2229,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); if(ses->serverNOS == NULL) goto sesssetup_nomem; @@ -2223,6 +2240,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(len + 1,GFP_KERNEL); if(ses->serverDomain == NULL) goto sesssetup_nomem; @@ -2427,6 +2446,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ + if(ses->serverOS) + kfree(ses->serverOS); ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, @@ -2441,6 +2462,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, len = UniStrnlen((wchar_t *)bcc_ptr, remaining_words - 1); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1), GFP_KERNEL); @@ -2454,7 +2477,9 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, remaining_words -= len + 1; if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); - /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ + /* last string not null terminated (e.g.Windows XP/2000) */ + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverDomain, (__le16 *)bcc_ptr, @@ -2463,11 +2488,18 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, ses->serverDomain[2*len] = 0; ses->serverDomain[1+(2*len)] = 0; } /* else no more room so create dummy domain string */ - else + else { + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2,GFP_KERNEL); - } else { /* no room so create dummy domain and NOS string */ + } + } else {/* no room use dummy domain&NOS */ + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } } else { /* ASCII */ @@ -2476,6 +2508,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { + if(ses->serverOS) + kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS, bcc_ptr, len); @@ -2484,6 +2518,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; @@ -2491,6 +2527,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; @@ -2728,6 +2766,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ + if(ses->serverOS) + kfree(ses->serverOS); ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, @@ -2743,6 +2783,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, bcc_ptr, remaining_words - 1); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1), GFP_KERNEL); @@ -2760,6 +2802,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2 * (len + @@ -2777,13 +2821,20 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, [1 + (2 * len)] = 0; } /* else no more room so create dummy domain string */ - else + else { + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); + } } else { /* no room so create dummy domain and NOS string */ + if(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } @@ -2792,6 +2843,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { + if(ses->serverOS) + kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1, GFP_KERNEL); @@ -2803,6 +2856,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, bcc_ptr++; len = strnlen(bcc_ptr, 1024); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); @@ -2812,6 +2867,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, bcc_ptr++; len = strnlen(bcc_ptr, 1024); + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); @@ -3116,6 +3173,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ + if(ses->serverOS) + kfree(ses->serverOS); ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, @@ -3131,6 +3190,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr, remaining_words - 1); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1), GFP_KERNEL); @@ -3147,6 +3208,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string not always null terminated (e.g. for Windows XP & 2000) */ + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2 * (len + @@ -3172,10 +3235,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, len)] = 0; } /* else no more room so create dummy domain string */ - else + else { + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2,GFP_KERNEL); + } } else { /* no room so create dummy domain and NOS string */ + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } } else { /* ASCII */ @@ -3183,6 +3253,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { + if(ses->serverOS) + kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1,GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); @@ -3191,6 +3263,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); + if(ses->serverNOS) + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len+1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; @@ -3198,6 +3272,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); + if(ses->serverDomain) + kfree(ses->serverDomain); ses->serverDomain = kzalloc(len+1,GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; @@ -3282,7 +3358,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; /* align */ } - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + if(ses->server->secMode & + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; if (ses->capabilities & CAP_STATUS32) { @@ -3294,8 +3371,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; length = - cifs_strtoUCS((__le16 *) bcc_ptr, tree, 100, nls_codepage); - bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */ + cifs_strtoUCS((__le16 *) bcc_ptr, tree, + 6 /* max utf8 char length in bytes */ * + (/* server len*/ + 256 /* share len */), nls_codepage); + bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */ bcc_ptr += 2; /* skip trailing null */ } else { /* ASCII */ strcpy(bcc_ptr, tree); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e152bf6..e2b4ce1 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -84,6 +84,8 @@ static inline int cifs_get_disposition(unsigned int flags) return FILE_OVERWRITE_IF; else if ((flags & O_CREAT) == O_CREAT) return FILE_OPEN_IF; + else if ((flags & O_TRUNC) == O_TRUNC) + return FILE_OVERWRITE; else return FILE_OPEN; } @@ -656,7 +658,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) else posix_lock_type = CIFS_WRLCK; rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */, - length, pfLock->fl_start, + length, pfLock, posix_lock_type, wait_flag); FreeXid(xid); return rc; @@ -704,7 +706,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) return -EOPNOTSUPP; } rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */, - length, pfLock->fl_start, + length, pfLock, posix_lock_type, wait_flag); } else rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, @@ -904,8 +906,10 @@ static ssize_t cifs_write(struct file *file, const char *write_data, if (rc != 0) break; } - if(experimEnabled || (pTcon->ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) { + if(experimEnabled || (pTcon->ses->server && + ((pTcon->ses->server->secMode & + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + == 0))) { struct kvec iov[2]; unsigned int len; |