diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
| -rw-r--r-- | fs/cifs/cifssmb.c | 3076 |
1 files changed, 1903 insertions, 1173 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2f2632b6df5..6ce4e0954b9 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -32,6 +32,9 @@ #include <linux/vfs.h> #include <linux/slab.h> #include <linux/posix_acl_xattr.h> +#include <linux/pagemap.h> +#include <linux/swap.h> +#include <linux/task_io_accounting_ops.h> #include <asm/uaccess.h> #include "cifspdu.h" #include "cifsglob.h" @@ -39,6 +42,7 @@ #include "cifsproto.h" #include "cifs_unicode.h" #include "cifs_debug.h" +#include "fscache.h" #ifdef CONFIG_CIFS_POSIX static struct { @@ -82,32 +86,37 @@ static struct { #endif /* CONFIG_CIFS_WEAK_PW_HASH */ #endif /* CIFS_POSIX */ -/* Mark as invalid, all open files on tree connections since they - were closed when session to server was lost */ -static void mark_open_files_invalid(struct cifsTconInfo *pTcon) +/* + * Mark as invalid, all open files on tree connections since they + * were closed when session to server was lost. + */ +void +cifs_mark_open_files_invalid(struct cifs_tcon *tcon) { struct cifsFileInfo *open_file = NULL; struct list_head *tmp; struct list_head *tmp1; -/* list all files open on tree connection and mark them invalid */ + /* list all files open on tree connection and mark them invalid */ spin_lock(&cifs_file_list_lock); - list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { + list_for_each_safe(tmp, tmp1, &tcon->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, tlist); open_file->invalidHandle = true; open_file->oplock_break_cancelled = true; } spin_unlock(&cifs_file_list_lock); - /* BB Add call to invalidate_inodes(sb) for all superblocks mounted - to this tcon */ + /* + * BB Add call to invalidate_inodes(sb) for all superblocks mounted + * to this tcon. + */ } /* reconnect the socket, tcon, and smb session if needed */ static int -cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) +cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) { - int rc = 0; - struct cifsSesInfo *ses; + int rc; + struct cifs_ses *ses; struct TCP_Server_Info *server; struct nls_table *nls_codepage; @@ -130,24 +139,21 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) if (smb_command != SMB_COM_WRITE_ANDX && smb_command != SMB_COM_OPEN_ANDX && smb_command != SMB_COM_TREE_DISCONNECT) { - cFYI(1, "can not send cmd %d while umounting", - smb_command); + cifs_dbg(FYI, "can not send cmd %d while umounting\n", + smb_command); return -ENODEV; } } - if (ses->status == CifsExiting) - return -EIO; - /* * Give demultiplex thread up to 10 seconds to reconnect, should be * greater than cifs socket timeout which is 7 seconds */ while (server->tcpStatus == CifsNeedReconnect) { wait_event_interruptible_timeout(server->response_q, - (server->tcpStatus == CifsGood), 10 * HZ); + (server->tcpStatus != CifsNeedReconnect), 10 * HZ); - /* is TCP session is reestablished now ?*/ + /* are we still trying to reconnect? */ if (server->tcpStatus != CifsNeedReconnect) break; @@ -156,8 +162,8 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) * retrying until process is killed or server comes * back on-line */ - if (!tcon->retry || ses->status == CifsExiting) { - cFYI(1, "gave up waiting on reconnect in smb_init"); + if (!tcon->retry) { + cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n"); return -EHOSTDOWN; } } @@ -182,10 +188,10 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) goto out; } - mark_open_files_invalid(tcon); + cifs_mark_open_files_invalid(tcon); rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage); mutex_unlock(&ses->session_mutex); - cFYI(1, "reconnect tcon rc = %d", rc); + cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); if (rc) goto out; @@ -229,7 +235,7 @@ out: SMB information in the SMB header. If the return code is zero, this function must have filled in request_buf pointer */ static int -small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, +small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon, void **request_buf) { int rc; @@ -255,7 +261,7 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, int small_smb_init_no_tc(const int smb_command, const int wct, - struct cifsSesInfo *ses, void **request_buf) + struct cifs_ses *ses, void **request_buf) { int rc; struct smb_hdr *buffer; @@ -265,7 +271,7 @@ small_smb_init_no_tc(const int smb_command, const int wct, return rc; buffer = (struct smb_hdr *)*request_buf; - buffer->Mid = GetNextMid(ses->server); + buffer->Mid = get_next_mid(ses->server); if (ses->capabilities & CAP_UNICODE) buffer->Flags2 |= SMBFLG2_UNICODE; if (ses->capabilities & CAP_STATUS32) @@ -281,7 +287,7 @@ small_smb_init_no_tc(const int smb_command, const int wct, /* If the return code is zero, this function must fill in request_buf pointer */ static int -__smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, +__smb_init(int smb_command, int wct, struct cifs_tcon *tcon, void **request_buf, void **response_buf) { *request_buf = cifs_buf_get(); @@ -307,7 +313,7 @@ __smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, /* If the return code is zero, this function must fill in request_buf pointer */ static int -smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, +smb_init(int smb_command, int wct, struct cifs_tcon *tcon, void **request_buf, void **response_buf) { int rc; @@ -320,7 +326,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, } static int -smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon, +smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon, void **request_buf, void **response_buf) { if (tcon->ses->need_reconnect || tcon->need_reconnect) @@ -331,85 +337,242 @@ smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon, static int validate_t2(struct smb_t2_rsp *pSMB) { - int rc = -EINVAL; - int total_size; - char *pBCC; + unsigned int total_size; + + /* check for plausible wct */ + if (pSMB->hdr.WordCount < 10) + goto vt2_err; - /* check for plausible wct, bcc and t2 data and parm sizes */ /* check for parm and data offset going beyond end of smb */ - if (pSMB->hdr.WordCount >= 10) { - if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) && - (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) { - /* check that bcc is at least as big as parms + data */ - /* check that bcc is less than negotiated smb buffer */ - total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount); - if (total_size < 512) { - total_size += - le16_to_cpu(pSMB->t2_rsp.DataCount); - /* BCC le converted in SendReceive */ - pBCC = (pSMB->hdr.WordCount * 2) + - sizeof(struct smb_hdr) + - (char *)pSMB; - if ((total_size <= (*(u16 *)pBCC)) && - (total_size < - CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) { - return 0; - } - } - } - } + if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 || + get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024) + goto vt2_err; + + total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount); + if (total_size >= 512) + goto vt2_err; + + /* check that bcc is at least as big as parms + data, and that it is + * less than negotiated smb buffer + */ + total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount); + if (total_size > get_bcc(&pSMB->hdr) || + total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) + goto vt2_err; + + return 0; +vt2_err: cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, sizeof(struct smb_t2_rsp) + 16); - return rc; + return -EINVAL; +} + +static int +decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr) +{ + int rc = 0; + u16 count; + char *guid = pSMBr->u.extended_response.GUID; + struct TCP_Server_Info *server = ses->server; + + count = get_bcc(&pSMBr->hdr); + if (count < SMB1_CLIENT_GUID_SIZE) + return -EIO; + + spin_lock(&cifs_tcp_ses_lock); + if (server->srv_count > 1) { + spin_unlock(&cifs_tcp_ses_lock); + if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) { + cifs_dbg(FYI, "server UID changed\n"); + memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE); + } + } else { + spin_unlock(&cifs_tcp_ses_lock); + memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE); + } + + if (count == SMB1_CLIENT_GUID_SIZE) { + server->sec_ntlmssp = true; + } else { + count -= SMB1_CLIENT_GUID_SIZE; + rc = decode_negTokenInit( + pSMBr->u.extended_response.SecurityBlob, count, server); + if (rc != 1) + return -EINVAL; + } + + return 0; +} + +int +cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required) +{ + bool srv_sign_required = server->sec_mode & server->vals->signing_required; + bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled; + bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN; + + /* + * Is signing required by mnt options? If not then check + * global_secflags to see if it is there. + */ + if (!mnt_sign_required) + mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) == + CIFSSEC_MUST_SIGN); + + /* + * If signing is required then it's automatically enabled too, + * otherwise, check to see if the secflags allow it. + */ + mnt_sign_enabled = mnt_sign_required ? mnt_sign_required : + (global_secflags & CIFSSEC_MAY_SIGN); + + /* If server requires signing, does client allow it? */ + if (srv_sign_required) { + if (!mnt_sign_enabled) { + cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!"); + return -ENOTSUPP; + } + server->sign = true; + } + + /* If client requires signing, does server allow it? */ + if (mnt_sign_required) { + if (!srv_sign_enabled) { + cifs_dbg(VFS, "Server does not support signing!"); + return -ENOTSUPP; + } + server->sign = true; + } + + return 0; +} + +#ifdef CONFIG_CIFS_WEAK_PW_HASH +static int +decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) +{ + __s16 tmp; + struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr; + + if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT) + return -EOPNOTSUPP; + + server->sec_mode = le16_to_cpu(rsp->SecurityMode); + server->maxReq = min_t(unsigned int, + le16_to_cpu(rsp->MaxMpxCount), + cifs_max_pending); + set_credits(server, server->maxReq); + server->maxBuf = le16_to_cpu(rsp->MaxBufSize); + /* even though we do not use raw we might as well set this + accurately, in case we ever find a need for it */ + if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { + server->max_rw = 0xFF00; + server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; + } else { + server->max_rw = 0;/* do not need to use raw anyway */ + server->capabilities = CAP_MPX_MODE; + } + tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); + if (tmp == -1) { + /* OS/2 often does not set timezone therefore + * we must use server time to calc time zone. + * Could deviate slightly from the right zone. + * Smallest defined timezone difference is 15 minutes + * (i.e. Nepal). Rounding up/down is done to match + * this requirement. + */ + int val, seconds, remain, result; + struct timespec ts, utc; + utc = CURRENT_TIME; + ts = cnvrtDosUnixTm(rsp->SrvTime.Date, + rsp->SrvTime.Time, 0); + cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n", + (int)ts.tv_sec, (int)utc.tv_sec, + (int)(utc.tv_sec - ts.tv_sec)); + val = (int)(utc.tv_sec - ts.tv_sec); + seconds = abs(val); + result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; + remain = seconds % MIN_TZ_ADJ; + if (remain >= (MIN_TZ_ADJ / 2)) + result += MIN_TZ_ADJ; + if (val < 0) + result = -result; + server->timeAdj = result; + } else { + server->timeAdj = (int)tmp; + server->timeAdj *= 60; /* also in seconds */ + } + cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj); + + + /* BB get server time for time conversions and add + code to use it and timezone since this is not UTC */ + + if (rsp->EncryptionKeyLength == + cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { + memcpy(server->cryptkey, rsp->EncryptionKey, + CIFS_CRYPTO_KEY_SIZE); + } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { + return -EIO; /* need cryptkey unless plain text */ + } + + cifs_dbg(FYI, "LANMAN negotiated\n"); + return 0; } +#else +static inline int +decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) +{ + cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n"); + return -EOPNOTSUPP; +} +#endif + +static bool +should_set_ext_sec_flag(enum securityEnum sectype) +{ + switch (sectype) { + case RawNTLMSSP: + case Kerberos: + return true; + case Unspecified: + if (global_secflags & + (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)) + return true; + /* Fallthrough */ + default: + return false; + } +} + int -CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) +CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) { NEGOTIATE_REQ *pSMB; NEGOTIATE_RSP *pSMBr; int rc = 0; int bytes_returned; int i; - struct TCP_Server_Info *server; + struct TCP_Server_Info *server = ses->server; u16 count; - unsigned int secFlags; - if (ses->server) - server = ses->server; - else { - rc = -EIO; - return rc; + if (!server) { + WARN(1, "%s: server is NULL!\n", __func__); + return -EIO; } + rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , (void **) &pSMB, (void **) &pSMBr); if (rc) return rc; - /* if any of auth flags (ie not sign or seal) are overriden use them */ - if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) - secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */ - else /* if override flags set only sign/seal OR them with global auth */ - secFlags = global_secflags | ses->overrideSecFlg; - - cFYI(1, "secFlags 0x%x", secFlags); - - pSMB->hdr.Mid = GetNextMid(server); + pSMB->hdr.Mid = get_next_mid(server); pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); - if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) - pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { - cFYI(1, "Kerberos only mechanism, enable extended security"); + if (should_set_ext_sec_flag(ses->sectype)) { + cifs_dbg(FYI, "Requesting extended security."); pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; } -#ifdef CONFIG_CIFS_EXPERIMENTAL - else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP) - pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) { - cFYI(1, "NTLMSSP only mechanism, enable extended security"); - pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - } -#endif count = 0; for (i = 0; i < CIFS_NUM_PROT; i++) { @@ -417,7 +580,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) count += strlen(protocols[i].name) + 1; /* null at end of source and target buffers anyway */ } - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, @@ -426,7 +589,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) goto neg_err_exit; server->dialect = le16_to_cpu(pSMBr->DialectIndex); - cFYI(1, "Dialect: %d", server->dialect); + cifs_dbg(FYI, "Dialect: %d\n", server->dialect); /* Check wct = 1 error case */ if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) { /* core returns wct = 1, but we do not ask for core - otherwise @@ -434,250 +597,67 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) could not negotiate a common dialect */ rc = -EOPNOTSUPP; goto neg_err_exit; -#ifdef CONFIG_CIFS_WEAK_PW_HASH - } else if ((pSMBr->hdr.WordCount == 13) - && ((server->dialect == LANMAN_PROT) - || (server->dialect == LANMAN2_PROT))) { - __s16 tmp; - struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr; - - if ((secFlags & CIFSSEC_MAY_LANMAN) || - (secFlags & CIFSSEC_MAY_PLNTXT)) - server->secType = LANMAN; - else { - cERROR(1, "mount failed weak security disabled" - " in /proc/fs/cifs/SecurityFlags"); - rc = -EOPNOTSUPP; - goto neg_err_exit; - } - server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); - server->maxReq = le16_to_cpu(rsp->MaxMpxCount); - server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), - (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); - server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); - GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); - /* even though we do not use raw we might as well set this - accurately, in case we ever find a need for it */ - if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { - server->max_rw = 0xFF00; - server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; - } else { - server->max_rw = 0;/* do not need to use raw anyway */ - server->capabilities = CAP_MPX_MODE; - } - tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); - if (tmp == -1) { - /* OS/2 often does not set timezone therefore - * we must use server time to calc time zone. - * Could deviate slightly from the right zone. - * Smallest defined timezone difference is 15 minutes - * (i.e. Nepal). Rounding up/down is done to match - * this requirement. - */ - int val, seconds, remain, result; - struct timespec ts, utc; - utc = CURRENT_TIME; - ts = cnvrtDosUnixTm(rsp->SrvTime.Date, - rsp->SrvTime.Time, 0); - cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d", - (int)ts.tv_sec, (int)utc.tv_sec, - (int)(utc.tv_sec - ts.tv_sec)); - val = (int)(utc.tv_sec - ts.tv_sec); - seconds = abs(val); - result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; - remain = seconds % MIN_TZ_ADJ; - if (remain >= (MIN_TZ_ADJ / 2)) - result += MIN_TZ_ADJ; - if (val < 0) - result = -result; - server->timeAdj = result; - } else { - server->timeAdj = (int)tmp; - server->timeAdj *= 60; /* also in seconds */ - } - cFYI(1, "server->timeAdj: %d seconds", server->timeAdj); - - - /* BB get server time for time conversions and add - code to use it and timezone since this is not UTC */ - - if (rsp->EncryptionKeyLength == - cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { - memcpy(ses->server->cryptkey, rsp->EncryptionKey, - CIFS_CRYPTO_KEY_SIZE); - } else if (server->secMode & SECMODE_PW_ENCRYPT) { - rc = -EIO; /* need cryptkey unless plain text */ - goto neg_err_exit; - } - - cFYI(1, "LANMAN negotiated"); - /* we will not end up setting signing flags - as no signing - was in LANMAN and server did not return the flags on */ - goto signing_check; -#else /* weak security disabled */ } else if (pSMBr->hdr.WordCount == 13) { - cERROR(1, "mount failed, cifs module not built " - "with CIFS_WEAK_PW_HASH support"); - rc = -EOPNOTSUPP; -#endif /* WEAK_PW_HASH */ - goto neg_err_exit; + server->negflavor = CIFS_NEGFLAVOR_LANMAN; + rc = decode_lanman_negprot_rsp(server, pSMBr); + goto signing_check; } else if (pSMBr->hdr.WordCount != 17) { /* unknown wct */ rc = -EOPNOTSUPP; goto neg_err_exit; } - /* else wct == 17 NTLM */ - server->secMode = pSMBr->SecurityMode; - if ((server->secMode & SECMODE_USER) == 0) - cFYI(1, "share mode security"); + /* else wct == 17, NTLM or better */ - if ((server->secMode & SECMODE_PW_ENCRYPT) == 0) -#ifdef CONFIG_CIFS_WEAK_PW_HASH - if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0) -#endif /* CIFS_WEAK_PW_HASH */ - cERROR(1, "Server requests plain text password" - " but client support disabled"); - - if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2) - server->secType = NTLMv2; - else if (secFlags & CIFSSEC_MAY_NTLM) - server->secType = NTLM; - else if (secFlags & CIFSSEC_MAY_NTLMV2) - server->secType = NTLMv2; - else if (secFlags & CIFSSEC_MAY_KRB5) - server->secType = Kerberos; - else if (secFlags & CIFSSEC_MAY_NTLMSSP) - server->secType = RawNTLMSSP; - else if (secFlags & CIFSSEC_MAY_LANMAN) - server->secType = LANMAN; -/* #ifdef CONFIG_CIFS_EXPERIMENTAL - else if (secFlags & CIFSSEC_MAY_PLNTXT) - server->secType = ?? -#endif */ - else { - rc = -EOPNOTSUPP; - cERROR(1, "Invalid security type"); - goto neg_err_exit; - } - /* else ... any others ...? */ + server->sec_mode = pSMBr->SecurityMode; + if ((server->sec_mode & SECMODE_USER) == 0) + cifs_dbg(FYI, "share mode security\n"); /* one byte, so no need to convert this or EncryptionKeyLen from little endian */ - server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); + server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), + cifs_max_pending); + set_credits(server, server->maxReq); /* probably no need to store and check maxvcs */ - server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize), - (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); + server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); - cFYI(DBG2, "Max buf = %d", ses->server->maxBuf); - GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); + cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf); server->capabilities = le32_to_cpu(pSMBr->Capabilities); server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); server->timeAdj *= 60; + if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { + server->negflavor = CIFS_NEGFLAVOR_UNENCAP; memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey, CIFS_CRYPTO_KEY_SIZE); - } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) - && (pSMBr->EncryptionKeyLength == 0)) { - /* decode security blob */ - } else if (server->secMode & SECMODE_PW_ENCRYPT) { + } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC || + server->capabilities & CAP_EXTENDED_SECURITY) && + (pSMBr->EncryptionKeyLength == 0)) { + server->negflavor = CIFS_NEGFLAVOR_EXTENDED; + rc = decode_ext_sec_blob(ses, pSMBr); + } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { rc = -EIO; /* no crypt key only if plain text pwd */ - goto neg_err_exit; - } - - /* BB might be helpful to save off the domain of server here */ - - if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && - (server->capabilities & CAP_EXTENDED_SECURITY)) { - count = pSMBr->ByteCount; - if (count < 16) { - rc = -EIO; - goto neg_err_exit; - } - spin_lock(&cifs_tcp_ses_lock); - if (server->srv_count > 1) { - spin_unlock(&cifs_tcp_ses_lock); - if (memcmp(server->server_GUID, - pSMBr->u.extended_response. - GUID, 16) != 0) { - cFYI(1, "server UID changed"); - memcpy(server->server_GUID, - pSMBr->u.extended_response.GUID, - 16); - } - } else { - spin_unlock(&cifs_tcp_ses_lock); - memcpy(server->server_GUID, - pSMBr->u.extended_response.GUID, 16); - } - - if (count == 16) { - server->secType = RawNTLMSSP; - } else { - rc = decode_negTokenInit(pSMBr->u.extended_response. - SecurityBlob, count - 16, - server); - if (rc == 1) - rc = 0; - else - rc = -EINVAL; - if (server->secType == Kerberos) { - if (!server->sec_kerberos && - !server->sec_mskerberos) - rc = -EOPNOTSUPP; - } else if (server->secType == RawNTLMSSP) { - if (!server->sec_ntlmssp) - rc = -EOPNOTSUPP; - } else - rc = -EOPNOTSUPP; - } - } else - server->capabilities &= ~CAP_EXTENDED_SECURITY; - -#ifdef CONFIG_CIFS_WEAK_PW_HASH -signing_check: -#endif - if ((secFlags & CIFSSEC_MAY_SIGN) == 0) { - /* MUST_SIGN already includes the MAY_SIGN FLAG - so if this is zero it means that signing is disabled */ - cFYI(1, "Signing disabled"); - if (server->secMode & SECMODE_SIGN_REQUIRED) { - cERROR(1, "Server requires " - "packet signing to be enabled in " - "/proc/fs/cifs/SecurityFlags."); - rc = -EOPNOTSUPP; - } - server->secMode &= - ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); - } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) { - /* signing required */ - cFYI(1, "Must sign - secFlags 0x%x", secFlags); - if ((server->secMode & - (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) { - cERROR(1, "signing required but server lacks support"); - rc = -EOPNOTSUPP; - } else - server->secMode |= SECMODE_SIGN_REQUIRED; } else { - /* signing optional ie CIFSSEC_MAY_SIGN */ - if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0) - server->secMode &= - ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); + server->negflavor = CIFS_NEGFLAVOR_UNENCAP; + server->capabilities &= ~CAP_EXTENDED_SECURITY; } +signing_check: + if (!rc) + rc = cifs_enable_signing(server, ses->sign); neg_err_exit: cifs_buf_release(pSMB); - cFYI(1, "negprot rc %d", rc); + cifs_dbg(FYI, "negprot rc %d\n", rc); return rc; } int -CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) +CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon) { struct smb_hdr *smb_buffer; int rc = 0; - cFYI(1, "In tree disconnect"); + cifs_dbg(FYI, "In tree disconnect\n"); /* BB: do we need to check this? These should never be NULL. */ if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) @@ -697,9 +677,9 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) if (rc) return rc; - rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0); if (rc) - cFYI(1, "Tree disconnect failed %d", rc); + cifs_dbg(FYI, "Tree disconnect failed %d\n", rc); /* No need to return error on this operation if tid invalidated and closed on server already e.g. due to tcp session crashing */ @@ -709,13 +689,64 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) return rc; } +/* + * This is a no-op for now. We're not really interested in the reply, but + * rather in the fact that the server sent one and that server->lstrp + * gets updated. + * + * FIXME: maybe we should consider checking that the reply matches request? + */ +static void +cifs_echo_callback(struct mid_q_entry *mid) +{ + struct TCP_Server_Info *server = mid->callback_data; + + DeleteMidQEntry(mid); + add_credits(server, 1, CIFS_ECHO_OP); +} + int -CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) +CIFSSMBEcho(struct TCP_Server_Info *server) +{ + ECHO_REQ *smb; + int rc = 0; + struct kvec iov; + struct smb_rqst rqst = { .rq_iov = &iov, + .rq_nvec = 1 }; + + cifs_dbg(FYI, "In echo request\n"); + + rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb); + if (rc) + return rc; + + /* set up echo request */ + smb->hdr.Tid = 0xffff; + smb->hdr.WordCount = 1; + put_unaligned_le16(1, &smb->EchoCount); + put_bcc(1, &smb->hdr); + smb->Data[0] = 'a'; + inc_rfc1001_len(smb, 3); + iov.iov_base = smb; + iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4; + + rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, + server, CIFS_ASYNC_OP | CIFS_ECHO_OP); + if (rc) + cifs_dbg(FYI, "Echo request failed: %d\n", rc); + + cifs_small_buf_release(smb); + + return rc; +} + +int +CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses) { LOGOFF_ANDX_REQ *pSMB; int rc = 0; - cFYI(1, "In SMBLogoff for session disconnect"); + cifs_dbg(FYI, "In SMBLogoff for session disconnect\n"); /* * BB: do we need to check validity of ses and server? They should @@ -735,16 +766,15 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) return rc; } - pSMB->hdr.Mid = GetNextMid(ses->server); + pSMB->hdr.Mid = get_next_mid(ses->server); - if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if (ses->server->sign) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->hdr.Uid = ses->Suid; pSMB->AndXCommand = 0xFF; - rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); + rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0); session_already_dead: mutex_unlock(&ses->session_mutex); @@ -757,8 +787,9 @@ session_already_dead: } int -CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, - __u16 type, const struct nls_table *nls_codepage, int remap) +CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, __u16 type, + const struct nls_table *nls_codepage, int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -768,7 +799,7 @@ CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, int bytes_returned = 0; __u16 params, param_offset, offset, byte_count; - cFYI(1, "In POSIX delete"); + cifs_dbg(FYI, "In POSIX delete\n"); PsxDelete: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -777,8 +808,8 @@ PsxDelete: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB add path length overrun check */ @@ -815,15 +846,15 @@ PsxDelete: pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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, "Posix delete returned %d", rc); + cifs_dbg(FYI, "Posix delete returned %d\n", rc); cifs_buf_release(pSMB); - cifs_stats_inc(&tcon->num_deletes); + cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes); if (rc == -EAGAIN) goto PsxDelete; @@ -832,14 +863,15 @@ PsxDelete: } int -CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, - const struct nls_table *nls_codepage, int remap) +CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name, + struct cifs_sb_info *cifs_sb) { DELETE_FILE_REQ *pSMB = NULL; DELETE_FILE_RSP *pSMBr = NULL; int rc = 0; int bytes_returned; int name_len; + int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; DelFileRetry: rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, @@ -848,26 +880,26 @@ DelFileRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = - cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, - PATH_MAX, nls_codepage, remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name, + PATH_MAX, cifs_sb->local_nls, + remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ - name_len = strnlen(fileName, PATH_MAX); + name_len = strnlen(name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->fileName, fileName, name_len); + strncpy(pSMB->fileName, name, name_len); } pSMB->SearchAttributes = cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); - cifs_stats_inc(&tcon->num_deletes); + cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes); if (rc) - cFYI(1, "Error in RMFile = %d", rc); + cifs_dbg(FYI, "Error in RMFile = %d\n", rc); cifs_buf_release(pSMB); if (rc == -EAGAIN) @@ -877,16 +909,17 @@ DelFileRetry: } int -CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, - const struct nls_table *nls_codepage, int remap) +CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, + struct cifs_sb_info *cifs_sb) { DELETE_DIRECTORY_REQ *pSMB = NULL; DELETE_DIRECTORY_RSP *pSMBr = NULL; int rc = 0; int bytes_returned; int name_len; + int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; - cFYI(1, "In CIFSSMBRmDir"); + cifs_dbg(FYI, "In CIFSSMBRmDir\n"); RmDirRetry: rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -894,24 +927,25 @@ RmDirRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName, - PATH_MAX, nls_codepage, remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, + PATH_MAX, cifs_sb->local_nls, + remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ - name_len = strnlen(dirName, PATH_MAX); + name_len = strnlen(name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->DirName, dirName, name_len); + strncpy(pSMB->DirName, name, name_len); } pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); - cifs_stats_inc(&tcon->num_rmdirs); + cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs); if (rc) - cFYI(1, "Error in RMDir = %d", rc); + cifs_dbg(FYI, "Error in RMDir = %d\n", rc); cifs_buf_release(pSMB); if (rc == -EAGAIN) @@ -920,16 +954,17 @@ RmDirRetry: } int -CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, - const char *name, const struct nls_table *nls_codepage, int remap) +CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, + struct cifs_sb_info *cifs_sb) { int rc = 0; CREATE_DIRECTORY_REQ *pSMB = NULL; CREATE_DIRECTORY_RSP *pSMBr = NULL; int bytes_returned; int name_len; + int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; - cFYI(1, "In CIFSSMBMkDir"); + cifs_dbg(FYI, "In CIFSSMBMkDir\n"); MkDirRetry: rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -937,8 +972,9 @@ MkDirRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, - PATH_MAX, nls_codepage, remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, + PATH_MAX, cifs_sb->local_nls, + remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ @@ -948,13 +984,13 @@ MkDirRetry: } pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); - cifs_stats_inc(&tcon->num_mkdirs); + cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs); if (rc) - cFYI(1, "Error in Mkdir = %d", rc); + cifs_dbg(FYI, "Error in Mkdir = %d\n", rc); cifs_buf_release(pSMB); if (rc == -EAGAIN) @@ -963,10 +999,11 @@ MkDirRetry: } int -CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags, - __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData, - __u32 *pOplock, const char *name, - const struct nls_table *nls_codepage, int remap) +CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, + __u32 posix_flags, __u64 mode, __u16 *netfid, + FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock, + const char *name, const struct nls_table *nls_codepage, + int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -977,7 +1014,7 @@ CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags, OPEN_PSX_REQ *pdata; OPEN_PSX_RSP *psx_rsp; - cFYI(1, "In POSIX Create"); + cifs_dbg(FYI, "In POSIX Create\n"); PsxCreat: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -986,8 +1023,8 @@ PsxCreat: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, name, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, name, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -1026,19 +1063,19 @@ PsxCreat: pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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, "Posix create returned %d", rc); + cifs_dbg(FYI, "Posix create returned %d\n", rc); goto psx_create_err; } - cFYI(1, "copying inode info"); + cifs_dbg(FYI, "copying inode info\n"); rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) { + if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) { rc = -EIO; /* bad smb */ goto psx_create_err; } @@ -1057,11 +1094,11 @@ PsxCreat: /* check to make sure response data is there */ if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) { pRetData->Type = cpu_to_le32(-1); /* unknown */ - cFYI(DBG2, "unknown type"); + cifs_dbg(NOISY, "unknown type\n"); } else { - if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP) + if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP) + sizeof(FILE_UNIX_BASIC_INFO)) { - cERROR(1, "Open response data too small"); + cifs_dbg(VFS, "Open response data too small\n"); pRetData->Type = cpu_to_le32(-1); goto psx_create_err; } @@ -1074,9 +1111,9 @@ psx_create_err: cifs_buf_release(pSMB); if (posix_flags & SMB_O_DIRECTORY) - cifs_stats_inc(&tcon->num_posixmkdirs); + cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs); else - cifs_stats_inc(&tcon->num_posixopens); + cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens); if (rc == -EAGAIN) goto PsxCreat; @@ -1108,7 +1145,7 @@ static __u16 convert_disposition(int disposition) ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; break; default: - cFYI(1, "unknown disposition %d", disposition); + cifs_dbg(FYI, "unknown disposition %d\n", disposition); ofun = SMBOPEN_OAPPEND; /* regular open */ } return ofun; @@ -1129,7 +1166,7 @@ access_flags_to_smbopen_mode(const int access_flags) } int -SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, +SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const int openDisposition, const int access_flags, const int create_options, __u16 *netfid, int *pOplock, FILE_ALL_INFO *pfile_info, @@ -1153,8 +1190,8 @@ OldOpenRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { count = 1; /* account for one byte pad to word boundary */ name_len = - cifsConvertToUCS((__le16 *) (pSMB->fileName + 1), - fileName, PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1), + fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ @@ -1191,15 +1228,15 @@ OldOpenRetry: pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); count += name_len; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); /* long_op set to 1 to allow for oplock break timeouts */ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); - cifs_stats_inc(&tcon->num_opens); + (struct smb_hdr *)pSMBr, &bytes_returned, 0); + cifs_stats_inc(&tcon->stats.cifs_stats.num_opens); if (rc) { - cFYI(1, "Error in Open = %d", rc); + cifs_dbg(FYI, "Error in Open = %d\n", rc); } else { /* BB verify if wct == 15 */ @@ -1236,111 +1273,377 @@ OldOpenRetry: } int -CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, - const char *fileName, const int openDisposition, - const int access_flags, const int create_options, __u16 *netfid, - int *pOplock, FILE_ALL_INFO *pfile_info, - const struct nls_table *nls_codepage, int remap) +CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock, + FILE_ALL_INFO *buf) { int rc = -EACCES; - OPEN_REQ *pSMB = NULL; - OPEN_RSP *pSMBr = NULL; + OPEN_REQ *req = NULL; + OPEN_RSP *rsp = NULL; int bytes_returned; int name_len; __u16 count; + struct cifs_sb_info *cifs_sb = oparms->cifs_sb; + struct cifs_tcon *tcon = oparms->tcon; + int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; + const struct nls_table *nls = cifs_sb->local_nls; + int create_options = oparms->create_options; + int desired_access = oparms->desired_access; + int disposition = oparms->disposition; + const char *path = oparms->path; openRetry: - rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req, + (void **)&rsp); if (rc) return rc; - pSMB->AndXCommand = 0xFF; /* none */ + /* no commands go after this */ + req->AndXCommand = 0xFF; - if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - count = 1; /* account for one byte pad to word boundary */ - name_len = - cifsConvertToUCS((__le16 *) (pSMB->fileName + 1), - fileName, PATH_MAX, nls_codepage, remap); - name_len++; /* trailing null */ + if (req->hdr.Flags2 & SMBFLG2_UNICODE) { + /* account for one byte pad to word boundary */ + count = 1; + name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1), + path, PATH_MAX, nls, remap); + /* trailing null */ + name_len++; name_len *= 2; - pSMB->NameLength = cpu_to_le16(name_len); - } else { /* BB improve check for buffer overruns BB */ - count = 0; /* no pad */ - name_len = strnlen(fileName, PATH_MAX); - name_len++; /* trailing null */ - pSMB->NameLength = cpu_to_le16(name_len); - strncpy(pSMB->fileName, fileName, name_len); + req->NameLength = cpu_to_le16(name_len); + } else { + /* BB improve check for buffer overruns BB */ + /* no pad */ + count = 0; + name_len = strnlen(path, PATH_MAX); + /* trailing null */ + name_len++; + req->NameLength = cpu_to_le16(name_len); + strncpy(req->fileName, path, name_len); } - if (*pOplock & REQ_OPLOCK) - pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK); - else if (*pOplock & REQ_BATCHOPLOCK) - pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); - pSMB->DesiredAccess = cpu_to_le32(access_flags); - pSMB->AllocationSize = 0; - /* set file as system file if special file such - as fifo and server expecting SFU style and - no Unix extensions */ + + if (*oplock & REQ_OPLOCK) + req->OpenFlags = cpu_to_le32(REQ_OPLOCK); + else if (*oplock & REQ_BATCHOPLOCK) + req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); + + req->DesiredAccess = cpu_to_le32(desired_access); + req->AllocationSize = 0; + + /* + * Set file as system file if special file such as fifo and server + * expecting SFU style and no Unix extensions. + */ if (create_options & CREATE_OPTION_SPECIAL) - pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); + req->FileAttributes = cpu_to_le32(ATTR_SYSTEM); else - pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); + req->FileAttributes = cpu_to_le32(ATTR_NORMAL); - /* XP does not handle ATTR_POSIX_SEMANTICS */ - /* but it helps speed up case sensitive checks for other - servers such as Samba */ + /* + * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case + * sensitive checks for other servers such as Samba. + */ if (tcon->ses->capabilities & CAP_UNIX) - pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); + req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); if (create_options & CREATE_OPTION_READONLY) - pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY); + req->FileAttributes |= cpu_to_le32(ATTR_READONLY); + + req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); + req->CreateDisposition = cpu_to_le32(disposition); + req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); - pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); - pSMB->CreateDisposition = cpu_to_le32(openDisposition); - pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); /* BB Expirement with various impersonation levels and verify */ - pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); - pSMB->SecurityFlags = - SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY; + req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); + req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY; count += name_len; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(req, count); - pSMB->ByteCount = cpu_to_le16(count); - /* long_op set to 1 to allow for oplock break timeouts */ - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); - cifs_stats_inc(&tcon->num_opens); + req->ByteCount = cpu_to_le16(count); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req, + (struct smb_hdr *)rsp, &bytes_returned, 0); + cifs_stats_inc(&tcon->stats.cifs_stats.num_opens); if (rc) { - cFYI(1, "Error in Open = %d", rc); - } else { - *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */ - *netfid = pSMBr->Fid; /* cifs fid stays in le */ - /* Let caller know file was created so we can set the mode. */ - /* Do we care about the CreateAction in any other cases? */ - if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) - *pOplock |= CIFS_CREATE_ACTION; - if (pfile_info) { - memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime, - 36 /* CreationTime to Attributes */); - /* the file_info buf is endian converted by caller */ - pfile_info->AllocationSize = pSMBr->AllocationSize; - pfile_info->EndOfFile = pSMBr->EndOfFile; - pfile_info->NumberOfLinks = cpu_to_le32(1); - pfile_info->DeletePending = 0; + cifs_dbg(FYI, "Error in Open = %d\n", rc); + cifs_buf_release(req); + if (rc == -EAGAIN) + goto openRetry; + return rc; + } + + /* 1 byte no need to le_to_cpu */ + *oplock = rsp->OplockLevel; + /* cifs fid stays in le */ + oparms->fid->netfid = rsp->Fid; + + /* Let caller know file was created so we can set the mode. */ + /* Do we care about the CreateAction in any other cases? */ + if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction) + *oplock |= CIFS_CREATE_ACTION; + + if (buf) { + /* copy from CreationTime to Attributes */ + memcpy((char *)buf, (char *)&rsp->CreationTime, 36); + /* the file_info buf is endian converted by caller */ + buf->AllocationSize = rsp->AllocationSize; + buf->EndOfFile = rsp->EndOfFile; + buf->NumberOfLinks = cpu_to_le32(1); + buf->DeletePending = 0; + } + + cifs_buf_release(req); + return rc; +} + +/* + * Discard any remaining data in the current SMB. To do this, we borrow the + * current bigbuf. + */ +static int +cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) +{ + unsigned int rfclen = get_rfc1002_length(server->smallbuf); + int remaining = rfclen + 4 - server->total_read; + struct cifs_readdata *rdata = mid->callback_data; + + while (remaining > 0) { + int length; + + length = cifs_read_from_socket(server, server->bigbuf, + min_t(unsigned int, remaining, + CIFSMaxBufSize + MAX_HEADER_SIZE(server))); + if (length < 0) + return length; + server->total_read += length; + remaining -= length; + } + + dequeue_mid(mid, rdata->result); + return 0; +} + +int +cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) +{ + int length, len; + unsigned int data_offset, data_len; + struct cifs_readdata *rdata = mid->callback_data; + char *buf = server->smallbuf; + unsigned int buflen = get_rfc1002_length(buf) + 4; + + cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n", + __func__, mid->mid, rdata->offset, rdata->bytes); + + /* + * read the rest of READ_RSP header (sans Data array), or whatever we + * can if there's not enough data. At this point, we've read down to + * the Mid. + */ + len = min_t(unsigned int, buflen, server->vals->read_rsp_size) - + HEADER_SIZE(server) + 1; + + rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1; + rdata->iov.iov_len = len; + + length = cifs_readv_from_socket(server, &rdata->iov, 1, len); + if (length < 0) + return length; + server->total_read += length; + + /* Was the SMB read successful? */ + rdata->result = server->ops->map_error(buf, false); + if (rdata->result != 0) { + cifs_dbg(FYI, "%s: server returned error %d\n", + __func__, rdata->result); + return cifs_readv_discard(server, mid); + } + + /* Is there enough to get to the rest of the READ_RSP header? */ + if (server->total_read < server->vals->read_rsp_size) { + cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n", + __func__, server->total_read, + server->vals->read_rsp_size); + rdata->result = -EIO; + return cifs_readv_discard(server, mid); + } + + data_offset = server->ops->read_data_offset(buf) + 4; + if (data_offset < server->total_read) { + /* + * win2k8 sometimes sends an offset of 0 when the read + * is beyond the EOF. Treat it as if the data starts just after + * the header. + */ + cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n", + __func__, data_offset); + data_offset = server->total_read; + } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) { + /* data_offset is beyond the end of smallbuf */ + cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n", + __func__, data_offset); + rdata->result = -EIO; + return cifs_readv_discard(server, mid); + } + + cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n", + __func__, server->total_read, data_offset); + + len = data_offset - server->total_read; + if (len > 0) { + /* read any junk before data into the rest of smallbuf */ + rdata->iov.iov_base = buf + server->total_read; + rdata->iov.iov_len = len; + length = cifs_readv_from_socket(server, &rdata->iov, 1, len); + if (length < 0) + return length; + server->total_read += length; + } + + /* set up first iov for signature check */ + rdata->iov.iov_base = buf; + rdata->iov.iov_len = server->total_read; + cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", + rdata->iov.iov_base, rdata->iov.iov_len); + + /* how much data is in the response? */ + data_len = server->ops->read_data_length(buf); + if (data_offset + data_len > buflen) { + /* data_len is corrupt -- discard frame */ + rdata->result = -EIO; + return cifs_readv_discard(server, mid); + } + + length = rdata->read_into_pages(server, rdata, data_len); + if (length < 0) + return length; + + server->total_read += length; + rdata->bytes = length; + + cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n", + server->total_read, buflen, data_len); + + /* discard anything left over */ + if (server->total_read < buflen) + return cifs_readv_discard(server, mid); + + dequeue_mid(mid, false); + return length; +} + +static void +cifs_readv_callback(struct mid_q_entry *mid) +{ + struct cifs_readdata *rdata = mid->callback_data; + struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); + struct TCP_Server_Info *server = tcon->ses->server; + struct smb_rqst rqst = { .rq_iov = &rdata->iov, + .rq_nvec = 1, + .rq_pages = rdata->pages, + .rq_npages = rdata->nr_pages, + .rq_pagesz = rdata->pagesz, + .rq_tailsz = rdata->tailsz }; + + cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n", + __func__, mid->mid, mid->mid_state, rdata->result, + rdata->bytes); + + switch (mid->mid_state) { + case MID_RESPONSE_RECEIVED: + /* result already set, check signature */ + if (server->sign) { + int rc = 0; + + rc = cifs_verify_signature(&rqst, server, + mid->sequence_number); + if (rc) + cifs_dbg(VFS, "SMB signature verification returned error = %d\n", + rc); } + /* FIXME: should this be counted toward the initiating task? */ + task_io_account_read(rdata->bytes); + cifs_stats_bytes_read(tcon, rdata->bytes); + break; + case MID_REQUEST_SUBMITTED: + case MID_RETRY_NEEDED: + rdata->result = -EAGAIN; + break; + default: + rdata->result = -EIO; } - cifs_buf_release(pSMB); - if (rc == -EAGAIN) - goto openRetry; + queue_work(cifsiod_wq, &rdata->work); + DeleteMidQEntry(mid); + add_credits(server, 1, 0); +} + +/* cifs_async_readv - send an async write, and set up mid to handle result */ +int +cifs_async_readv(struct cifs_readdata *rdata) +{ + int rc; + READ_REQ *smb = NULL; + int wct; + struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); + struct smb_rqst rqst = { .rq_iov = &rdata->iov, + .rq_nvec = 1 }; + + cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", + __func__, rdata->offset, rdata->bytes); + + if (tcon->ses->capabilities & CAP_LARGE_FILES) + wct = 12; + else { + wct = 10; /* old style read */ + if ((rdata->offset >> 32) > 0) { + /* can not handle this big offset for old */ + return -EIO; + } + } + + rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb); + if (rc) + return rc; + + smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid); + smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16)); + + smb->AndXCommand = 0xFF; /* none */ + smb->Fid = rdata->cfile->fid.netfid; + smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF); + if (wct == 12) + smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32); + smb->Remaining = 0; + smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF); + smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16); + if (wct == 12) + smb->ByteCount = 0; + else { + /* old style read */ + struct smb_com_readx_req *smbr = + (struct smb_com_readx_req *)smb; + smbr->ByteCount = 0; + } + + /* 4 for RFC1001 length + 1 for BCC */ + rdata->iov.iov_base = smb; + rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4; + + kref_get(&rdata->refcount); + rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive, + cifs_readv_callback, rdata, 0); + + if (rc == 0) + cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); + else + kref_put(&rdata->refcount, cifs_readdata_release); + + cifs_small_buf_release(smb); return rc; } int -CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, - const unsigned int count, const __u64 lseek, unsigned int *nbytes, - char **buf, int *pbuf_type) +CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms, + unsigned int *nbytes, char **buf, int *pbuf_type) { int rc = -EACCES; READ_REQ *pSMB = NULL; @@ -1349,13 +1652,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, int wct; int resp_buf_type = 0; struct kvec iov[1]; + __u32 pid = io_parms->pid; + __u16 netfid = io_parms->netfid; + __u64 offset = io_parms->offset; + struct cifs_tcon *tcon = io_parms->tcon; + unsigned int count = io_parms->length; - cFYI(1, "Reading %d bytes on fid %d", count, netfid); + cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid); if (tcon->ses->capabilities & CAP_LARGE_FILES) wct = 12; else { wct = 10; /* old style read */ - if ((lseek >> 32) > 0) { + if ((offset >> 32) > 0) { /* can not handle this big offset for old */ return -EIO; } @@ -1366,15 +1674,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, if (rc) return rc; + pSMB->hdr.Pid = cpu_to_le16((__u16)pid); + pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); + /* tcon and ses pointer are checked in smb_init */ if (tcon->ses->server == NULL) return -ECONNABORTED; pSMB->AndXCommand = 0xFF; /* none */ pSMB->Fid = netfid; - pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); + pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); if (wct == 12) - pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); + pSMB->OffsetHigh = cpu_to_le32(offset >> 32); pSMB->Remaining = 0; pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); @@ -1389,13 +1700,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, } iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, - &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR); - cifs_stats_inc(&tcon->num_reads); + &resp_buf_type, CIFS_LOG_ERROR); + cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); pSMBr = (READ_RSP *)iov[0].iov_base; if (rc) { - cERROR(1, "Send error in read = %d", rc); + cifs_dbg(VFS, "Send error in read = %d\n", rc); } else { int data_length = le16_to_cpu(pSMBr->DataLengthHigh); data_length = data_length << 16; @@ -1405,7 +1716,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, /*check that DataLength would not go beyond end of SMB */ if ((data_length > CIFSMaxBufSize) || (data_length > count)) { - cFYI(1, "bad length %d for count %d", + cifs_dbg(FYI, "bad length %d for count %d\n", data_length, count); rc = -EIO; *nbytes = 0; @@ -1413,7 +1724,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, pReadData = (char *) (&pSMBr->hdr.Protocol) + le16_to_cpu(pSMBr->DataOffset); /* if (rc = copy_to_user(buf, pReadData, data_length)) { - cERROR(1, "Faulting on read rc = %d",rc); + cifs_dbg(VFS, "Faulting on read rc = %d\n",rc); rc = -EFAULT; }*/ /* can not use copy_to_user when using page cache*/ if (*buf) @@ -1443,9 +1754,8 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, int -CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, - const int netfid, const unsigned int count, - const __u64 offset, unsigned int *nbytes, const char *buf, +CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, + unsigned int *nbytes, const char *buf, const char __user *ubuf, const int long_op) { int rc = -EACCES; @@ -1454,10 +1764,15 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, int bytes_returned, wct; __u32 bytes_sent; __u16 byte_count; + __u32 pid = io_parms->pid; + __u16 netfid = io_parms->netfid; + __u64 offset = io_parms->offset; + struct cifs_tcon *tcon = io_parms->tcon; + unsigned int count = io_parms->length; *nbytes = 0; - /* cFYI(1, "write at %lld %d bytes", offset, count);*/ + /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/ if (tcon->ses == NULL) return -ECONNABORTED; @@ -1475,6 +1790,10 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, (void **) &pSMBr); if (rc) return rc; + + pSMB->hdr.Pid = cpu_to_le16((__u16)pid); + pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); + /* tcon and ses pointer are checked in smb_init */ if (tcon->ses->server == NULL) return -ECONNABORTED; @@ -1523,7 +1842,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); if (wct == 14) pSMB->ByteCount = cpu_to_le16(byte_count); @@ -1536,9 +1855,9 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, long_op); - cifs_stats_inc(&tcon->num_writes); + cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); if (rc) { - cFYI(1, "Send error in write = %d", rc); + cifs_dbg(FYI, "Send error in write = %d\n", rc); } else { *nbytes = le16_to_cpu(pSMBr->CountHigh); *nbytes = (*nbytes) << 16; @@ -1561,21 +1880,251 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, return rc; } +void +cifs_writedata_release(struct kref *refcount) +{ + struct cifs_writedata *wdata = container_of(refcount, + struct cifs_writedata, refcount); + + if (wdata->cfile) + cifsFileInfo_put(wdata->cfile); + + kfree(wdata); +} + +/* + * Write failed with a retryable error. Resend the write request. It's also + * possible that the page was redirtied so re-clean the page. + */ +static void +cifs_writev_requeue(struct cifs_writedata *wdata) +{ + int i, rc; + struct inode *inode = wdata->cfile->dentry->d_inode; + struct TCP_Server_Info *server; + + for (i = 0; i < wdata->nr_pages; i++) { + lock_page(wdata->pages[i]); + clear_page_dirty_for_io(wdata->pages[i]); + } + + do { + server = tlink_tcon(wdata->cfile->tlink)->ses->server; + rc = server->ops->async_writev(wdata, cifs_writedata_release); + } while (rc == -EAGAIN); + + for (i = 0; i < wdata->nr_pages; i++) { + unlock_page(wdata->pages[i]); + if (rc != 0) { + SetPageError(wdata->pages[i]); + end_page_writeback(wdata->pages[i]); + page_cache_release(wdata->pages[i]); + } + } + + mapping_set_error(inode->i_mapping, rc); + kref_put(&wdata->refcount, cifs_writedata_release); +} + +void +cifs_writev_complete(struct work_struct *work) +{ + struct cifs_writedata *wdata = container_of(work, + struct cifs_writedata, work); + struct inode *inode = wdata->cfile->dentry->d_inode; + int i = 0; + + if (wdata->result == 0) { + spin_lock(&inode->i_lock); + cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes); + spin_unlock(&inode->i_lock); + cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink), + wdata->bytes); + } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN) + return cifs_writev_requeue(wdata); + + for (i = 0; i < wdata->nr_pages; i++) { + struct page *page = wdata->pages[i]; + if (wdata->result == -EAGAIN) + __set_page_dirty_nobuffers(page); + else if (wdata->result < 0) + SetPageError(page); + end_page_writeback(page); + page_cache_release(page); + } + if (wdata->result != -EAGAIN) + mapping_set_error(inode->i_mapping, wdata->result); + kref_put(&wdata->refcount, cifs_writedata_release); +} + +struct cifs_writedata * +cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete) +{ + struct cifs_writedata *wdata; + + /* writedata + number of page pointers */ + wdata = kzalloc(sizeof(*wdata) + + sizeof(struct page *) * nr_pages, GFP_NOFS); + if (wdata != NULL) { + kref_init(&wdata->refcount); + INIT_LIST_HEAD(&wdata->list); + init_completion(&wdata->done); + INIT_WORK(&wdata->work, complete); + } + return wdata; +} + +/* + * Check the mid_state and signature on received buffer (if any), and queue the + * workqueue completion task. + */ +static void +cifs_writev_callback(struct mid_q_entry *mid) +{ + struct cifs_writedata *wdata = mid->callback_data; + struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); + unsigned int written; + WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf; + + switch (mid->mid_state) { + case MID_RESPONSE_RECEIVED: + wdata->result = cifs_check_receive(mid, tcon->ses->server, 0); + if (wdata->result != 0) + break; + + written = le16_to_cpu(smb->CountHigh); + written <<= 16; + written += le16_to_cpu(smb->Count); + /* + * Mask off high 16 bits when bytes written as returned + * by the server is greater than bytes requested by the + * client. OS/2 servers are known to set incorrect + * CountHigh values. + */ + if (written > wdata->bytes) + written &= 0xFFFF; + + if (written < wdata->bytes) + wdata->result = -ENOSPC; + else + wdata->bytes = written; + break; + case MID_REQUEST_SUBMITTED: + case MID_RETRY_NEEDED: + wdata->result = -EAGAIN; + break; + default: + wdata->result = -EIO; + break; + } + + queue_work(cifsiod_wq, &wdata->work); + DeleteMidQEntry(mid); + add_credits(tcon->ses->server, 1, 0); +} + +/* cifs_async_writev - send an async write, and set up mid to handle result */ +int +cifs_async_writev(struct cifs_writedata *wdata, + void (*release)(struct kref *kref)) +{ + int rc = -EACCES; + WRITE_REQ *smb = NULL; + int wct; + struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); + struct kvec iov; + struct smb_rqst rqst = { }; + + if (tcon->ses->capabilities & CAP_LARGE_FILES) { + wct = 14; + } else { + wct = 12; + if (wdata->offset >> 32 > 0) { + /* can not handle big offset for old srv */ + return -EIO; + } + } + + rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb); + if (rc) + goto async_writev_out; + + smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid); + smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16)); + + smb->AndXCommand = 0xFF; /* none */ + smb->Fid = wdata->cfile->fid.netfid; + smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF); + if (wct == 14) + smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32); + smb->Reserved = 0xFFFFFFFF; + smb->WriteMode = 0; + smb->Remaining = 0; + + smb->DataOffset = + cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); + + /* 4 for RFC1001 length + 1 for BCC */ + iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1; + iov.iov_base = smb; + + rqst.rq_iov = &iov; + rqst.rq_nvec = 1; + rqst.rq_pages = wdata->pages; + rqst.rq_npages = wdata->nr_pages; + rqst.rq_pagesz = wdata->pagesz; + rqst.rq_tailsz = wdata->tailsz; + + cifs_dbg(FYI, "async write at %llu %u bytes\n", + wdata->offset, wdata->bytes); + + smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF); + smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16); + + if (wct == 14) { + inc_rfc1001_len(&smb->hdr, wdata->bytes + 1); + put_bcc(wdata->bytes + 1, &smb->hdr); + } else { + /* wct == 12 */ + struct smb_com_writex_req *smbw = + (struct smb_com_writex_req *)smb; + inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5); + put_bcc(wdata->bytes + 5, &smbw->hdr); + iov.iov_len += 4; /* pad bigger by four bytes */ + } + + kref_get(&wdata->refcount); + rc = cifs_call_async(tcon->ses->server, &rqst, NULL, + cifs_writev_callback, wdata, 0); + + if (rc == 0) + cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); + else + kref_put(&wdata->refcount, release); + +async_writev_out: + cifs_small_buf_release(smb); + return rc; +} + int -CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, - const int netfid, const unsigned int count, - const __u64 offset, unsigned int *nbytes, struct kvec *iov, - int n_vec, const int long_op) +CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms, + unsigned int *nbytes, struct kvec *iov, int n_vec) { int rc = -EACCES; WRITE_REQ *pSMB = NULL; int wct; int smb_hdr_len; int resp_buf_type = 0; + __u32 pid = io_parms->pid; + __u16 netfid = io_parms->netfid; + __u64 offset = io_parms->offset; + struct cifs_tcon *tcon = io_parms->tcon; + unsigned int count = io_parms->length; *nbytes = 0; - cFYI(1, "write2 at %lld %d bytes", (long long)offset, count); + cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count); if (tcon->ses->capabilities & CAP_LARGE_FILES) { wct = 14; @@ -1589,6 +2138,10 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB); if (rc) return rc; + + pSMB->hdr.Pid = cpu_to_le16((__u16)pid); + pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); + /* tcon and ses pointer are checked in smb_init */ if (tcon->ses->server == NULL) return -ECONNABORTED; @@ -1607,11 +2160,12 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); pSMB->DataLengthHigh = cpu_to_le16(count >> 16); - smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ + /* header + 1 byte pad */ + smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1; if (wct == 14) - pSMB->hdr.smb_buf_length += count+1; + inc_rfc1001_len(pSMB, count + 1); else /* wct == 12 */ - pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ + inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */ if (wct == 14) pSMB->ByteCount = cpu_to_le16(count + 1); else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ { @@ -1626,11 +2180,10 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, iov[0].iov_len = smb_hdr_len + 8; - rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, - long_op); - cifs_stats_inc(&tcon->num_writes); + rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0); + cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); if (rc) { - cFYI(1, "Send error Write2 = %d", rc); + cifs_dbg(FYI, "Send error Write2 = %d\n", rc); } else if (resp_buf_type == 0) { /* presumably this can not happen, but best to be safe */ rc = -EIO; @@ -1661,31 +2214,75 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, return rc; } +int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon, + const __u16 netfid, const __u8 lock_type, const __u32 num_unlock, + const __u32 num_lock, LOCKING_ANDX_RANGE *buf) +{ + int rc = 0; + LOCK_REQ *pSMB = NULL; + struct kvec iov[2]; + int resp_buf_type; + __u16 count; + + cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n", + num_lock, num_unlock); + + rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); + if (rc) + return rc; + + pSMB->Timeout = 0; + pSMB->NumberOfLocks = cpu_to_le16(num_lock); + pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock); + pSMB->LockType = lock_type; + pSMB->AndXCommand = 0xFF; /* none */ + pSMB->Fid = netfid; /* netfid stays le */ + + count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); + inc_rfc1001_len(pSMB, count); + pSMB->ByteCount = cpu_to_le16(count); + + iov[0].iov_base = (char *)pSMB; + iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 - + (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); + iov[1].iov_base = (char *)buf; + iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); + + cifs_stats_inc(&tcon->stats.cifs_stats.num_locks); + rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP); + if (rc) + cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc); + + return rc; +} int -CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, - const __u16 smb_file_id, const __u64 len, +CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon, + const __u16 smb_file_id, const __u32 netpid, const __u64 len, const __u64 offset, const __u32 numUnlock, - const __u32 numLock, const __u8 lockType, const bool waitFlag) + const __u32 numLock, const __u8 lockType, + const bool waitFlag, const __u8 oplock_level) { int rc = 0; LOCK_REQ *pSMB = NULL; /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */ int bytes_returned; - int timeout = 0; + int flags = 0; __u16 count; - cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock); + cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n", + (int)waitFlag, numLock); rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); if (rc) return rc; if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) { - timeout = CIFS_ASYNC_OP; /* no response expected */ + /* no response expected */ + flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP; pSMB->Timeout = 0; } else if (waitFlag) { - timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ + flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */ } else { pSMB->Timeout = 0; @@ -1694,11 +2291,12 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, pSMB->NumberOfLocks = cpu_to_le16(numLock); pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); pSMB->LockType = lockType; + pSMB->OplockLevel = oplock_level; pSMB->AndXCommand = 0xFF; /* none */ pSMB->Fid = smb_file_id; /* netfid stays le */ if ((numLock != 0) || (numUnlock != 0)) { - pSMB->Locks[0].Pid = cpu_to_le16(current->tgid); + pSMB->Locks[0].Pid = cpu_to_le16(netpid); /* BB where to store pid high? */ pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len); pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32)); @@ -1709,7 +2307,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, /* oplock break */ count = 0; } - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); if (waitFlag) { @@ -1717,13 +2315,12 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, (struct smb_hdr *) pSMB, &bytes_returned); cifs_small_buf_release(pSMB); } else { - rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB, - timeout); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags); /* SMB buffer freed by function above */ } - cifs_stats_inc(&tcon->num_locks); + cifs_stats_inc(&tcon->stats.cifs_stats.num_locks); if (rc) - cFYI(1, "Send error in Lock = %d", rc); + cifs_dbg(FYI, "Send error in Lock = %d\n", rc); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ @@ -1731,8 +2328,9 @@ 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, +CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, + const __u16 smb_file_id, const __u32 netpid, + const loff_t start_offset, const __u64 len, struct file_lock *pLockData, const __u16 lock_type, const bool waitFlag) { @@ -1746,10 +2344,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, __u16 params, param_offset, offset, byte_count, count; struct kvec iov[1]; - cFYI(1, "Posix Lock"); - - if (pLockData == NULL) - return -EINVAL; + cifs_dbg(FYI, "Posix Lock\n"); rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); @@ -1771,7 +2366,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */ pSMB->SetupCount = 1; pSMB->Reserved3 = 0; - if (get_flag) + if (pLockData) pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); else pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); @@ -1792,22 +2387,22 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, } else pSMB->Timeout = 0; - parm_data->pid = cpu_to_le32(current->tgid); - parm_data->start = cpu_to_le64(pLockData->fl_start); + parm_data->pid = cpu_to_le32(netpid); + parm_data->start = cpu_to_le64(start_offset); parm_data->length = cpu_to_le64(len); /* normalize negative numbers */ pSMB->DataOffset = cpu_to_le16(offset); pSMB->Fid = smb_file_id; pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); if (waitFlag) { rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned); } else { iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, &resp_buf_type, timeout); pSMB = NULL; /* request buf already freed by SendReceive2. Do @@ -1816,14 +2411,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, } if (rc) { - cFYI(1, "Send error in Posix Lock = %d", rc); - } else if (get_flag) { + cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc); + } else if (pLockData) { /* 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))) { + if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) { rc = -EIO; /* bad smb */ goto plk_err_exit; } @@ -1845,10 +2440,10 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, __constant_cpu_to_le16(CIFS_WRLCK)) pLockData->fl_type = F_WRLCK; - pLockData->fl_start = parm_data->start; - pLockData->fl_end = parm_data->start + - parm_data->length - 1; - pLockData->fl_pid = parm_data->pid; + pLockData->fl_start = le64_to_cpu(parm_data->start); + pLockData->fl_end = pLockData->fl_start + + le64_to_cpu(parm_data->length) - 1; + pLockData->fl_pid = le32_to_cpu(parm_data->pid); } } @@ -1869,11 +2464,11 @@ plk_err_exit: int -CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) +CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id) { int rc = 0; CLOSE_REQ *pSMB = NULL; - cFYI(1, "In CIFSSMBClose"); + cifs_dbg(FYI, "In CIFSSMBClose\n"); /* do not retry on dead session on close */ rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB); @@ -1885,12 +2480,12 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) pSMB->FileID = (__u16) smb_file_id; pSMB->LastWriteTime = 0xFFFFFFFF; pSMB->ByteCount = 0; - rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); - cifs_stats_inc(&tcon->num_closes); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); + cifs_stats_inc(&tcon->stats.cifs_stats.num_closes); if (rc) { if (rc != -EINTR) { /* EINTR is expected when user ctl-c to kill app */ - cERROR(1, "Send error in Close = %d", rc); + cifs_dbg(VFS, "Send error in Close = %d\n", rc); } } @@ -1902,11 +2497,11 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) } int -CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id) +CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id) { int rc = 0; FLUSH_REQ *pSMB = NULL; - cFYI(1, "In CIFSSMBFlush"); + cifs_dbg(FYI, "In CIFSSMBFlush\n"); rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB); if (rc) @@ -1914,18 +2509,18 @@ CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id) pSMB->FileID = (__u16) smb_file_id; pSMB->ByteCount = 0; - rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); - cifs_stats_inc(&tcon->num_flushes); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); + cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes); if (rc) - cERROR(1, "Send error in Flush = %d", rc); + cifs_dbg(VFS, "Send error in Flush = %d\n", rc); return rc; } int -CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, - const char *fromName, const char *toName, - const struct nls_table *nls_codepage, int remap) +CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, + const char *from_name, const char *to_name, + struct cifs_sb_info *cifs_sb) { int rc = 0; RENAME_REQ *pSMB = NULL; @@ -1933,8 +2528,9 @@ CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, int bytes_returned; int name_len, name_len2; __u16 count; + int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; - cFYI(1, "In CIFSSMBRename"); + cifs_dbg(FYI, "In CIFSSMBRename\n"); renameRetry: rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -1947,40 +2543,41 @@ renameRetry: ATTR_DIRECTORY); if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = - cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, - PATH_MAX, nls_codepage, remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName, + from_name, PATH_MAX, + cifs_sb->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0x04; /* pad */ /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; name_len2 = - cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], - toName, PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], + to_name, PATH_MAX, cifs_sb->local_nls, + remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(fromName, PATH_MAX); + name_len = strnlen(from_name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->OldFileName, fromName, name_len); - name_len2 = strnlen(toName, PATH_MAX); + strncpy(pSMB->OldFileName, from_name, name_len); + name_len2 = strnlen(to_name, PATH_MAX); name_len2++; /* trailing null */ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ - strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); + strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2); name_len2++; /* trailing null */ name_len2++; /* signature byte */ } count = 1 /* 1st signature byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); - cifs_stats_inc(&tcon->num_renames); + cifs_stats_inc(&tcon->stats.cifs_stats.num_renames); if (rc) - cFYI(1, "Send error in rename = %d", rc); + cifs_dbg(FYI, "Send error in rename = %d\n", rc); cifs_buf_release(pSMB); @@ -1990,7 +2587,7 @@ renameRetry: return rc; } -int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, +int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, int netfid, const char *target_name, const struct nls_table *nls_codepage, int remap) { @@ -2004,7 +2601,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, int len_of_str; __u16 params, param_offset, offset, count, byte_count; - cFYI(1, "Rename to File by handle"); + cifs_dbg(FYI, "Rename to File by handle\n"); rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2037,10 +2634,12 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, /* unicode only call */ if (target_name == NULL) { sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid); - len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name, + len_of_str = + cifsConvertToUTF16((__le16 *)rename_info->target_name, dummy_string, 24, nls_codepage, remap); } else { - len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name, + len_of_str = + cifsConvertToUTF16((__le16 *)rename_info->target_name, target_name, PATH_MAX, nls_codepage, remap); } @@ -2053,13 +2652,14 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); - cifs_stats_inc(&pTcon->num_t2renames); + cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames); if (rc) - cFYI(1, "Send error in Rename (by file handle) = %d", rc); + cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n", + rc); cifs_buf_release(pSMB); @@ -2070,9 +2670,9 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, } int -CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName, - const __u16 target_tid, const char *toName, const int flags, - const struct nls_table *nls_codepage, int remap) +CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon, + const char *fromName, const __u16 target_tid, const char *toName, + const int flags, const struct nls_table *nls_codepage, int remap) { int rc = 0; COPY_REQ *pSMB = NULL; @@ -2081,7 +2681,7 @@ CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName, int name_len, name_len2; __u16 count; - cFYI(1, "In CIFSSMBCopy"); + cifs_dbg(FYI, "In CIFSSMBCopy\n"); copyRetry: rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -2094,17 +2694,17 @@ copyRetry: pSMB->Flags = cpu_to_le16(flags & COPY_TREE); if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, - fromName, PATH_MAX, nls_codepage, - remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName, + fromName, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0x04; /* pad */ /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; name_len2 = - cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], - toName, PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], + toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ @@ -2120,14 +2720,14 @@ copyRetry: } count = 1 /* 1st signature byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { - cFYI(1, "Send error in copy = %d with %d files copied", - rc, le16_to_cpu(pSMBr->CopyCount)); + cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n", + rc, le16_to_cpu(pSMBr->CopyCount)); } cifs_buf_release(pSMB); @@ -2138,7 +2738,7 @@ copyRetry: } int -CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon, +CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, const char *fromName, const char *toName, const struct nls_table *nls_codepage) { @@ -2151,7 +2751,7 @@ CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon, int bytes_returned = 0; __u16 params, param_offset, offset, byte_count; - cFYI(1, "In Symlink Unix style"); + cifs_dbg(FYI, "In Symlink Unix style\n"); createSymLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -2160,9 +2760,9 @@ createSymLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName, + /* find define for this maxpathcomponent */ + PATH_MAX, nls_codepage); name_len++; /* trailing null */ name_len *= 2; @@ -2184,9 +2784,9 @@ createSymLinkRetry: data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX + /* find define for this maxpathcomponent */ + , nls_codepage); name_len_target++; /* trailing null */ name_len_target *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2210,13 +2810,14 @@ createSymLinkRetry: pSMB->DataOffset = cpu_to_le16(offset); pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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); - cifs_stats_inc(&tcon->num_symlinks); + cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks); if (rc) - cFYI(1, "Send error in SetPathInfo create symlink = %d", rc); + cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n", + rc); cifs_buf_release(pSMB); @@ -2227,7 +2828,7 @@ createSymLinkRetry: } int -CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon, +CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, const char *fromName, const char *toName, const struct nls_table *nls_codepage, int remap) { @@ -2240,7 +2841,7 @@ CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon, int bytes_returned = 0; __u16 params, param_offset, offset, byte_count; - cFYI(1, "In Create Hard link Unix style"); + cifs_dbg(FYI, "In Create Hard link Unix style\n"); createHardLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -2248,8 +2849,8 @@ createHardLinkRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName, - PATH_MAX, nls_codepage, remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2271,8 +2872,8 @@ createHardLinkRetry: data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX, - nls_codepage, remap); + cifsConvertToUTF16((__le16 *) data_offset, fromName, + PATH_MAX, nls_codepage, remap); name_len_target++; /* trailing null */ name_len_target *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2296,13 +2897,14 @@ createHardLinkRetry: pSMB->DataOffset = cpu_to_le16(offset); pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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); - cifs_stats_inc(&tcon->num_hardlinks); + cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks); if (rc) - cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc); + cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n", + rc); cifs_buf_release(pSMB); if (rc == -EAGAIN) @@ -2312,9 +2914,9 @@ createHardLinkRetry: } int -CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon, - const char *fromName, const char *toName, - const struct nls_table *nls_codepage, int remap) +CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, + const char *from_name, const char *to_name, + struct cifs_sb_info *cifs_sb) { int rc = 0; NT_RENAME_REQ *pSMB = NULL; @@ -2322,8 +2924,9 @@ CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon, int bytes_returned; int name_len, name_len2; __u16 count; + int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; - cFYI(1, "In CIFSCreateHardLink"); + cifs_dbg(FYI, "In CIFSCreateHardLink\n"); winCreateHardLinkRetry: rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB, @@ -2341,8 +2944,8 @@ winCreateHardLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name, + PATH_MAX, cifs_sb->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2350,31 +2953,32 @@ winCreateHardLinkRetry: pSMB->OldFileName[name_len] = 0x04; pSMB->OldFileName[name_len + 1] = 0x00; /* pad */ name_len2 = - cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], - toName, PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], + to_name, PATH_MAX, cifs_sb->local_nls, + remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(fromName, PATH_MAX); + name_len = strnlen(from_name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->OldFileName, fromName, name_len); - name_len2 = strnlen(toName, PATH_MAX); + strncpy(pSMB->OldFileName, from_name, name_len); + name_len2 = strnlen(to_name, PATH_MAX); name_len2++; /* trailing null */ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ - strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); + strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2); name_len2++; /* trailing null */ name_len2++; /* signature byte */ } count = 1 /* string type byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); - cifs_stats_inc(&tcon->num_hardlinks); + cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks); if (rc) - cFYI(1, "Send error in hard link (NT rename) = %d", rc); + cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc); cifs_buf_release(pSMB); if (rc == -EAGAIN) @@ -2384,7 +2988,7 @@ winCreateHardLinkRetry: } int -CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, +CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *searchName, char **symlinkinfo, const struct nls_table *nls_codepage) { @@ -2397,7 +3001,7 @@ CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, __u16 params, byte_count; char *data_start; - cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName); + cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName); querySymLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, @@ -2407,8 +3011,8 @@ querySymLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage); + cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2438,19 +3042,19 @@ querySymLinkRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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 QuerySymLinkInfo = %d", rc); + cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); /* BB also check enough total bytes returned */ - if (rc || (pSMBr->ByteCount < 2)) + if (rc || get_bcc(&pSMBr->hdr) < 2) rc = -EIO; else { bool is_unicode; @@ -2465,8 +3069,8 @@ querySymLinkRetry: is_unicode = false; /* BB FIXME investigate remapping reserved chars here */ - *symlinkinfo = cifs_strndup_from_ucs(data_start, count, - is_unicode, nls_codepage); + *symlinkinfo = cifs_strndup_from_utf16(data_start, + count, is_unicode, nls_codepage); if (!*symlinkinfo) rc = -ENOMEM; } @@ -2477,108 +3081,34 @@ querySymLinkRetry: return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL -/* Initialize NT TRANSACT SMB into small smb request buffer. - This assumes that all NT TRANSACTS that we init here have - total parm and data under about 400 bytes (to fit in small cifs - buffer size), which is the case so far, it easily fits. NB: - Setup words themselves and ByteCount - MaxSetupCount (size of returned setup area) and - MaxParameterCount (returned parms size) must be set by caller */ -static int -smb_init_nttransact(const __u16 sub_command, const int setup_count, - const int parm_len, struct cifsTconInfo *tcon, - void **ret_buf) -{ - int rc; - __u32 temp_offset; - struct smb_com_ntransact_req *pSMB; - - rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, - (void **)&pSMB); - if (rc) - return rc; - *ret_buf = (void *)pSMB; - pSMB->Reserved = 0; - pSMB->TotalParameterCount = cpu_to_le32(parm_len); - pSMB->TotalDataCount = 0; - pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); - pSMB->ParameterCount = pSMB->TotalParameterCount; - pSMB->DataCount = pSMB->TotalDataCount; - temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + - (setup_count * 2) - 4 /* for rfc1001 length itself */; - pSMB->ParameterOffset = cpu_to_le32(temp_offset); - pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); - pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ - pSMB->SubCommand = cpu_to_le16(sub_command); - return 0; -} - -static int -validate_ntransact(char *buf, char **ppparm, char **ppdata, - __u32 *pparmlen, __u32 *pdatalen) -{ - char *end_of_smb; - __u32 data_count, data_offset, parm_count, parm_offset; - struct smb_com_ntransact_rsp *pSMBr; - - *pdatalen = 0; - *pparmlen = 0; - - if (buf == NULL) - return -EINVAL; - - pSMBr = (struct smb_com_ntransact_rsp *)buf; - - /* ByteCount was converted from little endian in SendReceive */ - end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + - (char *)&pSMBr->ByteCount; - - data_offset = le32_to_cpu(pSMBr->DataOffset); - data_count = le32_to_cpu(pSMBr->DataCount); - parm_offset = le32_to_cpu(pSMBr->ParameterOffset); - parm_count = le32_to_cpu(pSMBr->ParameterCount); - - *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; - *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; - - /* should we also check that parm and data areas do not overlap? */ - if (*ppparm > end_of_smb) { - cFYI(1, "parms start after end of smb"); - return -EINVAL; - } else if (parm_count + *ppparm > end_of_smb) { - cFYI(1, "parm end after end of smb"); - return -EINVAL; - } else if (*ppdata > end_of_smb) { - cFYI(1, "data starts after end of smb"); - return -EINVAL; - } else if (data_count + *ppdata > end_of_smb) { - cFYI(1, "data %p + count %d (%p) past smb end %p start %p", - *ppdata, data_count, (data_count + *ppdata), - end_of_smb, pSMBr); - return -EINVAL; - } else if (parm_count + data_count > pSMBr->ByteCount) { - cFYI(1, "parm count and data count larger than SMB"); - return -EINVAL; - } - *pdatalen = data_count; - *pparmlen = parm_count; - return 0; -} - +/* + * Recent Windows versions now create symlinks more frequently + * and they use the "reparse point" mechanism below. We can of course + * do symlinks nicely to Samba and other servers which support the + * CIFS Unix Extensions and we can also do SFU symlinks and "client only" + * "MF" symlinks optionally, but for recent Windows we really need to + * reenable the code below and fix the cifs_symlink callers to handle this. + * In the interim this code has been moved to its own config option so + * it is not compiled in by default until callers fixed up and more tested. + */ int -CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, - const unsigned char *searchName, - char *symlinkinfo, const int buflen, __u16 fid, - const struct nls_table *nls_codepage) +CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, + __u16 fid, char **symlinkinfo, + const struct nls_table *nls_codepage) { int rc = 0; int bytes_returned; struct smb_com_transaction_ioctl_req *pSMB; struct smb_com_transaction_ioctl_rsp *pSMBr; + bool is_unicode; + unsigned int sub_len; + char *sub_start; + struct reparse_symlink_data *reparse_buf; + struct reparse_posix_data *posix_buf; + __u32 data_offset, data_count; + char *end_of_smb; - cFYI(1, "In Windows reparse style QueryLink for path %s", searchName); + cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid); rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2588,8 +3118,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le32(2); /* BB find exact data count max from sess structure BB */ - pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); pSMB->MaxSetupCount = 4; pSMB->Reserved = 0; pSMB->ParameterOffset = 0; @@ -2607,68 +3136,137 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { - cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc); - } else { /* decode response */ - __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); - __u32 data_count = le32_to_cpu(pSMBr->DataCount); - if ((pSMBr->ByteCount < 2) || (data_offset > 512)) { + cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); + goto qreparse_out; + } + + data_offset = le32_to_cpu(pSMBr->DataOffset); + data_count = le32_to_cpu(pSMBr->DataCount); + if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { /* BB also check enough total bytes returned */ - rc = -EIO; /* bad smb */ + rc = -EIO; /* bad smb */ + goto qreparse_out; + } + if (!data_count || (data_count > 2048)) { + rc = -EIO; + cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); + goto qreparse_out; + } + end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; + reparse_buf = (struct reparse_symlink_data *) + ((char *)&pSMBr->hdr.Protocol + data_offset); + if ((char *)reparse_buf >= end_of_smb) { + rc = -EIO; + goto qreparse_out; + } + if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) { + cifs_dbg(FYI, "NFS style reparse tag\n"); + posix_buf = (struct reparse_posix_data *)reparse_buf; + + if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) { + cifs_dbg(FYI, "unsupported file type 0x%llx\n", + le64_to_cpu(posix_buf->InodeType)); + rc = -EOPNOTSUPP; goto qreparse_out; } - if (data_count && (data_count < 2048)) { - char *end_of_smb = 2 /* sizeof byte count */ + - pSMBr->ByteCount + (char *)&pSMBr->ByteCount; - - struct reparse_data *reparse_buf = - (struct reparse_data *) - ((char *)&pSMBr->hdr.Protocol - + data_offset); - if ((char *)reparse_buf >= end_of_smb) { - rc = -EIO; - goto qreparse_out; - } - if ((reparse_buf->LinkNamesBuf + - reparse_buf->TargetNameOffset + - reparse_buf->TargetNameLen) > end_of_smb) { - cFYI(1, "reparse buf beyond SMB"); - rc = -EIO; - goto qreparse_out; - } - - if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { - cifs_from_ucs2(symlinkinfo, (__le16 *) - (reparse_buf->LinkNamesBuf + - reparse_buf->TargetNameOffset), - buflen, - reparse_buf->TargetNameLen, - nls_codepage, 0); - } else { /* ASCII names */ - strncpy(symlinkinfo, - reparse_buf->LinkNamesBuf + - reparse_buf->TargetNameOffset, - min_t(const int, buflen, - reparse_buf->TargetNameLen)); - } - } else { + is_unicode = true; + sub_len = le16_to_cpu(reparse_buf->ReparseDataLength); + if (posix_buf->PathBuffer + sub_len > end_of_smb) { + cifs_dbg(FYI, "reparse buf beyond SMB\n"); rc = -EIO; - cFYI(1, "Invalid return data count on " - "get reparse info ioctl"); + goto qreparse_out; } - symlinkinfo[buflen] = 0; /* just in case so the caller - does not go off the end of the buffer */ - cFYI(1, "readlink result - %s", symlinkinfo); + *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer, + sub_len, is_unicode, nls_codepage); + goto qreparse_out; + } else if (reparse_buf->ReparseTag != + cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) { + rc = -EOPNOTSUPP; + goto qreparse_out; } + /* Reparse tag is NTFS symlink */ + sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) + + reparse_buf->PathBuffer; + sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength); + if (sub_start + sub_len > end_of_smb) { + cifs_dbg(FYI, "reparse buf beyond SMB\n"); + rc = -EIO; + goto qreparse_out; + } + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) + is_unicode = true; + else + is_unicode = false; + + /* BB FIXME investigate remapping reserved chars here */ + *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode, + nls_codepage); + if (!*symlinkinfo) + rc = -ENOMEM; qreparse_out: cifs_buf_release(pSMB); - /* Note: On -EAGAIN error only caller can retry on handle based calls - since file handle passed in no longer valid */ + /* + * Note: On -EAGAIN error only caller can retry on handle based calls + * since file handle passed in no longer valid. + */ + return rc; +} + +int +CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon, + __u16 fid) +{ + int rc = 0; + int bytes_returned; + struct smb_com_transaction_compr_ioctl_req *pSMB; + struct smb_com_transaction_ioctl_rsp *pSMBr; + + cifs_dbg(FYI, "Set compression for %u\n", fid); + rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT); + pSMB->TotalParameterCount = 0; + pSMB->TotalDataCount = __constant_cpu_to_le32(2); + pSMB->MaxParameterCount = 0; + pSMB->MaxDataCount = 0; + pSMB->MaxSetupCount = 4; + pSMB->Reserved = 0; + pSMB->ParameterOffset = 0; + pSMB->DataCount = __constant_cpu_to_le32(2); + pSMB->DataOffset = + cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req, + compression_state) - 4); /* 84 */ + pSMB->SetupCount = 4; + pSMB->SubCommand = __constant_cpu_to_le16(NT_TRANSACT_IOCTL); + pSMB->ParameterCount = 0; + pSMB->FunctionCode = __constant_cpu_to_le32(FSCTL_SET_COMPRESSION); + pSMB->IsFsctl = 1; /* FSCTL */ + pSMB->IsRootFlag = 0; + pSMB->Fid = fid; /* file handle always le */ + /* 3 byte pad, followed by 2 byte compress state */ + pSMB->ByteCount = __constant_cpu_to_le16(5); + inc_rfc1001_len(pSMB, 5); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) + cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc); + + cifs_buf_release(pSMB); + + /* + * Note: On -EAGAIN error only caller can retry on handle based calls + * since file handle passed in no longer valid. + */ return rc; } -#endif /* CIFS_EXPERIMENTAL */ + #ifdef CONFIG_CIFS_POSIX @@ -2680,7 +3278,10 @@ static void cifs_convert_ace(posix_acl_xattr_entry *ace, ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm); ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag); ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid)); - /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */ +/* + cifs_dbg(FYI, "perm %d tag %d id %d\n", + ace->e_perm, ace->e_tag, ace->e_id); +*/ return; } @@ -2706,8 +3307,8 @@ static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen, size += sizeof(struct cifs_posix_ace) * count; /* check if we would go beyond end of SMB */ if (size_of_data_area < size) { - cFYI(1, "bad CIFS POSIX ACL size %d vs. %d", - size_of_data_area, size); + cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n", + size_of_data_area, size); return -EINVAL; } } else if (acl_type & ACL_TYPE_DEFAULT) { @@ -2754,7 +3355,10 @@ static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace, cifs_ace->cifs_uid = cpu_to_le64(-1); } else cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id)); - /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/ +/* + cifs_dbg(FYI, "perm %d tag %d id %d\n", + ace->e_perm, ace->e_tag, ace->e_id); +*/ return rc; } @@ -2772,21 +3376,22 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL, return 0; count = posix_acl_xattr_count((size_t)buflen); - cFYI(1, "setting acl with %d entries from buf of length %d and " - "version of %d", - count, buflen, le32_to_cpu(local_acl->a_version)); + cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n", + count, buflen, le32_to_cpu(local_acl->a_version)); if (le32_to_cpu(local_acl->a_version) != 2) { - cFYI(1, "unknown POSIX ACL version %d", - le32_to_cpu(local_acl->a_version)); + cifs_dbg(FYI, "unknown POSIX ACL version %d\n", + le32_to_cpu(local_acl->a_version)); return 0; } cifs_acl->version = cpu_to_le16(1); - if (acl_type == ACL_TYPE_ACCESS) + if (acl_type == ACL_TYPE_ACCESS) { cifs_acl->access_entry_count = cpu_to_le16(count); - else if (acl_type == ACL_TYPE_DEFAULT) + cifs_acl->default_entry_count = __constant_cpu_to_le16(0xFFFF); + } else if (acl_type == ACL_TYPE_DEFAULT) { cifs_acl->default_entry_count = cpu_to_le16(count); - else { - cFYI(1, "unknown ACL type %d", acl_type); + cifs_acl->access_entry_count = __constant_cpu_to_le16(0xFFFF); + } else { + cifs_dbg(FYI, "unknown ACL type %d\n", acl_type); return 0; } for (i = 0; i < count; i++) { @@ -2806,7 +3411,7 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL, } int -CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, +CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *searchName, char *acl_inf, const int buflen, const int acl_type, const struct nls_table *nls_codepage, int remap) @@ -2819,7 +3424,7 @@ CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, int name_len; __u16 params, byte_count; - cFYI(1, "In GetPosixACL (Unix) for path %s", searchName); + cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName); queryAclRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, @@ -2829,8 +3434,9 @@ queryAclRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, + searchName, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; pSMB->FileName[name_len] = 0; @@ -2864,20 +3470,20 @@ queryAclRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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); - cifs_stats_inc(&tcon->num_acl_get); + cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get); if (rc) { - cFYI(1, "Send error in Query POSIX ACL = %d", rc); + cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 2)) /* BB also check enough total bytes returned */ + if (rc || get_bcc(&pSMBr->hdr) < 2) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -2894,7 +3500,7 @@ queryAclRetry: } int -CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, +CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *fileName, const char *local_acl, const int buflen, const int acl_type, @@ -2908,7 +3514,7 @@ CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, int bytes_returned = 0; __u16 params, byte_count, data_count, param_offset, offset; - cFYI(1, "In SetPosixACL (Unix) for path %s", fileName); + cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName); setAclRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -2916,8 +3522,8 @@ setAclRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2958,12 +3564,12 @@ setAclRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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, "Set POSIX ACL returned %d", rc); + cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc); setACLerrorExit: cifs_buf_release(pSMB); @@ -2974,7 +3580,7 @@ setACLerrorExit: /* BB fix tabs in this function FIXME BB */ int -CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, +CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon, const int netfid, __u64 *pExtAttrBits, __u64 *pMask) { int rc = 0; @@ -2983,7 +3589,7 @@ CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, int bytes_returned; __u16 params, byte_count; - cFYI(1, "In GetExtAttr"); + cifs_dbg(FYI, "In GetExtAttr\n"); if (tcon == NULL) return -ENODEV; @@ -3016,18 +3622,18 @@ GetExtAttrRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS); pSMB->Pad = 0; pSMB->Fid = netfid; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->t2.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, "error %d in GetExtAttr", rc); + cifs_dbg(FYI, "error %d in GetExtAttr\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 2)) /* BB also check enough total bytes returned */ + if (rc || get_bcc(&pSMBr->hdr) < 2) /* If rc should we check for EOPNOSUPP and disable the srvino flag? or in caller? */ rc = -EIO; /* bad smb */ @@ -3037,7 +3643,7 @@ GetExtAttrRetry: struct file_chattr_info *pfinfo; /* BB Do we need a cast or hash here ? */ if (count != 16) { - cFYI(1, "Illegal size ret in GetExtAttr"); + cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n"); rc = -EIO; goto GetExtAttrOut; } @@ -3056,10 +3662,100 @@ GetExtAttrOut: #endif /* CONFIG_POSIX */ -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CONFIG_CIFS_ACL +/* + * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that + * all NT TRANSACTS that we init here have total parm and data under about 400 + * bytes (to fit in small cifs buffer size), which is the case so far, it + * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of + * returned setup area) and MaxParameterCount (returned parms size) must be set + * by caller + */ +static int +smb_init_nttransact(const __u16 sub_command, const int setup_count, + const int parm_len, struct cifs_tcon *tcon, + void **ret_buf) +{ + int rc; + __u32 temp_offset; + struct smb_com_ntransact_req *pSMB; + + rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, + (void **)&pSMB); + if (rc) + return rc; + *ret_buf = (void *)pSMB; + pSMB->Reserved = 0; + pSMB->TotalParameterCount = cpu_to_le32(parm_len); + pSMB->TotalDataCount = 0; + pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->DataCount = pSMB->TotalDataCount; + temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + + (setup_count * 2) - 4 /* for rfc1001 length itself */; + pSMB->ParameterOffset = cpu_to_le32(temp_offset); + pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); + pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ + pSMB->SubCommand = cpu_to_le16(sub_command); + return 0; +} + +static int +validate_ntransact(char *buf, char **ppparm, char **ppdata, + __u32 *pparmlen, __u32 *pdatalen) +{ + char *end_of_smb; + __u32 data_count, data_offset, parm_count, parm_offset; + struct smb_com_ntransact_rsp *pSMBr; + u16 bcc; + + *pdatalen = 0; + *pparmlen = 0; + + if (buf == NULL) + return -EINVAL; + + pSMBr = (struct smb_com_ntransact_rsp *)buf; + + bcc = get_bcc(&pSMBr->hdr); + end_of_smb = 2 /* sizeof byte count */ + bcc + + (char *)&pSMBr->ByteCount; + + data_offset = le32_to_cpu(pSMBr->DataOffset); + data_count = le32_to_cpu(pSMBr->DataCount); + parm_offset = le32_to_cpu(pSMBr->ParameterOffset); + parm_count = le32_to_cpu(pSMBr->ParameterCount); + + *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; + *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; + + /* should we also check that parm and data areas do not overlap? */ + if (*ppparm > end_of_smb) { + cifs_dbg(FYI, "parms start after end of smb\n"); + return -EINVAL; + } else if (parm_count + *ppparm > end_of_smb) { + cifs_dbg(FYI, "parm end after end of smb\n"); + return -EINVAL; + } else if (*ppdata > end_of_smb) { + cifs_dbg(FYI, "data starts after end of smb\n"); + return -EINVAL; + } else if (data_count + *ppdata > end_of_smb) { + cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n", + *ppdata, data_count, (data_count + *ppdata), + end_of_smb, pSMBr); + return -EINVAL; + } else if (parm_count + data_count > bcc) { + cifs_dbg(FYI, "parm count and data count larger than SMB\n"); + return -EINVAL; + } + *pdatalen = data_count; + *pparmlen = parm_count; + return 0; +} + /* Get Security Descriptor (by handle) from remote server for a file or dir */ int -CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, +CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, struct cifs_ntsd **acl_inf, __u32 *pbuflen) { int rc = 0; @@ -3067,7 +3763,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, QUERY_SEC_DESC_REQ *pSMB; struct kvec iov[1]; - cFYI(1, "GetCifsACL"); + cifs_dbg(FYI, "GetCifsACL\n"); *pbuflen = 0; *acl_inf = NULL; @@ -3084,15 +3780,15 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP | CIFS_ACL_DACL); pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */ - pSMB->hdr.smb_buf_length += 11; + inc_rfc1001_len(pSMB, 11); iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, - CIFS_STD_OP); - cifs_stats_inc(&tcon->num_acl_get); + 0); + cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get); if (rc) { - cFYI(1, "Send error in QuerySecDesc = %d", rc); + cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc); } else { /* decode response */ __le32 *parm; __u32 parm_len; @@ -3107,7 +3803,8 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, goto qsec_out; pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base; - cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf); + cifs_dbg(FYI, "smb %p parm %p data %p\n", + pSMBr, parm, *acl_inf); if (le32_to_cpu(pSMBr->ParameterCount) != 4) { rc = -EIO; /* bad smb */ @@ -3119,8 +3816,8 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, acl_len = le32_to_cpu(*parm); if (acl_len != *pbuflen) { - cERROR(1, "acl length %d does not match %d", - acl_len, *pbuflen); + cifs_dbg(VFS, "acl length %d does not match %d\n", + acl_len, *pbuflen); if (*pbuflen > acl_len) *pbuflen = acl_len; } @@ -3129,16 +3826,15 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, header followed by the smallest SID */ if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) || (*pbuflen >= 64 * 1024)) { - cERROR(1, "bad acl length %d", *pbuflen); + cifs_dbg(VFS, "bad acl length %d\n", *pbuflen); rc = -EINVAL; *pbuflen = 0; } else { - *acl_inf = kmalloc(*pbuflen, GFP_KERNEL); + *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL); if (*acl_inf == NULL) { *pbuflen = 0; rc = -ENOMEM; } - memcpy(*acl_inf, pdata, *pbuflen); } } qsec_out: @@ -3151,20 +3847,19 @@ qsec_out: } int -CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, - struct cifs_ntsd *pntsd, __u32 acllen) +CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, + struct cifs_ntsd *pntsd, __u32 acllen, int aclflag) { __u16 byte_count, param_count, data_count, param_offset, data_offset; int rc = 0; int bytes_returned = 0; SET_SEC_DESC_REQ *pSMB = NULL; - NTRANSACT_RSP *pSMBr = NULL; + void *pSMBr; setCifsAclRetry: - rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr); if (rc) - return (rc); + return rc; pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; @@ -3189,23 +3884,22 @@ setCifsAclRetry: pSMB->Fid = fid; /* file handle always le */ pSMB->Reserved2 = 0; - pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL); + pSMB->AclFlags = cpu_to_le32(aclflag); if (pntsd && acllen) { - memcpy((char *) &pSMBr->hdr.Protocol + data_offset, - (char *) pntsd, - acllen); - pSMB->hdr.smb_buf_length += (byte_count + data_count); - + memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) + + data_offset, pntsd, acllen); + inc_rfc1001_len(pSMB, byte_count + data_count); } else - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); - cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc); + cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n", + bytes_returned, rc); if (rc) - cFYI(1, "Set CIFS ACL returned %d", rc); + cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc); cifs_buf_release(pSMB); if (rc == -EAGAIN) @@ -3214,14 +3908,14 @@ setCifsAclRetry: return (rc); } -#endif /* CONFIG_CIFS_EXPERIMENTAL */ +#endif /* CONFIG_CIFS_ACL */ /* Legacy Query Path Information call for lookup to old servers such as Win9x/WinME */ -int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, - const unsigned char *searchName, - FILE_ALL_INFO *pFinfo, - const struct nls_table *nls_codepage, int remap) +int +SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon, + const char *search_name, FILE_ALL_INFO *data, + const struct nls_table *nls_codepage, int remap) { QUERY_INFORMATION_REQ *pSMB; QUERY_INFORMATION_RSP *pSMBr; @@ -3229,7 +3923,7 @@ int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, int bytes_returned; int name_len; - cFYI(1, "In SMBQPath path %s", searchName); + cifs_dbg(FYI, "In SMBQPath path %s\n", search_name); QInfRetry: rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -3238,41 +3932,42 @@ QInfRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, + search_name, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; } else { - name_len = strnlen(searchName, PATH_MAX); + name_len = strnlen(search_name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->FileName, searchName, name_len); + strncpy(pSMB->FileName, search_name, name_len); } pSMB->BufferFormat = 0x04; name_len++; /* account for buffer type byte */ - pSMB->hdr.smb_buf_length += (__u16) name_len; + inc_rfc1001_len(pSMB, (__u16)name_len); pSMB->ByteCount = cpu_to_le16(name_len); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { - cFYI(1, "Send error in QueryInfo = %d", rc); - } else if (pFinfo) { + cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc); + } else if (data) { struct timespec ts; __u32 time = le32_to_cpu(pSMBr->last_write_time); /* decode response */ /* BB FIXME - add time zone adjustment BB */ - memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); + memset(data, 0, sizeof(FILE_ALL_INFO)); ts.tv_nsec = 0; ts.tv_sec = time; /* decode time fields */ - pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts)); - pFinfo->LastWriteTime = pFinfo->ChangeTime; - pFinfo->LastAccessTime = 0; - pFinfo->AllocationSize = + data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts)); + data->LastWriteTime = data->ChangeTime; + data->LastAccessTime = 0; + data->AllocationSize = cpu_to_le64(le32_to_cpu(pSMBr->size)); - pFinfo->EndOfFile = pFinfo->AllocationSize; - pFinfo->Attributes = + data->EndOfFile = data->AllocationSize; + data->Attributes = cpu_to_le32(le16_to_cpu(pSMBr->attr)); } else rc = -EIO; /* bad buffer passed in */ @@ -3286,7 +3981,7 @@ QInfRetry: } int -CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon, +CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, u16 netfid, FILE_ALL_INFO *pFindData) { struct smb_t2_qfi_req *pSMB = NULL; @@ -3324,18 +4019,19 @@ QFileInfoRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); pSMB->Pad = 0; pSMB->Fid = netfid; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); + pSMB->t2.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 QPathInfo = %d", rc); + cifs_dbg(FYI, "Send error in QFileInfo = %d", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc) /* BB add auto retry on EOPNOTSUPP? */ rc = -EIO; - else if (pSMBr->ByteCount < 40) + else if (get_bcc(&pSMBr->hdr) < 40) rc = -EIO; /* bad smb */ else if (pFindData) { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -3353,13 +4049,12 @@ QFileInfoRetry: } int -CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, - const unsigned char *searchName, - FILE_ALL_INFO *pFindData, +CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, + const char *search_name, FILE_ALL_INFO *data, int legacy /* old style infolevel */, const struct nls_table *nls_codepage, int remap) { -/* level 263 SMB_QUERY_FILE_ALL_INFO */ + /* level 263 SMB_QUERY_FILE_ALL_INFO */ TRANSACTION2_QPI_REQ *pSMB = NULL; TRANSACTION2_QPI_RSP *pSMBr = NULL; int rc = 0; @@ -3367,7 +4062,7 @@ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, int name_len; __u16 params, byte_count; -/* cFYI(1, "In QPathInfo path %s", searchName); */ + /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */ QPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -3376,14 +4071,14 @@ QPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(searchName, PATH_MAX); + name_len = strnlen(search_name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->FileName, searchName, name_len); + strncpy(pSMB->FileName, search_name, name_len); } params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; @@ -3411,37 +4106,38 @@ QPathInfoRetry: else pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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 QPathInfo = %d", rc); + cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc) /* BB add auto retry on EOPNOTSUPP? */ rc = -EIO; - else if (!legacy && (pSMBr->ByteCount < 40)) + else if (!legacy && get_bcc(&pSMBr->hdr) < 40) rc = -EIO; /* bad smb */ - else if (legacy && (pSMBr->ByteCount < 24)) + else if (legacy && get_bcc(&pSMBr->hdr) < 24) rc = -EIO; /* 24 or 26 expected but we do not read last field */ - else if (pFindData) { + else if (data) { int size; __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); - /* On legacy responses we do not read the last field, - EAsize, fortunately since it varies by subdialect and - also note it differs on Set vs. Get, ie two bytes or 4 - bytes depending but we don't care here */ + /* + * On legacy responses we do not read the last field, + * EAsize, fortunately since it varies by subdialect and + * also note it differs on Set vs Get, ie two bytes or 4 + * bytes depending but we don't care here. + */ if (legacy) size = sizeof(FILE_INFO_STANDARD); else size = sizeof(FILE_ALL_INFO); - memcpy((char *) pFindData, - (char *) &pSMBr->hdr.Protocol + + memcpy((char *) data, (char *) &pSMBr->hdr.Protocol + data_offset, size); } else rc = -ENOMEM; @@ -3454,7 +4150,7 @@ QPathInfoRetry: } int -CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon, +CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, u16 netfid, FILE_UNIX_BASIC_INFO *pFindData) { struct smb_t2_qfi_req *pSMB = NULL; @@ -3492,19 +4188,18 @@ UnixQFileInfoRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pSMB->Pad = 0; pSMB->Fid = netfid; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); + pSMB->t2.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 QPathInfo = %d", rc); + cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { - cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n" - "Unix Extensions can be disabled on mount " - "by specifying the nosfu mount option."); + if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { + cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n"); rc = -EIO; /* bad smb */ } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -3523,7 +4218,7 @@ UnixQFileInfoRetry: } int -CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, +CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *searchName, FILE_UNIX_BASIC_INFO *pFindData, const struct nls_table *nls_codepage, int remap) @@ -3536,7 +4231,7 @@ CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, int name_len; __u16 params, byte_count; - cFYI(1, "In QPathInfo (Unix) the path %s", searchName); + cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName); UnixQPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -3545,8 +4240,8 @@ UnixQPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -3577,20 +4272,18 @@ UnixQPathInfoRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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 QPathInfo = %d", rc); + cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { - cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n" - "Unix Extensions can be disabled on mount " - "by specifying the nosfu mount option."); + if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { + cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n"); rc = -EIO; /* bad smb */ } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -3609,11 +4302,10 @@ UnixQPathInfoRetry: /* xid, tcon, searchName and codepage are input parms, rest are returned */ int -CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, - const char *searchName, - const struct nls_table *nls_codepage, - __u16 *pnetfid, - struct cifs_search_info *psrch_inf, int remap, const char dirsep) +CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, + const char *searchName, struct cifs_sb_info *cifs_sb, + __u16 *pnetfid, __u16 search_flags, + struct cifs_search_info *psrch_inf, bool msearch) { /* level 257 SMB_ */ TRANSACTION2_FFIRST_REQ *pSMB = NULL; @@ -3621,10 +4313,11 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, T2_FFIRST_RSP_PARMS *parms; int rc = 0; int bytes_returned = 0; - int name_len; + int name_len, remap; __u16 params, byte_count; + struct nls_table *nls_codepage; - cFYI(1, "In FindFirst for %s", searchName); + cifs_dbg(FYI, "In FindFirst for %s\n", searchName); findFirstRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, @@ -3632,39 +4325,46 @@ findFirstRetry: if (rc) return rc; + nls_codepage = cifs_sb->local_nls; + remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); /* We can not add the asterik earlier in case it got remapped to 0xF03A as if it were part of the directory name instead of a wildcard */ name_len *= 2; - pSMB->FileName[name_len] = dirsep; - pSMB->FileName[name_len+1] = 0; - pSMB->FileName[name_len+2] = '*'; - pSMB->FileName[name_len+3] = 0; - name_len += 4; /* now the trailing null */ - pSMB->FileName[name_len] = 0; /* null terminate just in case */ - pSMB->FileName[name_len+1] = 0; - name_len += 2; + if (msearch) { + pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb); + pSMB->FileName[name_len+1] = 0; + pSMB->FileName[name_len+2] = '*'; + pSMB->FileName[name_len+3] = 0; + name_len += 4; /* now the trailing null */ + /* null terminate just in case */ + pSMB->FileName[name_len] = 0; + pSMB->FileName[name_len+1] = 0; + name_len += 2; + } } else { /* BB add check for overrun of SMB buf BB */ name_len = strnlen(searchName, PATH_MAX); /* BB fix here and in unicode clause above ie if (name_len > buffersize-header) free buffer exit; BB */ strncpy(pSMB->FileName, searchName, name_len); - pSMB->FileName[name_len] = dirsep; - pSMB->FileName[name_len+1] = '*'; - pSMB->FileName[name_len+2] = 0; - name_len += 3; + if (msearch) { + pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb); + pSMB->FileName[name_len+1] = '*'; + pSMB->FileName[name_len+2] = 0; + name_len += 3; + } } params = 12 + name_len /* includes null */ ; pSMB->TotalDataCount = 0; /* no EAs */ pSMB->MaxParameterCount = cpu_to_le16(10); - pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf - - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -3685,23 +4385,22 @@ findFirstRetry: cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO)); - pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | - CIFS_SEARCH_RETURN_RESUME); + pSMB->SearchFlags = cpu_to_le16(search_flags); pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); /* BB what should we set StorageType to? Does it matter? BB */ pSMB->SearchStorageType = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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); - cifs_stats_inc(&tcon->num_ffirst); + cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst); if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ /* BB Add code to handle unsupported level rc */ - cFYI(1, "Error in FindFirst = %d", rc); + cifs_dbg(FYI, "Error in FindFirst = %d\n", rc); cifs_buf_release(pSMB); @@ -3738,9 +4437,8 @@ findFirstRetry: psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + psrch_inf->entries_in_buffer; lnoff = le16_to_cpu(parms->LastNameOffset); - if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE < - lnoff) { - cERROR(1, "ignoring corrupt resume name"); + if (CIFSMaxBufSize < lnoff) { + cifs_dbg(VFS, "ignoring corrupt resume name\n"); psrch_inf->last_entry = NULL; return rc; } @@ -3748,7 +4446,8 @@ findFirstRetry: psrch_inf->last_entry = psrch_inf->srch_entries_start + lnoff; - *pnetfid = parms->SearchHandle; + if (pnetfid) + *pnetfid = parms->SearchHandle; } else { cifs_buf_release(pSMB); } @@ -3757,18 +4456,20 @@ findFirstRetry: return rc; } -int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, - __u16 searchHandle, struct cifs_search_info *psrch_inf) +int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, + __u16 searchHandle, __u16 search_flags, + struct cifs_search_info *psrch_inf) { TRANSACTION2_FNEXT_REQ *pSMB = NULL; TRANSACTION2_FNEXT_RSP *pSMBr = NULL; T2_FNEXT_RSP_PARMS *parms; char *response_data; int rc = 0; - int bytes_returned, name_len; + int bytes_returned; + unsigned int name_len; __u16 params, byte_count; - cFYI(1, "In FindNext"); + cifs_dbg(FYI, "In FindNext\n"); if (psrch_inf->endOfSearch) return -ENOENT; @@ -3782,9 +4483,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, byte_count = 0; pSMB->TotalDataCount = 0; /* no EAs */ pSMB->MaxParameterCount = cpu_to_le16(8); - pSMB->MaxDataCount = - cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & - 0xFFFFFF00); + pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -3802,8 +4501,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO)); pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); pSMB->ResumeKey = psrch_inf->resume_key; - pSMB->SearchFlags = - cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); + pSMB->SearchFlags = cpu_to_le16(search_flags); name_len = psrch_inf->resume_name_len; params += name_len; @@ -3820,19 +4518,19 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, byte_count = params + 1 /* pad */ ; pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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); - cifs_stats_inc(&tcon->num_fnext); + cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext); if (rc) { if (rc == -EBADF) { psrch_inf->endOfSearch = true; cifs_buf_release(pSMB); rc = 0; /* search probably was closed at end of search*/ } else - cFYI(1, "FindNext returned = %d", rc); + cifs_dbg(FYI, "FindNext returned = %d\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); @@ -3866,17 +4564,16 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, psrch_inf->index_of_last_entry += psrch_inf->entries_in_buffer; lnoff = le16_to_cpu(parms->LastNameOffset); - if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE < - lnoff) { - cERROR(1, "ignoring corrupt resume name"); + if (CIFSMaxBufSize < lnoff) { + cifs_dbg(VFS, "ignoring corrupt resume name\n"); psrch_inf->last_entry = NULL; return rc; } else psrch_inf->last_entry = psrch_inf->srch_entries_start + lnoff; -/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d", - psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */ +/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n", + psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */ /* BB fixme add unlock here */ } @@ -3895,13 +4592,13 @@ FNext2_err_exit: } int -CIFSFindClose(const int xid, struct cifsTconInfo *tcon, +CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon, const __u16 searchHandle) { int rc = 0; FINDCLOSE_REQ *pSMB = NULL; - cFYI(1, "In CIFSSMBFindClose"); + cifs_dbg(FYI, "In CIFSSMBFindClose\n"); rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB); /* no sense returning error if session restarted @@ -3913,11 +4610,11 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, pSMB->FileID = searchHandle; pSMB->ByteCount = 0; - rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); if (rc) - cERROR(1, "Send error in FindClose = %d", rc); + cifs_dbg(VFS, "Send error in FindClose = %d\n", rc); - cifs_stats_inc(&tcon->num_fclose); + cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose); /* Since session is dead, search handle closed on server already */ if (rc == -EAGAIN) @@ -3927,9 +4624,8 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, } int -CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, - const unsigned char *searchName, - __u64 *inode_number, +CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, + const char *search_name, __u64 *inode_number, const struct nls_table *nls_codepage, int remap) { int rc = 0; @@ -3938,7 +4634,7 @@ CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, int name_len, bytes_returned; __u16 params, byte_count; - cFYI(1, "In GetSrvInodeNum for %s", searchName); + cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name); if (tcon == NULL) return -ENODEV; @@ -3950,14 +4646,15 @@ GetInodeNumberRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, + search_name, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(searchName, PATH_MAX); + name_len = strnlen(search_name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->FileName, searchName, name_len); + strncpy(pSMB->FileName, search_name, name_len); } params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; @@ -3982,18 +4679,18 @@ GetInodeNumberRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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, "error %d in QueryInternalInfo", rc); + cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 2)) /* BB also check enough total bytes returned */ + if (rc || get_bcc(&pSMBr->hdr) < 2) /* If rc should we check for EOPNOSUPP and disable the srvino flag? or in caller? */ rc = -EIO; /* bad smb */ @@ -4003,7 +4700,7 @@ GetInodeNumberRetry: struct file_internal_info *pfinfo; /* BB Do we need a cast or hash here ? */ if (count < 8) { - cFYI(1, "Illegal size ret in QryIntrnlInf"); + cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n"); rc = -EIO; goto GetInodeNumOut; } @@ -4044,16 +4741,16 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals); if (*num_of_nodes < 1) { - cERROR(1, "num_referrals: must be at least > 0," - "but we get num_referrals = %d\n", *num_of_nodes); + cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n", + *num_of_nodes); rc = -EINVAL; goto parse_DFS_referrals_exit; } ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals); if (ref->VersionNumber != cpu_to_le16(3)) { - cERROR(1, "Referrals of V%d version are not supported," - "should be V3", le16_to_cpu(ref->VersionNumber)); + cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n", + le16_to_cpu(ref->VersionNumber)); rc = -EINVAL; goto parse_DFS_referrals_exit; } @@ -4062,14 +4759,12 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, data_end = (char *)(&(pSMBr->PathConsumed)) + le16_to_cpu(pSMBr->t2.DataCount); - cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n", - *num_of_nodes, - le32_to_cpu(pSMBr->DFSFlags)); + cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n", + *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags)); - *target_nodes = kzalloc(sizeof(struct dfs_info3_param) * - *num_of_nodes, GFP_KERNEL); + *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param), + GFP_KERNEL); if (*target_nodes == NULL) { - cERROR(1, "Failed to allocate buffer for target_nodes\n"); rc = -ENOMEM; goto parse_DFS_referrals_exit; } @@ -4088,9 +4783,9 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, rc = -ENOMEM; goto parse_DFS_referrals_exit; } - cifsConvertToUCS((__le16 *) tmp, searchName, - PATH_MAX, nls_codepage, remap); - node->path_consumed = cifs_ucs2_bytes(tmp, + cifsConvertToUTF16((__le16 *) tmp, searchName, + PATH_MAX, nls_codepage, remap); + node->path_consumed = cifs_utf16_bytes(tmp, le16_to_cpu(pSMBr->PathConsumed), nls_codepage); kfree(tmp); @@ -4103,8 +4798,8 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, /* copy DfsPath */ temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); max_len = data_end - temp; - node->path_name = cifs_strndup_from_ucs(temp, max_len, - is_unicode, nls_codepage); + node->path_name = cifs_strndup_from_utf16(temp, max_len, + is_unicode, nls_codepage); if (!node->path_name) { rc = -ENOMEM; goto parse_DFS_referrals_exit; @@ -4113,10 +4808,14 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, /* copy link target UNC */ temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); max_len = data_end - temp; - node->node_name = cifs_strndup_from_ucs(temp, max_len, - is_unicode, nls_codepage); - if (!node->node_name) + node->node_name = cifs_strndup_from_utf16(temp, max_len, + is_unicode, nls_codepage); + if (!node->node_name) { rc = -ENOMEM; + goto parse_DFS_referrals_exit; + } + + ref++; } parse_DFS_referrals_exit: @@ -4129,9 +4828,8 @@ parse_DFS_referrals_exit: } int -CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, - const unsigned char *searchName, - struct dfs_info3_param **target_nodes, +CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, + const char *search_name, struct dfs_info3_param **target_nodes, unsigned int *num_of_nodes, const struct nls_table *nls_codepage, int remap) { @@ -4145,7 +4843,7 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, *num_of_nodes = 0; *target_nodes = NULL; - cFYI(1, "In GetDFSRefer the path %s", searchName); + cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name); if (ses == NULL) return -ENODEV; getDFSRetry: @@ -4156,7 +4854,7 @@ getDFSRetry: /* server pointer checked in called function, but should never be null here anyway */ - pSMB->hdr.Mid = GetNextMid(ses->server); + pSMB->hdr.Mid = get_next_mid(ses->server); pSMB->hdr.Tid = ses->ipc_tid; pSMB->hdr.Uid = ses->Suid; if (ses->capabilities & CAP_STATUS32) @@ -4167,21 +4865,19 @@ getDFSRetry: if (ses->capabilities & CAP_UNICODE) { pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; name_len = - cifsConvertToUCS((__le16 *) pSMB->RequestFileName, - searchName, PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->RequestFileName, + search_name, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(searchName, PATH_MAX); + name_len = strnlen(search_name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->RequestFileName, searchName, name_len); + strncpy(pSMB->RequestFileName, search_name, name_len); } - if (ses->server) { - if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - } + if (ses->server && ses->server->sign) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->hdr.Uid = ses->Suid; @@ -4206,31 +4902,30 @@ getDFSRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->MaxReferralLevel = cpu_to_le16(3); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { - cFYI(1, "Send error in GetDFSRefer = %d", rc); + cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc); goto GetDFSRefExit; } rc = validate_t2((struct smb_t2_rsp *)pSMBr); /* BB Also check if enough total bytes returned? */ - if (rc || (pSMBr->ByteCount < 17)) { + if (rc || get_bcc(&pSMBr->hdr) < 17) { rc = -EIO; /* bad smb */ goto GetDFSRefExit; } - cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d", - pSMBr->ByteCount, - le16_to_cpu(pSMBr->t2.DataOffset)); + cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n", + get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset)); /* parse returned result into more usable form */ rc = parse_DFS_referrals(pSMBr, num_of_nodes, target_nodes, nls_codepage, remap, - searchName); + search_name); GetDFSRefExit: cifs_buf_release(pSMB); @@ -4243,7 +4938,8 @@ GetDFSRefExit: /* 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) +SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, + struct kstatfs *FSData) { /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -4253,7 +4949,7 @@ SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) int bytes_returned = 0; __u16 params, byte_count; - cFYI(1, "OldQFSInfo"); + cifs_dbg(FYI, "OldQFSInfo\n"); oldQFSInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -4280,22 +4976,22 @@ oldQFSInfoRetry: 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; + inc_rfc1001_len(pSMB, 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); + cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 18)) + if (rc || get_bcc(&pSMBr->hdr) < 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); + cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n", + get_bcc(&pSMBr->hdr), data_offset); response_data = (FILE_SYSTEM_ALLOC_INFO *) (((char *) &pSMBr->hdr.Protocol) + data_offset); @@ -4307,10 +5003,10 @@ oldQFSInfoRetry: 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_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n", + (unsigned long long)FSData->f_blocks, + (unsigned long long)FSData->f_bfree, + FSData->f_bsize); } } cifs_buf_release(pSMB); @@ -4322,7 +5018,8 @@ oldQFSInfoRetry: } int -CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) +CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, + struct kstatfs *FSData) { /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -4332,7 +5029,7 @@ CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) int bytes_returned = 0; __u16 params, byte_count; - cFYI(1, "In QFSInfo"); + cifs_dbg(FYI, "In QFSInfo\n"); QFSInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -4359,17 +5056,17 @@ QFSInfoRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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); + cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 24)) + if (rc || get_bcc(&pSMBr->hdr) < 24) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -4386,10 +5083,10 @@ QFSInfoRetry: le64_to_cpu(response_data->TotalAllocationUnits); FSData->f_bfree = FSData->f_bavail = le64_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_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n", + (unsigned long long)FSData->f_blocks, + (unsigned long long)FSData->f_bfree, + FSData->f_bsize); } } cifs_buf_release(pSMB); @@ -4401,7 +5098,7 @@ QFSInfoRetry: } int -CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon) +CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon) { /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -4411,7 +5108,7 @@ CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon) int bytes_returned = 0; __u16 params, byte_count; - cFYI(1, "In QFSAttributeInfo"); + cifs_dbg(FYI, "In QFSAttributeInfo\n"); QFSAttributeRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -4439,17 +5136,17 @@ QFSAttributeRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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) { - cERROR(1, "Send error in QFSAttributeInfo = %d", rc); + cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 13)) { + if (rc || get_bcc(&pSMBr->hdr) < 13) { /* BB also check if enough bytes returned */ rc = -EIO; /* bad smb */ } else { @@ -4471,7 +5168,7 @@ QFSAttributeRetry: } int -CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon) +CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon) { /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -4481,7 +5178,7 @@ CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon) int bytes_returned = 0; __u16 params, byte_count; - cFYI(1, "In QFSDeviceInfo"); + cifs_dbg(FYI, "In QFSDeviceInfo\n"); QFSDeviceRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -4510,17 +5207,18 @@ QFSDeviceRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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 QFSDeviceInfo = %d", rc); + cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO))) + if (rc || get_bcc(&pSMBr->hdr) < + sizeof(FILE_SYSTEM_DEVICE_INFO)) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -4541,7 +5239,7 @@ QFSDeviceRetry: } int -CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon) +CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon) { /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -4551,7 +5249,7 @@ CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon) int bytes_returned = 0; __u16 params, byte_count; - cFYI(1, "In QFSUnixInfo"); + cifs_dbg(FYI, "In QFSUnixInfo\n"); QFSUnixRetry: rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -4579,17 +5277,17 @@ QFSUnixRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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) { - cERROR(1, "Send error in QFSUnixInfo = %d", rc); + cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 13)) { + if (rc || get_bcc(&pSMBr->hdr) < 13) { rc = -EIO; /* bad smb */ } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -4611,7 +5309,7 @@ QFSUnixRetry: } int -CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap) +CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap) { /* level 0x200 SMB_SET_CIFS_UNIX_INFO */ TRANSACTION2_SETFSI_REQ *pSMB = NULL; @@ -4620,7 +5318,7 @@ CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap) int bytes_returned = 0; __u16 params, param_offset, offset, byte_count; - cFYI(1, "In SETFSUnixInfo"); + cifs_dbg(FYI, "In SETFSUnixInfo\n"); SETFSUnixRetry: /* BB switch to small buf init to save memory */ rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon, @@ -4662,13 +5360,13 @@ SETFSUnixRetry: pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); pSMB->ClientUnixCap = cpu_to_le64(cap); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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) { - cERROR(1, "Send error in SETFSUnixInfo = %d", rc); + cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc) @@ -4685,7 +5383,7 @@ SETFSUnixRetry: int -CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, +CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon, struct kstatfs *FSData) { /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */ @@ -4696,7 +5394,7 @@ CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, int bytes_returned = 0; __u16 params, byte_count; - cFYI(1, "In QFSPosixInfo"); + cifs_dbg(FYI, "In QFSPosixInfo\n"); QFSPosixRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -4724,17 +5422,17 @@ QFSPosixRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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 QFSUnixInfo = %d", rc); + cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 13)) { + if (rc || get_bcc(&pSMBr->hdr) < 13) { rc = -EIO; /* bad smb */ } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -4771,16 +5469,16 @@ QFSPosixRetry: } -/* We can not use write of zero bytes trick to - set file size due to need for large file support. Also note that - this SetPathInfo is preferred to SetFileInfo based method in next - routine which is only needed to work around a sharing violation bug - in Samba which this routine can run into */ - +/* + * We can not use write of zero bytes trick to set file size due to need for + * large file support. Also note that this SetPathInfo is preferred to + * SetFileInfo based method in next routine which is only needed to work around + * a sharing violation bugin Samba which this routine can run into. + */ int -CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName, - __u64 size, bool SetAllocation, - const struct nls_table *nls_codepage, int remap) +CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon, + const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb, + bool set_allocation) { struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; @@ -4788,9 +5486,11 @@ CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName, int name_len; int rc = 0; int bytes_returned = 0; + int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; + __u16 params, byte_count, data_count, param_offset, offset; - cFYI(1, "In SetEOF"); + cifs_dbg(FYI, "In SetEOF\n"); SetEOFRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -4799,14 +5499,14 @@ SetEOFRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name, + PATH_MAX, cifs_sb->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(fileName, PATH_MAX); + name_len = strnlen(file_name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->FileName, fileName, name_len); + strncpy(pSMB->FileName, file_name, name_len); } params = 6 + name_len; data_count = sizeof(struct file_end_of_file_info); @@ -4820,7 +5520,7 @@ SetEOFRetry: param_offset = offsetof(struct smb_com_transaction2_spi_req, InformationLevel) - 4; offset = param_offset + params; - if (SetAllocation) { + if (set_allocation) { if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); @@ -4850,13 +5550,13 @@ SetEOFRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); parm_data->FileSize = cpu_to_le64(size); 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, "SetPathInfo (file size) returned %d", rc); + cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc); cifs_buf_release(pSMB); @@ -4867,24 +5567,23 @@ SetEOFRetry: } int -CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, - __u16 fid, __u32 pid_of_opener, bool SetAllocation) +CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, + struct cifsFileInfo *cfile, __u64 size, bool set_allocation) { struct smb_com_transaction2_sfi_req *pSMB = NULL; - char *data_offset; struct file_end_of_file_info *parm_data; int rc = 0; __u16 params, param_offset, offset, byte_count, count; - cFYI(1, "SetFileSize (via SetFileInfo) %lld", - (long long)size); + cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n", + (long long)size); rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); if (rc) return rc; - pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); - pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); + pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid); + pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16)); params = 6; pSMB->MaxSetupCount = 0; @@ -4895,8 +5594,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; offset = param_offset + params; - data_offset = (char *) (&pSMB->hdr.Protocol) + offset; - count = sizeof(struct file_end_of_file_info); pSMB->MaxParameterCount = cpu_to_le16(2); /* BB find exact max SMB PDU from sess structure BB */ @@ -4915,8 +5612,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, + offset); pSMB->DataOffset = cpu_to_le16(offset); parm_data->FileSize = cpu_to_le64(size); - pSMB->Fid = fid; - if (SetAllocation) { + pSMB->Fid = cfile->fid.netfid; + if (set_allocation) { if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); @@ -4932,11 +5629,12 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); } pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); if (rc) { - cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc); + cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n", + rc); } /* Note: On -EAGAIN error only caller can retry on handle based calls @@ -4952,7 +5650,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, time and resort to the original setpathinfo level which takes the ancient DOS time format with 2 second granularity */ int -CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, +CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener) { struct smb_com_transaction2_sfi_req *pSMB = NULL; @@ -4960,7 +5658,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, int rc = 0; __u16 params, param_offset, offset, byte_count, count; - cFYI(1, "Set Times (via SetFileInfo)"); + cifs_dbg(FYI, "Set Times (via SetFileInfo)\n"); rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); if (rc) @@ -4978,7 +5676,8 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; offset = param_offset + params; - data_offset = (char *) (&pSMB->hdr.Protocol) + offset; + data_offset = (char *)pSMB + + offsetof(struct smb_hdr, Protocol) + offset; count = sizeof(FILE_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); @@ -5000,12 +5699,13 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, else pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); - rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); if (rc) - cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc); + cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n", + rc); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ @@ -5014,7 +5714,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, } int -CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon, +CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, bool delete_file, __u16 fid, __u32 pid_of_opener) { struct smb_com_transaction2_sfi_req *pSMB = NULL; @@ -5022,7 +5722,7 @@ CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon, int rc = 0; __u16 params, param_offset, offset, byte_count, count; - cFYI(1, "Set File Disposition (via SetFileInfo)"); + cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n"); rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); if (rc) @@ -5059,18 +5759,18 @@ CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon, pSMB->Fid = fid; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); *data_offset = delete_file ? 1 : 0; - rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); if (rc) - cFYI(1, "Send error in SetFileDisposition = %d", rc); + cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc); return rc; } int -CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon, +CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const FILE_BASIC_INFO *data, const struct nls_table *nls_codepage, int remap) { @@ -5082,7 +5782,7 @@ CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *data_offset; __u16 params, param_offset, offset, byte_count, count; - cFYI(1, "In SetTimes"); + cifs_dbg(FYI, "In SetTimes\n"); SetTimesRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, @@ -5092,8 +5792,8 @@ SetTimesRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -5132,13 +5832,13 @@ SetTimesRetry: else pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); 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, "SetPathInfo (times) returned %d", rc); + cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc); cifs_buf_release(pSMB); @@ -5154,7 +5854,7 @@ SetTimesRetry: handling it anyway and NT4 was what we thought it would be needed for Do not delete it until we prove whether needed for Win9x though */ int -CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName, +CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName, __u16 dos_attrs, const struct nls_table *nls_codepage) { SETATTR_REQ *pSMB = NULL; @@ -5163,7 +5863,7 @@ CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName, int bytes_returned; int name_len; - cFYI(1, "In SetAttrLegacy"); + cifs_dbg(FYI, "In SetAttrLegacy\n"); SetAttrLgcyRetry: rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB, @@ -5173,8 +5873,8 @@ SetAttrLgcyRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - ConvertToUCS((__le16 *) pSMB->fileName, fileName, - PATH_MAX, nls_codepage); + ConvertToUTF16((__le16 *) pSMB->fileName, fileName, + PATH_MAX, nls_codepage); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -5184,12 +5884,12 @@ SetAttrLgcyRetry: } pSMB->attr = cpu_to_le16(dos_attrs); pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) - cFYI(1, "Error in LegacySetAttr = %d", rc); + cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc); cifs_buf_release(pSMB); @@ -5204,13 +5904,19 @@ static void cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, const struct cifs_unix_set_info_args *args) { + u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64; u64 mode = args->mode; + if (uid_valid(args->uid)) + uid = from_kuid(&init_user_ns, args->uid); + if (gid_valid(args->gid)) + gid = from_kgid(&init_user_ns, args->gid); + /* * Samba server ignores set of file size to zero due to bugs in some * older clients, but we should be precise - we use SetFileSize to * set file size and do not want to truncate file size to zero - * accidently as happened on one Samba server beta by putting + * accidentally as happened on one Samba server beta by putting * zero instead of -1 here */ data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); @@ -5218,8 +5924,8 @@ cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, data_offset->LastStatusChange = cpu_to_le64(args->ctime); data_offset->LastAccessTime = cpu_to_le64(args->atime); data_offset->LastModificationTime = cpu_to_le64(args->mtime); - data_offset->Uid = cpu_to_le64(args->uid); - data_offset->Gid = cpu_to_le64(args->gid); + data_offset->Uid = cpu_to_le64(uid); + data_offset->Gid = cpu_to_le64(gid); /* better to leave device as zero when it is */ data_offset->DevMajor = cpu_to_le64(MAJOR(args->device)); data_offset->DevMinor = cpu_to_le64(MINOR(args->device)); @@ -5242,16 +5948,16 @@ cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, } int -CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, +CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, const struct cifs_unix_set_info_args *args, u16 fid, u32 pid_of_opener) { struct smb_com_transaction2_sfi_req *pSMB = NULL; - FILE_UNIX_BASIC_INFO *data_offset; + char *data_offset; int rc = 0; u16 params, param_offset, offset, byte_count, count; - cFYI(1, "Set Unix Info (via SetFileInfo)"); + cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n"); rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); if (rc) @@ -5269,8 +5975,9 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; offset = param_offset + params; - data_offset = (FILE_UNIX_BASIC_INFO *) - ((char *)(&pSMB->hdr.Protocol) + offset); + data_offset = (char *)pSMB + + offsetof(struct smb_hdr, Protocol) + offset; + count = sizeof(FILE_UNIX_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); @@ -5289,14 +5996,15 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, pSMB->Fid = fid; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); - cifs_fill_unix_set_info(data_offset, args); + cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args); - rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); if (rc) - cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc); + cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n", + rc); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ @@ -5305,7 +6013,8 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, } int -CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, +CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, + const char *file_name, const struct cifs_unix_set_info_args *args, const struct nls_table *nls_codepage, int remap) { @@ -5317,7 +6026,7 @@ CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, FILE_UNIX_BASIC_INFO *data_offset; __u16 params, param_offset, offset, count, byte_count; - cFYI(1, "In SetUID/GID/Mode"); + cifs_dbg(FYI, "In SetUID/GID/Mode\n"); setPermsRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -5326,14 +6035,14 @@ setPermsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(fileName, PATH_MAX); + name_len = strnlen(file_name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->FileName, fileName, name_len); + strncpy(pSMB->FileName, file_name, name_len); } params = 6 + name_len; @@ -5365,7 +6074,7 @@ setPermsRetry: pSMB->TotalDataCount = pSMB->DataCount; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); cifs_fill_unix_set_info(data_offset, args); @@ -5373,7 +6082,7 @@ setPermsRetry: rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) - cFYI(1, "SetPathInfo (perms) returned %d", rc); + cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc); cifs_buf_release(pSMB); if (rc == -EAGAIN) @@ -5381,79 +6090,6 @@ setPermsRetry: return rc; } -int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, - const int notify_subdirs, const __u16 netfid, - __u32 filter, struct file *pfile, int multishot, - const struct nls_table *nls_codepage) -{ - int rc = 0; - struct smb_com_transaction_change_notify_req *pSMB = NULL; - struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL; - struct dir_notify_req *dnotify_req; - int bytes_returned; - - cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid); - rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; - - pSMB->TotalParameterCount = 0 ; - pSMB->TotalDataCount = 0; - pSMB->MaxParameterCount = cpu_to_le32(2); - /* BB find exact data count max from sess structure BB */ - pSMB->MaxDataCount = 0; /* same in little endian or be */ -/* BB VERIFY verify which is correct for above BB */ - pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); - - pSMB->MaxSetupCount = 4; - pSMB->Reserved = 0; - pSMB->ParameterOffset = 0; - pSMB->DataCount = 0; - pSMB->DataOffset = 0; - pSMB->SetupCount = 4; /* single byte does not need le conversion */ - pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); - pSMB->ParameterCount = pSMB->TotalParameterCount; - if (notify_subdirs) - pSMB->WatchTree = 1; /* one byte - no le conversion needed */ - pSMB->Reserved2 = 0; - pSMB->CompletionFilter = cpu_to_le32(filter); - pSMB->Fid = netfid; /* file handle always le */ - pSMB->ByteCount = 0; - - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *)pSMBr, &bytes_returned, - CIFS_ASYNC_OP); - if (rc) { - cFYI(1, "Error in Notify = %d", rc); - } else { - /* Add file to outstanding requests */ - /* BB change to kmem cache alloc */ - dnotify_req = kmalloc( - sizeof(struct dir_notify_req), - GFP_KERNEL); - if (dnotify_req) { - dnotify_req->Pid = pSMB->hdr.Pid; - dnotify_req->PidHigh = pSMB->hdr.PidHigh; - dnotify_req->Mid = pSMB->hdr.Mid; - dnotify_req->Tid = pSMB->hdr.Tid; - dnotify_req->Uid = pSMB->hdr.Uid; - dnotify_req->netfid = netfid; - dnotify_req->pfile = pfile; - dnotify_req->filter = filter; - dnotify_req->multishot = multishot; - spin_lock(&GlobalMid_Lock); - list_add_tail(&dnotify_req->lhead, - &GlobalDnotifyReqList); - spin_unlock(&GlobalMid_Lock); - } else - rc = -ENOMEM; - } - cifs_buf_release(pSMB); - return rc; -} - #ifdef CONFIG_CIFS_XATTR /* * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common @@ -5465,7 +6101,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, * the data isn't copied to it, but the length is returned. */ ssize_t -CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, +CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *searchName, const unsigned char *ea_name, char *EAData, size_t buf_size, const struct nls_table *nls_codepage, int remap) @@ -5481,8 +6117,9 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, char *temp_ptr; char *end_of_smb; __u16 params, byte_count, data_offset; + unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0; - cFYI(1, "In Query All EAs path %s", searchName); + cifs_dbg(FYI, "In Query All EAs path %s\n", searchName); QAllEAsRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -5491,8 +6128,8 @@ QAllEAsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { list_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); list_len++; /* trailing null */ list_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -5523,13 +6160,13 @@ QAllEAsRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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 QueryAllEAs = %d", rc); + cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc); goto QAllEAsOut; } @@ -5539,7 +6176,7 @@ QAllEAsRetry: of these trans2 responses */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 4)) { + if (rc || get_bcc(&pSMBr->hdr) < 4) { rc = -EIO; /* bad smb */ goto QAllEAsOut; } @@ -5557,16 +6194,19 @@ QAllEAsRetry: (((char *) &pSMBr->hdr.Protocol) + data_offset); list_len = le32_to_cpu(ea_response_data->list_len); - cFYI(1, "ea length %d", list_len); + cifs_dbg(FYI, "ea length %d\n", list_len); if (list_len <= 8) { - cFYI(1, "empty EA list returned from server"); + cifs_dbg(FYI, "empty EA list returned from server\n"); + /* didn't find the named attribute */ + if (ea_name) + rc = -ENODATA; goto QAllEAsOut; } /* make sure list_len doesn't go past end of SMB */ - end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr); + end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr); if ((char *)ea_response_data + list_len > end_of_smb) { - cFYI(1, "EA list appears to go beyond SMB"); + cifs_dbg(FYI, "EA list appears to go beyond SMB\n"); rc = -EIO; goto QAllEAsOut; } @@ -5583,7 +6223,7 @@ QAllEAsRetry: temp_ptr += 4; /* make sure we can read name_len and value_len */ if (list_len < 0) { - cFYI(1, "EA entry goes beyond length of list"); + cifs_dbg(FYI, "EA entry goes beyond length of list\n"); rc = -EIO; goto QAllEAsOut; } @@ -5592,13 +6232,14 @@ QAllEAsRetry: value_len = le16_to_cpu(temp_fea->value_len); list_len -= name_len + 1 + value_len; if (list_len < 0) { - cFYI(1, "EA entry goes beyond length of list"); + cifs_dbg(FYI, "EA entry goes beyond length of list\n"); rc = -EIO; goto QAllEAsOut; } if (ea_name) { - if (strncmp(ea_name, temp_ptr, name_len) == 0) { + if (ea_name_len == name_len && + memcmp(ea_name, temp_ptr, name_len) == 0) { temp_ptr += name_len + 1; rc = value_len; if (buf_size == 0) @@ -5646,8 +6287,8 @@ QAllEAsOut: } int -CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, - const char *ea_name, const void *ea_value, +CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, const char *ea_name, const void *ea_value, const __u16 ea_value_len, const struct nls_table *nls_codepage, int remap) { @@ -5659,7 +6300,7 @@ CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, int bytes_returned = 0; __u16 params, param_offset, byte_count, offset, count; - cFYI(1, "In SetEA"); + cifs_dbg(FYI, "In SetEA\n"); SetEARetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -5668,8 +6309,8 @@ SetEARetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -5736,12 +6377,12 @@ SetEARetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, 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, "SetPathInfo (EA) returned %d", rc); + cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc); cifs_buf_release(pSMB); @@ -5750,5 +6391,94 @@ SetEARetry: return rc; } - #endif + +#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */ +/* + * Years ago the kernel added a "dnotify" function for Samba server, + * to allow network clients (such as Windows) to display updated + * lists of files in directory listings automatically when + * files are added by one user when another user has the + * same directory open on their desktop. The Linux cifs kernel + * client hooked into the kernel side of this interface for + * the same reason, but ironically when the VFS moved from + * "dnotify" to "inotify" it became harder to plug in Linux + * network file system clients (the most obvious use case + * for notify interfaces is when multiple users can update + * the contents of the same directory - exactly what network + * file systems can do) although the server (Samba) could + * still use it. For the short term we leave the worker + * function ifdeffed out (below) until inotify is fixed + * in the VFS to make it easier to plug in network file + * system clients. If inotify turns out to be permanently + * incompatible for network fs clients, we could instead simply + * expose this config flag by adding a future cifs (and smb2) notify ioctl. + */ +int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon, + const int notify_subdirs, const __u16 netfid, + __u32 filter, struct file *pfile, int multishot, + const struct nls_table *nls_codepage) +{ + int rc = 0; + struct smb_com_transaction_change_notify_req *pSMB = NULL; + struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL; + struct dir_notify_req *dnotify_req; + int bytes_returned; + + cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid); + rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 0 ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le32(2); + pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); + pSMB->MaxSetupCount = 4; + pSMB->Reserved = 0; + pSMB->ParameterOffset = 0; + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 4; /* single byte does not need le conversion */ + pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); + pSMB->ParameterCount = pSMB->TotalParameterCount; + if (notify_subdirs) + pSMB->WatchTree = 1; /* one byte - no le conversion needed */ + pSMB->Reserved2 = 0; + pSMB->CompletionFilter = cpu_to_le32(filter); + pSMB->Fid = netfid; /* file handle always le */ + pSMB->ByteCount = 0; + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *)pSMBr, &bytes_returned, + CIFS_ASYNC_OP); + if (rc) { + cifs_dbg(FYI, "Error in Notify = %d\n", rc); + } else { + /* Add file to outstanding requests */ + /* BB change to kmem cache alloc */ + dnotify_req = kmalloc( + sizeof(struct dir_notify_req), + GFP_KERNEL); + if (dnotify_req) { + dnotify_req->Pid = pSMB->hdr.Pid; + dnotify_req->PidHigh = pSMB->hdr.PidHigh; + dnotify_req->Mid = pSMB->hdr.Mid; + dnotify_req->Tid = pSMB->hdr.Tid; + dnotify_req->Uid = pSMB->hdr.Uid; + dnotify_req->netfid = netfid; + dnotify_req->pfile = pfile; + dnotify_req->filter = filter; + dnotify_req->multishot = multishot; + spin_lock(&GlobalMid_Lock); + list_add_tail(&dnotify_req->lhead, + &GlobalDnotifyReqList); + spin_unlock(&GlobalMid_Lock); + } else + rc = -ENOMEM; + } + cifs_buf_release(pSMB); + return rc; +} +#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ |
