162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2002,2010 562306a36Sopenharmony_ci * Author(s): Steve French (sfrench@us.ibm.com) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Contains the routines for constructing the SMB PDUs themselves 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */ 1262306a36Sopenharmony_ci /* These are mostly routines that operate on a pathname, or on a tree id */ 1362306a36Sopenharmony_ci /* (mounted volume), but there are eight handle based routines which must be */ 1462306a36Sopenharmony_ci /* treated slightly differently for reconnection purposes since we never */ 1562306a36Sopenharmony_ci /* want to reuse a stale file handle and only the caller knows the file info */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/fs.h> 1862306a36Sopenharmony_ci#include <linux/filelock.h> 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/vfs.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/posix_acl_xattr.h> 2362306a36Sopenharmony_ci#include <linux/pagemap.h> 2462306a36Sopenharmony_ci#include <linux/swap.h> 2562306a36Sopenharmony_ci#include <linux/task_io_accounting_ops.h> 2662306a36Sopenharmony_ci#include <linux/uaccess.h> 2762306a36Sopenharmony_ci#include "cifspdu.h" 2862306a36Sopenharmony_ci#include "cifsfs.h" 2962306a36Sopenharmony_ci#include "cifsglob.h" 3062306a36Sopenharmony_ci#include "cifsacl.h" 3162306a36Sopenharmony_ci#include "cifsproto.h" 3262306a36Sopenharmony_ci#include "cifs_unicode.h" 3362306a36Sopenharmony_ci#include "cifs_debug.h" 3462306a36Sopenharmony_ci#include "fscache.h" 3562306a36Sopenharmony_ci#include "smbdirect.h" 3662306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DFS_UPCALL 3762306a36Sopenharmony_ci#include "dfs_cache.h" 3862306a36Sopenharmony_ci#endif 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#ifdef CONFIG_CIFS_POSIX 4162306a36Sopenharmony_cistatic struct { 4262306a36Sopenharmony_ci int index; 4362306a36Sopenharmony_ci char *name; 4462306a36Sopenharmony_ci} protocols[] = { 4562306a36Sopenharmony_ci {CIFS_PROT, "\2NT LM 0.12"}, 4662306a36Sopenharmony_ci {POSIX_PROT, "\2POSIX 2"}, 4762306a36Sopenharmony_ci {BAD_PROT, "\2"} 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci#else 5062306a36Sopenharmony_cistatic struct { 5162306a36Sopenharmony_ci int index; 5262306a36Sopenharmony_ci char *name; 5362306a36Sopenharmony_ci} protocols[] = { 5462306a36Sopenharmony_ci {CIFS_PROT, "\2NT LM 0.12"}, 5562306a36Sopenharmony_ci {BAD_PROT, "\2"} 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci#endif 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* define the number of elements in the cifs dialect array */ 6062306a36Sopenharmony_ci#ifdef CONFIG_CIFS_POSIX 6162306a36Sopenharmony_ci#define CIFS_NUM_PROT 2 6262306a36Sopenharmony_ci#else /* not posix */ 6362306a36Sopenharmony_ci#define CIFS_NUM_PROT 1 6462306a36Sopenharmony_ci#endif /* CIFS_POSIX */ 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* reconnect the socket, tcon, and smb session if needed */ 6862306a36Sopenharmony_cistatic int 6962306a36Sopenharmony_cicifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci int rc; 7262306a36Sopenharmony_ci struct cifs_ses *ses; 7362306a36Sopenharmony_ci struct TCP_Server_Info *server; 7462306a36Sopenharmony_ci struct nls_table *nls_codepage = NULL; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* 7762306a36Sopenharmony_ci * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for 7862306a36Sopenharmony_ci * tcp and smb session status done differently for those three - in the 7962306a36Sopenharmony_ci * calling routine 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci if (!tcon) 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci ses = tcon->ses; 8562306a36Sopenharmony_ci server = ses->server; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* 8862306a36Sopenharmony_ci * only tree disconnect, open, and write, (and ulogoff which does not 8962306a36Sopenharmony_ci * have tcon) are allowed as we start umount 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci spin_lock(&tcon->tc_lock); 9262306a36Sopenharmony_ci if (tcon->status == TID_EXITING) { 9362306a36Sopenharmony_ci if (smb_command != SMB_COM_TREE_DISCONNECT) { 9462306a36Sopenharmony_ci spin_unlock(&tcon->tc_lock); 9562306a36Sopenharmony_ci cifs_dbg(FYI, "can not send cmd %d while umounting\n", 9662306a36Sopenharmony_ci smb_command); 9762306a36Sopenharmony_ci return -ENODEV; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci spin_unlock(&tcon->tc_lock); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ciagain: 10362306a36Sopenharmony_ci rc = cifs_wait_for_server_reconnect(server, tcon->retry); 10462306a36Sopenharmony_ci if (rc) 10562306a36Sopenharmony_ci return rc; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci spin_lock(&ses->chan_lock); 10862306a36Sopenharmony_ci if (!cifs_chan_needs_reconnect(ses, server) && !tcon->need_reconnect) { 10962306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 11062306a36Sopenharmony_ci return 0; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci mutex_lock(&ses->session_mutex); 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * Recheck after acquire mutex. If another thread is negotiating 11762306a36Sopenharmony_ci * and the server never sends an answer the socket will be closed 11862306a36Sopenharmony_ci * and tcpStatus set to reconnect. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci spin_lock(&server->srv_lock); 12162306a36Sopenharmony_ci if (server->tcpStatus == CifsNeedReconnect) { 12262306a36Sopenharmony_ci spin_unlock(&server->srv_lock); 12362306a36Sopenharmony_ci mutex_unlock(&ses->session_mutex); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (tcon->retry) 12662306a36Sopenharmony_ci goto again; 12762306a36Sopenharmony_ci rc = -EHOSTDOWN; 12862306a36Sopenharmony_ci goto out; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci spin_unlock(&server->srv_lock); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci nls_codepage = ses->local_nls; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* 13562306a36Sopenharmony_ci * need to prevent multiple threads trying to simultaneously 13662306a36Sopenharmony_ci * reconnect the same SMB session 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci spin_lock(&ses->ses_lock); 13962306a36Sopenharmony_ci spin_lock(&ses->chan_lock); 14062306a36Sopenharmony_ci if (!cifs_chan_needs_reconnect(ses, server) && 14162306a36Sopenharmony_ci ses->ses_status == SES_GOOD) { 14262306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 14362306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* this means that we only need to tree connect */ 14662306a36Sopenharmony_ci if (tcon->need_reconnect) 14762306a36Sopenharmony_ci goto skip_sess_setup; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci mutex_unlock(&ses->session_mutex); 15062306a36Sopenharmony_ci goto out; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 15362306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci rc = cifs_negotiate_protocol(0, ses, server); 15662306a36Sopenharmony_ci if (!rc) 15762306a36Sopenharmony_ci rc = cifs_setup_session(0, ses, server, nls_codepage); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* do we need to reconnect tcon? */ 16062306a36Sopenharmony_ci if (rc || !tcon->need_reconnect) { 16162306a36Sopenharmony_ci mutex_unlock(&ses->session_mutex); 16262306a36Sopenharmony_ci goto out; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ciskip_sess_setup: 16662306a36Sopenharmony_ci cifs_mark_open_files_invalid(tcon); 16762306a36Sopenharmony_ci rc = cifs_tree_connect(0, tcon, nls_codepage); 16862306a36Sopenharmony_ci mutex_unlock(&ses->session_mutex); 16962306a36Sopenharmony_ci cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (rc) { 17262306a36Sopenharmony_ci pr_warn_once("reconnect tcon failed rc = %d\n", rc); 17362306a36Sopenharmony_ci goto out; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci atomic_inc(&tconInfoReconnectCount); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* tell server Unix caps we support */ 17962306a36Sopenharmony_ci if (cap_unix(ses)) 18062306a36Sopenharmony_ci reset_cifs_unix_caps(0, tcon, NULL, NULL); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* 18362306a36Sopenharmony_ci * Removed call to reopen open files here. It is safer (and faster) to 18462306a36Sopenharmony_ci * reopen files one at a time as needed in read and write. 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * FIXME: what about file locks? don't we need to reclaim them ASAP? 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ciout: 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * Check if handle based operation so we know whether we can continue 19262306a36Sopenharmony_ci * or not without returning to caller to reset file handle 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci switch (smb_command) { 19562306a36Sopenharmony_ci case SMB_COM_READ_ANDX: 19662306a36Sopenharmony_ci case SMB_COM_WRITE_ANDX: 19762306a36Sopenharmony_ci case SMB_COM_CLOSE: 19862306a36Sopenharmony_ci case SMB_COM_FIND_CLOSE2: 19962306a36Sopenharmony_ci case SMB_COM_LOCKING_ANDX: 20062306a36Sopenharmony_ci rc = -EAGAIN; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return rc; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* Allocate and return pointer to an SMB request buffer, and set basic 20762306a36Sopenharmony_ci SMB information in the SMB header. If the return code is zero, this 20862306a36Sopenharmony_ci function must have filled in request_buf pointer */ 20962306a36Sopenharmony_cistatic int 21062306a36Sopenharmony_cismall_smb_init(int smb_command, int wct, struct cifs_tcon *tcon, 21162306a36Sopenharmony_ci void **request_buf) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci int rc; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci rc = cifs_reconnect_tcon(tcon, smb_command); 21662306a36Sopenharmony_ci if (rc) 21762306a36Sopenharmony_ci return rc; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci *request_buf = cifs_small_buf_get(); 22062306a36Sopenharmony_ci if (*request_buf == NULL) { 22162306a36Sopenharmony_ci /* BB should we add a retry in here if not a writepage? */ 22262306a36Sopenharmony_ci return -ENOMEM; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci header_assemble((struct smb_hdr *) *request_buf, smb_command, 22662306a36Sopenharmony_ci tcon, wct); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (tcon != NULL) 22962306a36Sopenharmony_ci cifs_stats_inc(&tcon->num_smbs_sent); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciint 23562306a36Sopenharmony_cismall_smb_init_no_tc(const int smb_command, const int wct, 23662306a36Sopenharmony_ci struct cifs_ses *ses, void **request_buf) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci int rc; 23962306a36Sopenharmony_ci struct smb_hdr *buffer; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci rc = small_smb_init(smb_command, wct, NULL, request_buf); 24262306a36Sopenharmony_ci if (rc) 24362306a36Sopenharmony_ci return rc; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci buffer = (struct smb_hdr *)*request_buf; 24662306a36Sopenharmony_ci buffer->Mid = get_next_mid(ses->server); 24762306a36Sopenharmony_ci if (ses->capabilities & CAP_UNICODE) 24862306a36Sopenharmony_ci buffer->Flags2 |= SMBFLG2_UNICODE; 24962306a36Sopenharmony_ci if (ses->capabilities & CAP_STATUS32) 25062306a36Sopenharmony_ci buffer->Flags2 |= SMBFLG2_ERR_STATUS; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* uid, tid can stay at zero as set in header assemble */ 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* BB add support for turning on the signing when 25562306a36Sopenharmony_ci this function is used after 1st of session setup requests */ 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return rc; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/* If the return code is zero, this function must fill in request_buf pointer */ 26162306a36Sopenharmony_cistatic int 26262306a36Sopenharmony_ci__smb_init(int smb_command, int wct, struct cifs_tcon *tcon, 26362306a36Sopenharmony_ci void **request_buf, void **response_buf) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci *request_buf = cifs_buf_get(); 26662306a36Sopenharmony_ci if (*request_buf == NULL) { 26762306a36Sopenharmony_ci /* BB should we add a retry in here if not a writepage? */ 26862306a36Sopenharmony_ci return -ENOMEM; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci /* Although the original thought was we needed the response buf for */ 27162306a36Sopenharmony_ci /* potential retries of smb operations it turns out we can determine */ 27262306a36Sopenharmony_ci /* from the mid flags when the request buffer can be resent without */ 27362306a36Sopenharmony_ci /* having to use a second distinct buffer for the response */ 27462306a36Sopenharmony_ci if (response_buf) 27562306a36Sopenharmony_ci *response_buf = *request_buf; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, 27862306a36Sopenharmony_ci wct); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (tcon != NULL) 28162306a36Sopenharmony_ci cifs_stats_inc(&tcon->num_smbs_sent); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/* If the return code is zero, this function must fill in request_buf pointer */ 28762306a36Sopenharmony_cistatic int 28862306a36Sopenharmony_cismb_init(int smb_command, int wct, struct cifs_tcon *tcon, 28962306a36Sopenharmony_ci void **request_buf, void **response_buf) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci int rc; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci rc = cifs_reconnect_tcon(tcon, smb_command); 29462306a36Sopenharmony_ci if (rc) 29562306a36Sopenharmony_ci return rc; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return __smb_init(smb_command, wct, tcon, request_buf, response_buf); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic int 30162306a36Sopenharmony_cismb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon, 30262306a36Sopenharmony_ci void **request_buf, void **response_buf) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci spin_lock(&tcon->ses->chan_lock); 30562306a36Sopenharmony_ci if (cifs_chan_needs_reconnect(tcon->ses, tcon->ses->server) || 30662306a36Sopenharmony_ci tcon->need_reconnect) { 30762306a36Sopenharmony_ci spin_unlock(&tcon->ses->chan_lock); 30862306a36Sopenharmony_ci return -EHOSTDOWN; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci spin_unlock(&tcon->ses->chan_lock); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return __smb_init(smb_command, wct, tcon, request_buf, response_buf); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int validate_t2(struct smb_t2_rsp *pSMB) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci unsigned int total_size; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* check for plausible wct */ 32062306a36Sopenharmony_ci if (pSMB->hdr.WordCount < 10) 32162306a36Sopenharmony_ci goto vt2_err; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* check for parm and data offset going beyond end of smb */ 32462306a36Sopenharmony_ci if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 || 32562306a36Sopenharmony_ci get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024) 32662306a36Sopenharmony_ci goto vt2_err; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount); 32962306a36Sopenharmony_ci if (total_size >= 512) 33062306a36Sopenharmony_ci goto vt2_err; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* check that bcc is at least as big as parms + data, and that it is 33362306a36Sopenharmony_ci * less than negotiated smb buffer 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount); 33662306a36Sopenharmony_ci if (total_size > get_bcc(&pSMB->hdr) || 33762306a36Sopenharmony_ci total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) 33862306a36Sopenharmony_ci goto vt2_err; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_civt2_err: 34262306a36Sopenharmony_ci cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, 34362306a36Sopenharmony_ci sizeof(struct smb_t2_rsp) + 16); 34462306a36Sopenharmony_ci return -EINVAL; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int 34862306a36Sopenharmony_cidecode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci int rc = 0; 35162306a36Sopenharmony_ci u16 count; 35262306a36Sopenharmony_ci char *guid = pSMBr->u.extended_response.GUID; 35362306a36Sopenharmony_ci struct TCP_Server_Info *server = ses->server; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci count = get_bcc(&pSMBr->hdr); 35662306a36Sopenharmony_ci if (count < SMB1_CLIENT_GUID_SIZE) 35762306a36Sopenharmony_ci return -EIO; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci spin_lock(&cifs_tcp_ses_lock); 36062306a36Sopenharmony_ci if (server->srv_count > 1) { 36162306a36Sopenharmony_ci spin_unlock(&cifs_tcp_ses_lock); 36262306a36Sopenharmony_ci if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) { 36362306a36Sopenharmony_ci cifs_dbg(FYI, "server UID changed\n"); 36462306a36Sopenharmony_ci memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci } else { 36762306a36Sopenharmony_ci spin_unlock(&cifs_tcp_ses_lock); 36862306a36Sopenharmony_ci memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (count == SMB1_CLIENT_GUID_SIZE) { 37262306a36Sopenharmony_ci server->sec_ntlmssp = true; 37362306a36Sopenharmony_ci } else { 37462306a36Sopenharmony_ci count -= SMB1_CLIENT_GUID_SIZE; 37562306a36Sopenharmony_ci rc = decode_negTokenInit( 37662306a36Sopenharmony_ci pSMBr->u.extended_response.SecurityBlob, count, server); 37762306a36Sopenharmony_ci if (rc != 1) 37862306a36Sopenharmony_ci return -EINVAL; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return 0; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic bool 38562306a36Sopenharmony_cishould_set_ext_sec_flag(enum securityEnum sectype) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci switch (sectype) { 38862306a36Sopenharmony_ci case RawNTLMSSP: 38962306a36Sopenharmony_ci case Kerberos: 39062306a36Sopenharmony_ci return true; 39162306a36Sopenharmony_ci case Unspecified: 39262306a36Sopenharmony_ci if (global_secflags & 39362306a36Sopenharmony_ci (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)) 39462306a36Sopenharmony_ci return true; 39562306a36Sopenharmony_ci fallthrough; 39662306a36Sopenharmony_ci default: 39762306a36Sopenharmony_ci return false; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ciint 40262306a36Sopenharmony_ciCIFSSMBNegotiate(const unsigned int xid, 40362306a36Sopenharmony_ci struct cifs_ses *ses, 40462306a36Sopenharmony_ci struct TCP_Server_Info *server) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci NEGOTIATE_REQ *pSMB; 40762306a36Sopenharmony_ci NEGOTIATE_RSP *pSMBr; 40862306a36Sopenharmony_ci int rc = 0; 40962306a36Sopenharmony_ci int bytes_returned; 41062306a36Sopenharmony_ci int i; 41162306a36Sopenharmony_ci u16 count; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (!server) { 41462306a36Sopenharmony_ci WARN(1, "%s: server is NULL!\n", __func__); 41562306a36Sopenharmony_ci return -EIO; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , 41962306a36Sopenharmony_ci (void **) &pSMB, (void **) &pSMBr); 42062306a36Sopenharmony_ci if (rc) 42162306a36Sopenharmony_ci return rc; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci pSMB->hdr.Mid = get_next_mid(server); 42462306a36Sopenharmony_ci pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (should_set_ext_sec_flag(ses->sectype)) { 42762306a36Sopenharmony_ci cifs_dbg(FYI, "Requesting extended security\n"); 42862306a36Sopenharmony_ci pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci count = 0; 43262306a36Sopenharmony_ci /* 43362306a36Sopenharmony_ci * We know that all the name entries in the protocols array 43462306a36Sopenharmony_ci * are short (< 16 bytes anyway) and are NUL terminated. 43562306a36Sopenharmony_ci */ 43662306a36Sopenharmony_ci for (i = 0; i < CIFS_NUM_PROT; i++) { 43762306a36Sopenharmony_ci size_t len = strlen(protocols[i].name) + 1; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci memcpy(&pSMB->DialectsArray[count], protocols[i].name, len); 44062306a36Sopenharmony_ci count += len; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci inc_rfc1001_len(pSMB, count); 44362306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(count); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, 44662306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 44762306a36Sopenharmony_ci if (rc != 0) 44862306a36Sopenharmony_ci goto neg_err_exit; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci server->dialect = le16_to_cpu(pSMBr->DialectIndex); 45162306a36Sopenharmony_ci cifs_dbg(FYI, "Dialect: %d\n", server->dialect); 45262306a36Sopenharmony_ci /* Check wct = 1 error case */ 45362306a36Sopenharmony_ci if ((pSMBr->hdr.WordCount <= 13) || (server->dialect == BAD_PROT)) { 45462306a36Sopenharmony_ci /* core returns wct = 1, but we do not ask for core - otherwise 45562306a36Sopenharmony_ci small wct just comes when dialect index is -1 indicating we 45662306a36Sopenharmony_ci could not negotiate a common dialect */ 45762306a36Sopenharmony_ci rc = -EOPNOTSUPP; 45862306a36Sopenharmony_ci goto neg_err_exit; 45962306a36Sopenharmony_ci } else if (pSMBr->hdr.WordCount != 17) { 46062306a36Sopenharmony_ci /* unknown wct */ 46162306a36Sopenharmony_ci rc = -EOPNOTSUPP; 46262306a36Sopenharmony_ci goto neg_err_exit; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci /* else wct == 17, NTLM or better */ 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci server->sec_mode = pSMBr->SecurityMode; 46762306a36Sopenharmony_ci if ((server->sec_mode & SECMODE_USER) == 0) 46862306a36Sopenharmony_ci cifs_dbg(FYI, "share mode security\n"); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* one byte, so no need to convert this or EncryptionKeyLen from 47162306a36Sopenharmony_ci little endian */ 47262306a36Sopenharmony_ci server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), 47362306a36Sopenharmony_ci cifs_max_pending); 47462306a36Sopenharmony_ci set_credits(server, server->maxReq); 47562306a36Sopenharmony_ci /* probably no need to store and check maxvcs */ 47662306a36Sopenharmony_ci server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); 47762306a36Sopenharmony_ci /* set up max_read for readahead check */ 47862306a36Sopenharmony_ci server->max_read = server->maxBuf; 47962306a36Sopenharmony_ci server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); 48062306a36Sopenharmony_ci cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf); 48162306a36Sopenharmony_ci server->capabilities = le32_to_cpu(pSMBr->Capabilities); 48262306a36Sopenharmony_ci server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); 48362306a36Sopenharmony_ci server->timeAdj *= 60; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { 48662306a36Sopenharmony_ci server->negflavor = CIFS_NEGFLAVOR_UNENCAP; 48762306a36Sopenharmony_ci memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey, 48862306a36Sopenharmony_ci CIFS_CRYPTO_KEY_SIZE); 48962306a36Sopenharmony_ci } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC || 49062306a36Sopenharmony_ci server->capabilities & CAP_EXTENDED_SECURITY) { 49162306a36Sopenharmony_ci server->negflavor = CIFS_NEGFLAVOR_EXTENDED; 49262306a36Sopenharmony_ci rc = decode_ext_sec_blob(ses, pSMBr); 49362306a36Sopenharmony_ci } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { 49462306a36Sopenharmony_ci rc = -EIO; /* no crypt key only if plain text pwd */ 49562306a36Sopenharmony_ci } else { 49662306a36Sopenharmony_ci server->negflavor = CIFS_NEGFLAVOR_UNENCAP; 49762306a36Sopenharmony_ci server->capabilities &= ~CAP_EXTENDED_SECURITY; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (!rc) 50162306a36Sopenharmony_ci rc = cifs_enable_signing(server, ses->sign); 50262306a36Sopenharmony_cineg_err_exit: 50362306a36Sopenharmony_ci cifs_buf_release(pSMB); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci cifs_dbg(FYI, "negprot rc %d\n", rc); 50662306a36Sopenharmony_ci return rc; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ciint 51062306a36Sopenharmony_ciCIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct smb_hdr *smb_buffer; 51362306a36Sopenharmony_ci int rc = 0; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci cifs_dbg(FYI, "In tree disconnect\n"); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* BB: do we need to check this? These should never be NULL. */ 51862306a36Sopenharmony_ci if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) 51962306a36Sopenharmony_ci return -EIO; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* 52262306a36Sopenharmony_ci * No need to return error on this operation if tid invalidated and 52362306a36Sopenharmony_ci * closed on server already e.g. due to tcp session crashing. Also, 52462306a36Sopenharmony_ci * the tcon is no longer on the list, so no need to take lock before 52562306a36Sopenharmony_ci * checking this. 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_ci spin_lock(&tcon->ses->chan_lock); 52862306a36Sopenharmony_ci if ((tcon->need_reconnect) || CIFS_ALL_CHANS_NEED_RECONNECT(tcon->ses)) { 52962306a36Sopenharmony_ci spin_unlock(&tcon->ses->chan_lock); 53062306a36Sopenharmony_ci return -EIO; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci spin_unlock(&tcon->ses->chan_lock); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 53562306a36Sopenharmony_ci (void **)&smb_buffer); 53662306a36Sopenharmony_ci if (rc) 53762306a36Sopenharmony_ci return rc; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0); 54062306a36Sopenharmony_ci cifs_small_buf_release(smb_buffer); 54162306a36Sopenharmony_ci if (rc) 54262306a36Sopenharmony_ci cifs_dbg(FYI, "Tree disconnect failed %d\n", rc); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* No need to return error on this operation if tid invalidated and 54562306a36Sopenharmony_ci closed on server already e.g. due to tcp session crashing */ 54662306a36Sopenharmony_ci if (rc == -EAGAIN) 54762306a36Sopenharmony_ci rc = 0; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return rc; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci/* 55362306a36Sopenharmony_ci * This is a no-op for now. We're not really interested in the reply, but 55462306a36Sopenharmony_ci * rather in the fact that the server sent one and that server->lstrp 55562306a36Sopenharmony_ci * gets updated. 55662306a36Sopenharmony_ci * 55762306a36Sopenharmony_ci * FIXME: maybe we should consider checking that the reply matches request? 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_cistatic void 56062306a36Sopenharmony_cicifs_echo_callback(struct mid_q_entry *mid) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci struct TCP_Server_Info *server = mid->callback_data; 56362306a36Sopenharmony_ci struct cifs_credits credits = { .value = 1, .instance = 0 }; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci release_mid(mid); 56662306a36Sopenharmony_ci add_credits(server, &credits, CIFS_ECHO_OP); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ciint 57062306a36Sopenharmony_ciCIFSSMBEcho(struct TCP_Server_Info *server) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci ECHO_REQ *smb; 57362306a36Sopenharmony_ci int rc = 0; 57462306a36Sopenharmony_ci struct kvec iov[2]; 57562306a36Sopenharmony_ci struct smb_rqst rqst = { .rq_iov = iov, 57662306a36Sopenharmony_ci .rq_nvec = 2 }; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci cifs_dbg(FYI, "In echo request\n"); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb); 58162306a36Sopenharmony_ci if (rc) 58262306a36Sopenharmony_ci return rc; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (server->capabilities & CAP_UNICODE) 58562306a36Sopenharmony_ci smb->hdr.Flags2 |= SMBFLG2_UNICODE; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* set up echo request */ 58862306a36Sopenharmony_ci smb->hdr.Tid = 0xffff; 58962306a36Sopenharmony_ci smb->hdr.WordCount = 1; 59062306a36Sopenharmony_ci put_unaligned_le16(1, &smb->EchoCount); 59162306a36Sopenharmony_ci put_bcc(1, &smb->hdr); 59262306a36Sopenharmony_ci smb->Data[0] = 'a'; 59362306a36Sopenharmony_ci inc_rfc1001_len(smb, 3); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci iov[0].iov_len = 4; 59662306a36Sopenharmony_ci iov[0].iov_base = smb; 59762306a36Sopenharmony_ci iov[1].iov_len = get_rfc1002_length(smb); 59862306a36Sopenharmony_ci iov[1].iov_base = (char *)smb + 4; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL, 60162306a36Sopenharmony_ci server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL); 60262306a36Sopenharmony_ci if (rc) 60362306a36Sopenharmony_ci cifs_dbg(FYI, "Echo request failed: %d\n", rc); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci cifs_small_buf_release(smb); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return rc; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ciint 61162306a36Sopenharmony_ciCIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci LOGOFF_ANDX_REQ *pSMB; 61462306a36Sopenharmony_ci int rc = 0; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci cifs_dbg(FYI, "In SMBLogoff for session disconnect\n"); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* 61962306a36Sopenharmony_ci * BB: do we need to check validity of ses and server? They should 62062306a36Sopenharmony_ci * always be valid since we have an active reference. If not, that 62162306a36Sopenharmony_ci * should probably be a BUG() 62262306a36Sopenharmony_ci */ 62362306a36Sopenharmony_ci if (!ses || !ses->server) 62462306a36Sopenharmony_ci return -EIO; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci mutex_lock(&ses->session_mutex); 62762306a36Sopenharmony_ci spin_lock(&ses->chan_lock); 62862306a36Sopenharmony_ci if (CIFS_ALL_CHANS_NEED_RECONNECT(ses)) { 62962306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 63062306a36Sopenharmony_ci goto session_already_dead; /* no need to send SMBlogoff if uid 63162306a36Sopenharmony_ci already closed due to reconnect */ 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); 63662306a36Sopenharmony_ci if (rc) { 63762306a36Sopenharmony_ci mutex_unlock(&ses->session_mutex); 63862306a36Sopenharmony_ci return rc; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci pSMB->hdr.Mid = get_next_mid(ses->server); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (ses->server->sign) 64462306a36Sopenharmony_ci pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci pSMB->hdr.Uid = ses->Suid; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci pSMB->AndXCommand = 0xFF; 64962306a36Sopenharmony_ci rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0); 65062306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 65162306a36Sopenharmony_cisession_already_dead: 65262306a36Sopenharmony_ci mutex_unlock(&ses->session_mutex); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* if session dead then we do not need to do ulogoff, 65562306a36Sopenharmony_ci since server closed smb session, no sense reporting 65662306a36Sopenharmony_ci error */ 65762306a36Sopenharmony_ci if (rc == -EAGAIN) 65862306a36Sopenharmony_ci rc = 0; 65962306a36Sopenharmony_ci return rc; 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ciint 66362306a36Sopenharmony_ciCIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, 66462306a36Sopenharmony_ci const char *fileName, __u16 type, 66562306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci TRANSACTION2_SPI_REQ *pSMB = NULL; 66862306a36Sopenharmony_ci TRANSACTION2_SPI_RSP *pSMBr = NULL; 66962306a36Sopenharmony_ci struct unlink_psx_rq *pRqD; 67062306a36Sopenharmony_ci int name_len; 67162306a36Sopenharmony_ci int rc = 0; 67262306a36Sopenharmony_ci int bytes_returned = 0; 67362306a36Sopenharmony_ci __u16 params, param_offset, offset, byte_count; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci cifs_dbg(FYI, "In POSIX delete\n"); 67662306a36Sopenharmony_ciPsxDelete: 67762306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 67862306a36Sopenharmony_ci (void **) &pSMBr); 67962306a36Sopenharmony_ci if (rc) 68062306a36Sopenharmony_ci return rc; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 68362306a36Sopenharmony_ci name_len = 68462306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, 68562306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 68662306a36Sopenharmony_ci name_len++; /* trailing null */ 68762306a36Sopenharmony_ci name_len *= 2; 68862306a36Sopenharmony_ci } else { 68962306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, fileName); 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci params = 6 + name_len; 69362306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 69462306a36Sopenharmony_ci pSMB->MaxDataCount = 0; /* BB double check this with jra */ 69562306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 69662306a36Sopenharmony_ci pSMB->Reserved = 0; 69762306a36Sopenharmony_ci pSMB->Flags = 0; 69862306a36Sopenharmony_ci pSMB->Timeout = 0; 69962306a36Sopenharmony_ci pSMB->Reserved2 = 0; 70062306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_spi_req, 70162306a36Sopenharmony_ci InformationLevel) - 4; 70262306a36Sopenharmony_ci offset = param_offset + params; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci /* Setup pointer to Request Data (inode type). 70562306a36Sopenharmony_ci * Note that SMB offsets are from the beginning of SMB which is 4 bytes 70662306a36Sopenharmony_ci * in, after RFC1001 field 70762306a36Sopenharmony_ci */ 70862306a36Sopenharmony_ci pRqD = (struct unlink_psx_rq *)((char *)(pSMB) + offset + 4); 70962306a36Sopenharmony_ci pRqD->type = cpu_to_le16(type); 71062306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 71162306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 71262306a36Sopenharmony_ci pSMB->SetupCount = 1; 71362306a36Sopenharmony_ci pSMB->Reserved3 = 0; 71462306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); 71562306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq)); 71862306a36Sopenharmony_ci pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq)); 71962306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 72062306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 72162306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK); 72262306a36Sopenharmony_ci pSMB->Reserved4 = 0; 72362306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 72462306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 72562306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 72662306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 72762306a36Sopenharmony_ci if (rc) 72862306a36Sopenharmony_ci cifs_dbg(FYI, "Posix delete returned %d\n", rc); 72962306a36Sopenharmony_ci cifs_buf_release(pSMB); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (rc == -EAGAIN) 73462306a36Sopenharmony_ci goto PsxDelete; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci return rc; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ciint 74062306a36Sopenharmony_ciCIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 74162306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci DELETE_FILE_REQ *pSMB = NULL; 74462306a36Sopenharmony_ci DELETE_FILE_RSP *pSMBr = NULL; 74562306a36Sopenharmony_ci int rc = 0; 74662306a36Sopenharmony_ci int bytes_returned; 74762306a36Sopenharmony_ci int name_len; 74862306a36Sopenharmony_ci int remap = cifs_remap(cifs_sb); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ciDelFileRetry: 75162306a36Sopenharmony_ci rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, 75262306a36Sopenharmony_ci (void **) &pSMBr); 75362306a36Sopenharmony_ci if (rc) 75462306a36Sopenharmony_ci return rc; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 75762306a36Sopenharmony_ci name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name, 75862306a36Sopenharmony_ci PATH_MAX, cifs_sb->local_nls, 75962306a36Sopenharmony_ci remap); 76062306a36Sopenharmony_ci name_len++; /* trailing null */ 76162306a36Sopenharmony_ci name_len *= 2; 76262306a36Sopenharmony_ci } else { 76362306a36Sopenharmony_ci name_len = copy_path_name(pSMB->fileName, name); 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci pSMB->SearchAttributes = 76662306a36Sopenharmony_ci cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); 76762306a36Sopenharmony_ci pSMB->BufferFormat = 0x04; 76862306a36Sopenharmony_ci inc_rfc1001_len(pSMB, name_len + 1); 76962306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(name_len + 1); 77062306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 77162306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 77262306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes); 77362306a36Sopenharmony_ci if (rc) 77462306a36Sopenharmony_ci cifs_dbg(FYI, "Error in RMFile = %d\n", rc); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci cifs_buf_release(pSMB); 77762306a36Sopenharmony_ci if (rc == -EAGAIN) 77862306a36Sopenharmony_ci goto DelFileRetry; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci return rc; 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ciint 78462306a36Sopenharmony_ciCIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 78562306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci DELETE_DIRECTORY_REQ *pSMB = NULL; 78862306a36Sopenharmony_ci DELETE_DIRECTORY_RSP *pSMBr = NULL; 78962306a36Sopenharmony_ci int rc = 0; 79062306a36Sopenharmony_ci int bytes_returned; 79162306a36Sopenharmony_ci int name_len; 79262306a36Sopenharmony_ci int remap = cifs_remap(cifs_sb); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci cifs_dbg(FYI, "In CIFSSMBRmDir\n"); 79562306a36Sopenharmony_ciRmDirRetry: 79662306a36Sopenharmony_ci rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB, 79762306a36Sopenharmony_ci (void **) &pSMBr); 79862306a36Sopenharmony_ci if (rc) 79962306a36Sopenharmony_ci return rc; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 80262306a36Sopenharmony_ci name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, 80362306a36Sopenharmony_ci PATH_MAX, cifs_sb->local_nls, 80462306a36Sopenharmony_ci remap); 80562306a36Sopenharmony_ci name_len++; /* trailing null */ 80662306a36Sopenharmony_ci name_len *= 2; 80762306a36Sopenharmony_ci } else { 80862306a36Sopenharmony_ci name_len = copy_path_name(pSMB->DirName, name); 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci pSMB->BufferFormat = 0x04; 81262306a36Sopenharmony_ci inc_rfc1001_len(pSMB, name_len + 1); 81362306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(name_len + 1); 81462306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 81562306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 81662306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs); 81762306a36Sopenharmony_ci if (rc) 81862306a36Sopenharmony_ci cifs_dbg(FYI, "Error in RMDir = %d\n", rc); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci cifs_buf_release(pSMB); 82162306a36Sopenharmony_ci if (rc == -EAGAIN) 82262306a36Sopenharmony_ci goto RmDirRetry; 82362306a36Sopenharmony_ci return rc; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ciint 82762306a36Sopenharmony_ciCIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode, 82862306a36Sopenharmony_ci struct cifs_tcon *tcon, const char *name, 82962306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci int rc = 0; 83262306a36Sopenharmony_ci CREATE_DIRECTORY_REQ *pSMB = NULL; 83362306a36Sopenharmony_ci CREATE_DIRECTORY_RSP *pSMBr = NULL; 83462306a36Sopenharmony_ci int bytes_returned; 83562306a36Sopenharmony_ci int name_len; 83662306a36Sopenharmony_ci int remap = cifs_remap(cifs_sb); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci cifs_dbg(FYI, "In CIFSSMBMkDir\n"); 83962306a36Sopenharmony_ciMkDirRetry: 84062306a36Sopenharmony_ci rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB, 84162306a36Sopenharmony_ci (void **) &pSMBr); 84262306a36Sopenharmony_ci if (rc) 84362306a36Sopenharmony_ci return rc; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 84662306a36Sopenharmony_ci name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, 84762306a36Sopenharmony_ci PATH_MAX, cifs_sb->local_nls, 84862306a36Sopenharmony_ci remap); 84962306a36Sopenharmony_ci name_len++; /* trailing null */ 85062306a36Sopenharmony_ci name_len *= 2; 85162306a36Sopenharmony_ci } else { 85262306a36Sopenharmony_ci name_len = copy_path_name(pSMB->DirName, name); 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci pSMB->BufferFormat = 0x04; 85662306a36Sopenharmony_ci inc_rfc1001_len(pSMB, name_len + 1); 85762306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(name_len + 1); 85862306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 85962306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 86062306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs); 86162306a36Sopenharmony_ci if (rc) 86262306a36Sopenharmony_ci cifs_dbg(FYI, "Error in Mkdir = %d\n", rc); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci cifs_buf_release(pSMB); 86562306a36Sopenharmony_ci if (rc == -EAGAIN) 86662306a36Sopenharmony_ci goto MkDirRetry; 86762306a36Sopenharmony_ci return rc; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ciint 87162306a36Sopenharmony_ciCIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, 87262306a36Sopenharmony_ci __u32 posix_flags, __u64 mode, __u16 *netfid, 87362306a36Sopenharmony_ci FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock, 87462306a36Sopenharmony_ci const char *name, const struct nls_table *nls_codepage, 87562306a36Sopenharmony_ci int remap) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci TRANSACTION2_SPI_REQ *pSMB = NULL; 87862306a36Sopenharmony_ci TRANSACTION2_SPI_RSP *pSMBr = NULL; 87962306a36Sopenharmony_ci int name_len; 88062306a36Sopenharmony_ci int rc = 0; 88162306a36Sopenharmony_ci int bytes_returned = 0; 88262306a36Sopenharmony_ci __u16 params, param_offset, offset, byte_count, count; 88362306a36Sopenharmony_ci OPEN_PSX_REQ *pdata; 88462306a36Sopenharmony_ci OPEN_PSX_RSP *psx_rsp; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci cifs_dbg(FYI, "In POSIX Create\n"); 88762306a36Sopenharmony_ciPsxCreat: 88862306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 88962306a36Sopenharmony_ci (void **) &pSMBr); 89062306a36Sopenharmony_ci if (rc) 89162306a36Sopenharmony_ci return rc; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 89462306a36Sopenharmony_ci name_len = 89562306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, name, 89662306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 89762306a36Sopenharmony_ci name_len++; /* trailing null */ 89862306a36Sopenharmony_ci name_len *= 2; 89962306a36Sopenharmony_ci } else { 90062306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, name); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci params = 6 + name_len; 90462306a36Sopenharmony_ci count = sizeof(OPEN_PSX_REQ); 90562306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 90662306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */ 90762306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 90862306a36Sopenharmony_ci pSMB->Reserved = 0; 90962306a36Sopenharmony_ci pSMB->Flags = 0; 91062306a36Sopenharmony_ci pSMB->Timeout = 0; 91162306a36Sopenharmony_ci pSMB->Reserved2 = 0; 91262306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_spi_req, 91362306a36Sopenharmony_ci InformationLevel) - 4; 91462306a36Sopenharmony_ci offset = param_offset + params; 91562306a36Sopenharmony_ci /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ 91662306a36Sopenharmony_ci pdata = (OPEN_PSX_REQ *)((char *)(pSMB) + offset + 4); 91762306a36Sopenharmony_ci pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); 91862306a36Sopenharmony_ci pdata->Permissions = cpu_to_le64(mode); 91962306a36Sopenharmony_ci pdata->PosixOpenFlags = cpu_to_le32(posix_flags); 92062306a36Sopenharmony_ci pdata->OpenFlags = cpu_to_le32(*pOplock); 92162306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 92262306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 92362306a36Sopenharmony_ci pSMB->SetupCount = 1; 92462306a36Sopenharmony_ci pSMB->Reserved3 = 0; 92562306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); 92662306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + count; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(count); 92962306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 93062306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 93162306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 93262306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN); 93362306a36Sopenharmony_ci pSMB->Reserved4 = 0; 93462306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 93562306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 93662306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 93762306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 93862306a36Sopenharmony_ci if (rc) { 93962306a36Sopenharmony_ci cifs_dbg(FYI, "Posix create returned %d\n", rc); 94062306a36Sopenharmony_ci goto psx_create_err; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci cifs_dbg(FYI, "copying inode info\n"); 94462306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) { 94762306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 94862306a36Sopenharmony_ci goto psx_create_err; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci /* copy return information to pRetData */ 95262306a36Sopenharmony_ci psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol 95362306a36Sopenharmony_ci + le16_to_cpu(pSMBr->t2.DataOffset)); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci *pOplock = le16_to_cpu(psx_rsp->OplockFlags); 95662306a36Sopenharmony_ci if (netfid) 95762306a36Sopenharmony_ci *netfid = psx_rsp->Fid; /* cifs fid stays in le */ 95862306a36Sopenharmony_ci /* Let caller know file was created so we can set the mode. */ 95962306a36Sopenharmony_ci /* Do we care about the CreateAction in any other cases? */ 96062306a36Sopenharmony_ci if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction) 96162306a36Sopenharmony_ci *pOplock |= CIFS_CREATE_ACTION; 96262306a36Sopenharmony_ci /* check to make sure response data is there */ 96362306a36Sopenharmony_ci if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) { 96462306a36Sopenharmony_ci pRetData->Type = cpu_to_le32(-1); /* unknown */ 96562306a36Sopenharmony_ci cifs_dbg(NOISY, "unknown type\n"); 96662306a36Sopenharmony_ci } else { 96762306a36Sopenharmony_ci if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP) 96862306a36Sopenharmony_ci + sizeof(FILE_UNIX_BASIC_INFO)) { 96962306a36Sopenharmony_ci cifs_dbg(VFS, "Open response data too small\n"); 97062306a36Sopenharmony_ci pRetData->Type = cpu_to_le32(-1); 97162306a36Sopenharmony_ci goto psx_create_err; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci memcpy((char *) pRetData, 97462306a36Sopenharmony_ci (char *)psx_rsp + sizeof(OPEN_PSX_RSP), 97562306a36Sopenharmony_ci sizeof(FILE_UNIX_BASIC_INFO)); 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_cipsx_create_err: 97962306a36Sopenharmony_ci cifs_buf_release(pSMB); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (posix_flags & SMB_O_DIRECTORY) 98262306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs); 98362306a36Sopenharmony_ci else 98462306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (rc == -EAGAIN) 98762306a36Sopenharmony_ci goto PsxCreat; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci return rc; 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic __u16 convert_disposition(int disposition) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci __u16 ofun = 0; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci switch (disposition) { 99762306a36Sopenharmony_ci case FILE_SUPERSEDE: 99862306a36Sopenharmony_ci ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; 99962306a36Sopenharmony_ci break; 100062306a36Sopenharmony_ci case FILE_OPEN: 100162306a36Sopenharmony_ci ofun = SMBOPEN_OAPPEND; 100262306a36Sopenharmony_ci break; 100362306a36Sopenharmony_ci case FILE_CREATE: 100462306a36Sopenharmony_ci ofun = SMBOPEN_OCREATE; 100562306a36Sopenharmony_ci break; 100662306a36Sopenharmony_ci case FILE_OPEN_IF: 100762306a36Sopenharmony_ci ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND; 100862306a36Sopenharmony_ci break; 100962306a36Sopenharmony_ci case FILE_OVERWRITE: 101062306a36Sopenharmony_ci ofun = SMBOPEN_OTRUNC; 101162306a36Sopenharmony_ci break; 101262306a36Sopenharmony_ci case FILE_OVERWRITE_IF: 101362306a36Sopenharmony_ci ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; 101462306a36Sopenharmony_ci break; 101562306a36Sopenharmony_ci default: 101662306a36Sopenharmony_ci cifs_dbg(FYI, "unknown disposition %d\n", disposition); 101762306a36Sopenharmony_ci ofun = SMBOPEN_OAPPEND; /* regular open */ 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci return ofun; 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cistatic int 102362306a36Sopenharmony_ciaccess_flags_to_smbopen_mode(const int access_flags) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (masked_flags == GENERIC_READ) 102862306a36Sopenharmony_ci return SMBOPEN_READ; 102962306a36Sopenharmony_ci else if (masked_flags == GENERIC_WRITE) 103062306a36Sopenharmony_ci return SMBOPEN_WRITE; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci /* just go for read/write */ 103362306a36Sopenharmony_ci return SMBOPEN_READWRITE; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ciint 103762306a36Sopenharmony_ciSMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, 103862306a36Sopenharmony_ci const char *fileName, const int openDisposition, 103962306a36Sopenharmony_ci const int access_flags, const int create_options, __u16 *netfid, 104062306a36Sopenharmony_ci int *pOplock, FILE_ALL_INFO *pfile_info, 104162306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci int rc; 104462306a36Sopenharmony_ci OPENX_REQ *pSMB = NULL; 104562306a36Sopenharmony_ci OPENX_RSP *pSMBr = NULL; 104662306a36Sopenharmony_ci int bytes_returned; 104762306a36Sopenharmony_ci int name_len; 104862306a36Sopenharmony_ci __u16 count; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ciOldOpenRetry: 105162306a36Sopenharmony_ci rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB, 105262306a36Sopenharmony_ci (void **) &pSMBr); 105362306a36Sopenharmony_ci if (rc) 105462306a36Sopenharmony_ci return rc; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci pSMB->AndXCommand = 0xFF; /* none */ 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 105962306a36Sopenharmony_ci count = 1; /* account for one byte pad to word boundary */ 106062306a36Sopenharmony_ci name_len = 106162306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1), 106262306a36Sopenharmony_ci fileName, PATH_MAX, nls_codepage, remap); 106362306a36Sopenharmony_ci name_len++; /* trailing null */ 106462306a36Sopenharmony_ci name_len *= 2; 106562306a36Sopenharmony_ci } else { 106662306a36Sopenharmony_ci count = 0; /* no pad */ 106762306a36Sopenharmony_ci name_len = copy_path_name(pSMB->fileName, fileName); 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci if (*pOplock & REQ_OPLOCK) 107062306a36Sopenharmony_ci pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK); 107162306a36Sopenharmony_ci else if (*pOplock & REQ_BATCHOPLOCK) 107262306a36Sopenharmony_ci pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); 107562306a36Sopenharmony_ci pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags)); 107662306a36Sopenharmony_ci pSMB->Mode |= cpu_to_le16(0x40); /* deny none */ 107762306a36Sopenharmony_ci /* set file as system file if special file such 107862306a36Sopenharmony_ci as fifo and server expecting SFU style and 107962306a36Sopenharmony_ci no Unix extensions */ 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci if (create_options & CREATE_OPTION_SPECIAL) 108262306a36Sopenharmony_ci pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM); 108362306a36Sopenharmony_ci else /* BB FIXME BB */ 108462306a36Sopenharmony_ci pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (create_options & CREATE_OPTION_READONLY) 108762306a36Sopenharmony_ci pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci /* BB FIXME BB */ 109062306a36Sopenharmony_ci/* pSMB->CreateOptions = cpu_to_le32(create_options & 109162306a36Sopenharmony_ci CREATE_OPTIONS_MASK); */ 109262306a36Sopenharmony_ci /* BB FIXME END BB */ 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); 109562306a36Sopenharmony_ci pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); 109662306a36Sopenharmony_ci count += name_len; 109762306a36Sopenharmony_ci inc_rfc1001_len(pSMB, count); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(count); 110062306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 110162306a36Sopenharmony_ci (struct smb_hdr *)pSMBr, &bytes_returned, 0); 110262306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_opens); 110362306a36Sopenharmony_ci if (rc) { 110462306a36Sopenharmony_ci cifs_dbg(FYI, "Error in Open = %d\n", rc); 110562306a36Sopenharmony_ci } else { 110662306a36Sopenharmony_ci /* BB verify if wct == 15 */ 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/ 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci *netfid = pSMBr->Fid; /* cifs fid stays in le */ 111162306a36Sopenharmony_ci /* Let caller know file was created so we can set the mode. */ 111262306a36Sopenharmony_ci /* Do we care about the CreateAction in any other cases? */ 111362306a36Sopenharmony_ci /* BB FIXME BB */ 111462306a36Sopenharmony_ci/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) 111562306a36Sopenharmony_ci *pOplock |= CIFS_CREATE_ACTION; */ 111662306a36Sopenharmony_ci /* BB FIXME END */ 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci if (pfile_info) { 111962306a36Sopenharmony_ci pfile_info->CreationTime = 0; /* BB convert CreateTime*/ 112062306a36Sopenharmony_ci pfile_info->LastAccessTime = 0; /* BB fixme */ 112162306a36Sopenharmony_ci pfile_info->LastWriteTime = 0; /* BB fixme */ 112262306a36Sopenharmony_ci pfile_info->ChangeTime = 0; /* BB fixme */ 112362306a36Sopenharmony_ci pfile_info->Attributes = 112462306a36Sopenharmony_ci cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 112562306a36Sopenharmony_ci /* the file_info buf is endian converted by caller */ 112662306a36Sopenharmony_ci pfile_info->AllocationSize = 112762306a36Sopenharmony_ci cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile)); 112862306a36Sopenharmony_ci pfile_info->EndOfFile = pfile_info->AllocationSize; 112962306a36Sopenharmony_ci pfile_info->NumberOfLinks = cpu_to_le32(1); 113062306a36Sopenharmony_ci pfile_info->DeletePending = 0; 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci cifs_buf_release(pSMB); 113562306a36Sopenharmony_ci if (rc == -EAGAIN) 113662306a36Sopenharmony_ci goto OldOpenRetry; 113762306a36Sopenharmony_ci return rc; 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ciint 114162306a36Sopenharmony_ciCIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock, 114262306a36Sopenharmony_ci FILE_ALL_INFO *buf) 114362306a36Sopenharmony_ci{ 114462306a36Sopenharmony_ci int rc; 114562306a36Sopenharmony_ci OPEN_REQ *req = NULL; 114662306a36Sopenharmony_ci OPEN_RSP *rsp = NULL; 114762306a36Sopenharmony_ci int bytes_returned; 114862306a36Sopenharmony_ci int name_len; 114962306a36Sopenharmony_ci __u16 count; 115062306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = oparms->cifs_sb; 115162306a36Sopenharmony_ci struct cifs_tcon *tcon = oparms->tcon; 115262306a36Sopenharmony_ci int remap = cifs_remap(cifs_sb); 115362306a36Sopenharmony_ci const struct nls_table *nls = cifs_sb->local_nls; 115462306a36Sopenharmony_ci int create_options = oparms->create_options; 115562306a36Sopenharmony_ci int desired_access = oparms->desired_access; 115662306a36Sopenharmony_ci int disposition = oparms->disposition; 115762306a36Sopenharmony_ci const char *path = oparms->path; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ciopenRetry: 116062306a36Sopenharmony_ci rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req, 116162306a36Sopenharmony_ci (void **)&rsp); 116262306a36Sopenharmony_ci if (rc) 116362306a36Sopenharmony_ci return rc; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci /* no commands go after this */ 116662306a36Sopenharmony_ci req->AndXCommand = 0xFF; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (req->hdr.Flags2 & SMBFLG2_UNICODE) { 116962306a36Sopenharmony_ci /* account for one byte pad to word boundary */ 117062306a36Sopenharmony_ci count = 1; 117162306a36Sopenharmony_ci name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1), 117262306a36Sopenharmony_ci path, PATH_MAX, nls, remap); 117362306a36Sopenharmony_ci /* trailing null */ 117462306a36Sopenharmony_ci name_len++; 117562306a36Sopenharmony_ci name_len *= 2; 117662306a36Sopenharmony_ci req->NameLength = cpu_to_le16(name_len); 117762306a36Sopenharmony_ci } else { 117862306a36Sopenharmony_ci /* BB improve check for buffer overruns BB */ 117962306a36Sopenharmony_ci /* no pad */ 118062306a36Sopenharmony_ci count = 0; 118162306a36Sopenharmony_ci name_len = copy_path_name(req->fileName, path); 118262306a36Sopenharmony_ci req->NameLength = cpu_to_le16(name_len); 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (*oplock & REQ_OPLOCK) 118662306a36Sopenharmony_ci req->OpenFlags = cpu_to_le32(REQ_OPLOCK); 118762306a36Sopenharmony_ci else if (*oplock & REQ_BATCHOPLOCK) 118862306a36Sopenharmony_ci req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci req->DesiredAccess = cpu_to_le32(desired_access); 119162306a36Sopenharmony_ci req->AllocationSize = 0; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci /* 119462306a36Sopenharmony_ci * Set file as system file if special file such as fifo and server 119562306a36Sopenharmony_ci * expecting SFU style and no Unix extensions. 119662306a36Sopenharmony_ci */ 119762306a36Sopenharmony_ci if (create_options & CREATE_OPTION_SPECIAL) 119862306a36Sopenharmony_ci req->FileAttributes = cpu_to_le32(ATTR_SYSTEM); 119962306a36Sopenharmony_ci else 120062306a36Sopenharmony_ci req->FileAttributes = cpu_to_le32(ATTR_NORMAL); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* 120362306a36Sopenharmony_ci * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case 120462306a36Sopenharmony_ci * sensitive checks for other servers such as Samba. 120562306a36Sopenharmony_ci */ 120662306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_UNIX) 120762306a36Sopenharmony_ci req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci if (create_options & CREATE_OPTION_READONLY) 121062306a36Sopenharmony_ci req->FileAttributes |= cpu_to_le32(ATTR_READONLY); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); 121362306a36Sopenharmony_ci req->CreateDisposition = cpu_to_le32(disposition); 121462306a36Sopenharmony_ci req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci /* BB Expirement with various impersonation levels and verify */ 121762306a36Sopenharmony_ci req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); 121862306a36Sopenharmony_ci req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci count += name_len; 122162306a36Sopenharmony_ci inc_rfc1001_len(req, count); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci req->ByteCount = cpu_to_le16(count); 122462306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req, 122562306a36Sopenharmony_ci (struct smb_hdr *)rsp, &bytes_returned, 0); 122662306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_opens); 122762306a36Sopenharmony_ci if (rc) { 122862306a36Sopenharmony_ci cifs_dbg(FYI, "Error in Open = %d\n", rc); 122962306a36Sopenharmony_ci cifs_buf_release(req); 123062306a36Sopenharmony_ci if (rc == -EAGAIN) 123162306a36Sopenharmony_ci goto openRetry; 123262306a36Sopenharmony_ci return rc; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* 1 byte no need to le_to_cpu */ 123662306a36Sopenharmony_ci *oplock = rsp->OplockLevel; 123762306a36Sopenharmony_ci /* cifs fid stays in le */ 123862306a36Sopenharmony_ci oparms->fid->netfid = rsp->Fid; 123962306a36Sopenharmony_ci oparms->fid->access = desired_access; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci /* Let caller know file was created so we can set the mode. */ 124262306a36Sopenharmony_ci /* Do we care about the CreateAction in any other cases? */ 124362306a36Sopenharmony_ci if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction) 124462306a36Sopenharmony_ci *oplock |= CIFS_CREATE_ACTION; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci if (buf) { 124762306a36Sopenharmony_ci /* copy commonly used attributes */ 124862306a36Sopenharmony_ci memcpy(&buf->common_attributes, 124962306a36Sopenharmony_ci &rsp->common_attributes, 125062306a36Sopenharmony_ci sizeof(buf->common_attributes)); 125162306a36Sopenharmony_ci /* the file_info buf is endian converted by caller */ 125262306a36Sopenharmony_ci buf->AllocationSize = rsp->AllocationSize; 125362306a36Sopenharmony_ci buf->EndOfFile = rsp->EndOfFile; 125462306a36Sopenharmony_ci buf->NumberOfLinks = cpu_to_le32(1); 125562306a36Sopenharmony_ci buf->DeletePending = 0; 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci cifs_buf_release(req); 125962306a36Sopenharmony_ci return rc; 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cistatic void 126362306a36Sopenharmony_cicifs_readv_callback(struct mid_q_entry *mid) 126462306a36Sopenharmony_ci{ 126562306a36Sopenharmony_ci struct cifs_readdata *rdata = mid->callback_data; 126662306a36Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); 126762306a36Sopenharmony_ci struct TCP_Server_Info *server = tcon->ses->server; 126862306a36Sopenharmony_ci struct smb_rqst rqst = { .rq_iov = rdata->iov, 126962306a36Sopenharmony_ci .rq_nvec = 2, 127062306a36Sopenharmony_ci .rq_iter_size = iov_iter_count(&rdata->iter), 127162306a36Sopenharmony_ci .rq_iter = rdata->iter }; 127262306a36Sopenharmony_ci struct cifs_credits credits = { .value = 1, .instance = 0 }; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n", 127562306a36Sopenharmony_ci __func__, mid->mid, mid->mid_state, rdata->result, 127662306a36Sopenharmony_ci rdata->bytes); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci switch (mid->mid_state) { 127962306a36Sopenharmony_ci case MID_RESPONSE_RECEIVED: 128062306a36Sopenharmony_ci /* result already set, check signature */ 128162306a36Sopenharmony_ci if (server->sign) { 128262306a36Sopenharmony_ci int rc = 0; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci rc = cifs_verify_signature(&rqst, server, 128562306a36Sopenharmony_ci mid->sequence_number); 128662306a36Sopenharmony_ci if (rc) 128762306a36Sopenharmony_ci cifs_dbg(VFS, "SMB signature verification returned error = %d\n", 128862306a36Sopenharmony_ci rc); 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci /* FIXME: should this be counted toward the initiating task? */ 129162306a36Sopenharmony_ci task_io_account_read(rdata->got_bytes); 129262306a36Sopenharmony_ci cifs_stats_bytes_read(tcon, rdata->got_bytes); 129362306a36Sopenharmony_ci break; 129462306a36Sopenharmony_ci case MID_REQUEST_SUBMITTED: 129562306a36Sopenharmony_ci case MID_RETRY_NEEDED: 129662306a36Sopenharmony_ci rdata->result = -EAGAIN; 129762306a36Sopenharmony_ci if (server->sign && rdata->got_bytes) 129862306a36Sopenharmony_ci /* reset bytes number since we can not check a sign */ 129962306a36Sopenharmony_ci rdata->got_bytes = 0; 130062306a36Sopenharmony_ci /* FIXME: should this be counted toward the initiating task? */ 130162306a36Sopenharmony_ci task_io_account_read(rdata->got_bytes); 130262306a36Sopenharmony_ci cifs_stats_bytes_read(tcon, rdata->got_bytes); 130362306a36Sopenharmony_ci break; 130462306a36Sopenharmony_ci default: 130562306a36Sopenharmony_ci rdata->result = -EIO; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci queue_work(cifsiod_wq, &rdata->work); 130962306a36Sopenharmony_ci release_mid(mid); 131062306a36Sopenharmony_ci add_credits(server, &credits, 0); 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci/* cifs_async_readv - send an async write, and set up mid to handle result */ 131462306a36Sopenharmony_ciint 131562306a36Sopenharmony_cicifs_async_readv(struct cifs_readdata *rdata) 131662306a36Sopenharmony_ci{ 131762306a36Sopenharmony_ci int rc; 131862306a36Sopenharmony_ci READ_REQ *smb = NULL; 131962306a36Sopenharmony_ci int wct; 132062306a36Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); 132162306a36Sopenharmony_ci struct smb_rqst rqst = { .rq_iov = rdata->iov, 132262306a36Sopenharmony_ci .rq_nvec = 2 }; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", 132562306a36Sopenharmony_ci __func__, rdata->offset, rdata->bytes); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_LARGE_FILES) 132862306a36Sopenharmony_ci wct = 12; 132962306a36Sopenharmony_ci else { 133062306a36Sopenharmony_ci wct = 10; /* old style read */ 133162306a36Sopenharmony_ci if ((rdata->offset >> 32) > 0) { 133262306a36Sopenharmony_ci /* can not handle this big offset for old */ 133362306a36Sopenharmony_ci return -EIO; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb); 133862306a36Sopenharmony_ci if (rc) 133962306a36Sopenharmony_ci return rc; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid); 134262306a36Sopenharmony_ci smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16)); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci smb->AndXCommand = 0xFF; /* none */ 134562306a36Sopenharmony_ci smb->Fid = rdata->cfile->fid.netfid; 134662306a36Sopenharmony_ci smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF); 134762306a36Sopenharmony_ci if (wct == 12) 134862306a36Sopenharmony_ci smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32); 134962306a36Sopenharmony_ci smb->Remaining = 0; 135062306a36Sopenharmony_ci smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF); 135162306a36Sopenharmony_ci smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16); 135262306a36Sopenharmony_ci if (wct == 12) 135362306a36Sopenharmony_ci smb->ByteCount = 0; 135462306a36Sopenharmony_ci else { 135562306a36Sopenharmony_ci /* old style read */ 135662306a36Sopenharmony_ci struct smb_com_readx_req *smbr = 135762306a36Sopenharmony_ci (struct smb_com_readx_req *)smb; 135862306a36Sopenharmony_ci smbr->ByteCount = 0; 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci /* 4 for RFC1001 length + 1 for BCC */ 136262306a36Sopenharmony_ci rdata->iov[0].iov_base = smb; 136362306a36Sopenharmony_ci rdata->iov[0].iov_len = 4; 136462306a36Sopenharmony_ci rdata->iov[1].iov_base = (char *)smb + 4; 136562306a36Sopenharmony_ci rdata->iov[1].iov_len = get_rfc1002_length(smb); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci kref_get(&rdata->refcount); 136862306a36Sopenharmony_ci rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive, 136962306a36Sopenharmony_ci cifs_readv_callback, NULL, rdata, 0, NULL); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci if (rc == 0) 137262306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); 137362306a36Sopenharmony_ci else 137462306a36Sopenharmony_ci kref_put(&rdata->refcount, cifs_readdata_release); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci cifs_small_buf_release(smb); 137762306a36Sopenharmony_ci return rc; 137862306a36Sopenharmony_ci} 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ciint 138162306a36Sopenharmony_ciCIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms, 138262306a36Sopenharmony_ci unsigned int *nbytes, char **buf, int *pbuf_type) 138362306a36Sopenharmony_ci{ 138462306a36Sopenharmony_ci int rc = -EACCES; 138562306a36Sopenharmony_ci READ_REQ *pSMB = NULL; 138662306a36Sopenharmony_ci READ_RSP *pSMBr = NULL; 138762306a36Sopenharmony_ci char *pReadData = NULL; 138862306a36Sopenharmony_ci int wct; 138962306a36Sopenharmony_ci int resp_buf_type = 0; 139062306a36Sopenharmony_ci struct kvec iov[1]; 139162306a36Sopenharmony_ci struct kvec rsp_iov; 139262306a36Sopenharmony_ci __u32 pid = io_parms->pid; 139362306a36Sopenharmony_ci __u16 netfid = io_parms->netfid; 139462306a36Sopenharmony_ci __u64 offset = io_parms->offset; 139562306a36Sopenharmony_ci struct cifs_tcon *tcon = io_parms->tcon; 139662306a36Sopenharmony_ci unsigned int count = io_parms->length; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid); 139962306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_LARGE_FILES) 140062306a36Sopenharmony_ci wct = 12; 140162306a36Sopenharmony_ci else { 140262306a36Sopenharmony_ci wct = 10; /* old style read */ 140362306a36Sopenharmony_ci if ((offset >> 32) > 0) { 140462306a36Sopenharmony_ci /* can not handle this big offset for old */ 140562306a36Sopenharmony_ci return -EIO; 140662306a36Sopenharmony_ci } 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci *nbytes = 0; 141062306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB); 141162306a36Sopenharmony_ci if (rc) 141262306a36Sopenharmony_ci return rc; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci pSMB->hdr.Pid = cpu_to_le16((__u16)pid); 141562306a36Sopenharmony_ci pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci /* tcon and ses pointer are checked in smb_init */ 141862306a36Sopenharmony_ci if (tcon->ses->server == NULL) 141962306a36Sopenharmony_ci return -ECONNABORTED; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci pSMB->AndXCommand = 0xFF; /* none */ 142262306a36Sopenharmony_ci pSMB->Fid = netfid; 142362306a36Sopenharmony_ci pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); 142462306a36Sopenharmony_ci if (wct == 12) 142562306a36Sopenharmony_ci pSMB->OffsetHigh = cpu_to_le32(offset >> 32); 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci pSMB->Remaining = 0; 142862306a36Sopenharmony_ci pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); 142962306a36Sopenharmony_ci pSMB->MaxCountHigh = cpu_to_le32(count >> 16); 143062306a36Sopenharmony_ci if (wct == 12) 143162306a36Sopenharmony_ci pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ 143262306a36Sopenharmony_ci else { 143362306a36Sopenharmony_ci /* old style read */ 143462306a36Sopenharmony_ci struct smb_com_readx_req *pSMBW = 143562306a36Sopenharmony_ci (struct smb_com_readx_req *)pSMB; 143662306a36Sopenharmony_ci pSMBW->ByteCount = 0; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci iov[0].iov_base = (char *)pSMB; 144062306a36Sopenharmony_ci iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; 144162306a36Sopenharmony_ci rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type, 144262306a36Sopenharmony_ci CIFS_LOG_ERROR, &rsp_iov); 144362306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 144462306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); 144562306a36Sopenharmony_ci pSMBr = (READ_RSP *)rsp_iov.iov_base; 144662306a36Sopenharmony_ci if (rc) { 144762306a36Sopenharmony_ci cifs_dbg(VFS, "Send error in read = %d\n", rc); 144862306a36Sopenharmony_ci } else { 144962306a36Sopenharmony_ci int data_length = le16_to_cpu(pSMBr->DataLengthHigh); 145062306a36Sopenharmony_ci data_length = data_length << 16; 145162306a36Sopenharmony_ci data_length += le16_to_cpu(pSMBr->DataLength); 145262306a36Sopenharmony_ci *nbytes = data_length; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci /*check that DataLength would not go beyond end of SMB */ 145562306a36Sopenharmony_ci if ((data_length > CIFSMaxBufSize) 145662306a36Sopenharmony_ci || (data_length > count)) { 145762306a36Sopenharmony_ci cifs_dbg(FYI, "bad length %d for count %d\n", 145862306a36Sopenharmony_ci data_length, count); 145962306a36Sopenharmony_ci rc = -EIO; 146062306a36Sopenharmony_ci *nbytes = 0; 146162306a36Sopenharmony_ci } else { 146262306a36Sopenharmony_ci pReadData = (char *) (&pSMBr->hdr.Protocol) + 146362306a36Sopenharmony_ci le16_to_cpu(pSMBr->DataOffset); 146462306a36Sopenharmony_ci/* if (rc = copy_to_user(buf, pReadData, data_length)) { 146562306a36Sopenharmony_ci cifs_dbg(VFS, "Faulting on read rc = %d\n",rc); 146662306a36Sopenharmony_ci rc = -EFAULT; 146762306a36Sopenharmony_ci }*/ /* can not use copy_to_user when using page cache*/ 146862306a36Sopenharmony_ci if (*buf) 146962306a36Sopenharmony_ci memcpy(*buf, pReadData, data_length); 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci if (*buf) { 147462306a36Sopenharmony_ci free_rsp_buf(resp_buf_type, rsp_iov.iov_base); 147562306a36Sopenharmony_ci } else if (resp_buf_type != CIFS_NO_BUFFER) { 147662306a36Sopenharmony_ci /* return buffer to caller to free */ 147762306a36Sopenharmony_ci *buf = rsp_iov.iov_base; 147862306a36Sopenharmony_ci if (resp_buf_type == CIFS_SMALL_BUFFER) 147962306a36Sopenharmony_ci *pbuf_type = CIFS_SMALL_BUFFER; 148062306a36Sopenharmony_ci else if (resp_buf_type == CIFS_LARGE_BUFFER) 148162306a36Sopenharmony_ci *pbuf_type = CIFS_LARGE_BUFFER; 148262306a36Sopenharmony_ci } /* else no valid buffer on return - leave as null */ 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci /* Note: On -EAGAIN error only caller can retry on handle based calls 148562306a36Sopenharmony_ci since file handle passed in no longer valid */ 148662306a36Sopenharmony_ci return rc; 148762306a36Sopenharmony_ci} 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ciint 149162306a36Sopenharmony_ciCIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, 149262306a36Sopenharmony_ci unsigned int *nbytes, const char *buf) 149362306a36Sopenharmony_ci{ 149462306a36Sopenharmony_ci int rc = -EACCES; 149562306a36Sopenharmony_ci WRITE_REQ *pSMB = NULL; 149662306a36Sopenharmony_ci WRITE_RSP *pSMBr = NULL; 149762306a36Sopenharmony_ci int bytes_returned, wct; 149862306a36Sopenharmony_ci __u32 bytes_sent; 149962306a36Sopenharmony_ci __u16 byte_count; 150062306a36Sopenharmony_ci __u32 pid = io_parms->pid; 150162306a36Sopenharmony_ci __u16 netfid = io_parms->netfid; 150262306a36Sopenharmony_ci __u64 offset = io_parms->offset; 150362306a36Sopenharmony_ci struct cifs_tcon *tcon = io_parms->tcon; 150462306a36Sopenharmony_ci unsigned int count = io_parms->length; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci *nbytes = 0; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/ 150962306a36Sopenharmony_ci if (tcon->ses == NULL) 151062306a36Sopenharmony_ci return -ECONNABORTED; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_LARGE_FILES) 151362306a36Sopenharmony_ci wct = 14; 151462306a36Sopenharmony_ci else { 151562306a36Sopenharmony_ci wct = 12; 151662306a36Sopenharmony_ci if ((offset >> 32) > 0) { 151762306a36Sopenharmony_ci /* can not handle big offset for old srv */ 151862306a36Sopenharmony_ci return -EIO; 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB, 152362306a36Sopenharmony_ci (void **) &pSMBr); 152462306a36Sopenharmony_ci if (rc) 152562306a36Sopenharmony_ci return rc; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci pSMB->hdr.Pid = cpu_to_le16((__u16)pid); 152862306a36Sopenharmony_ci pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci /* tcon and ses pointer are checked in smb_init */ 153162306a36Sopenharmony_ci if (tcon->ses->server == NULL) 153262306a36Sopenharmony_ci return -ECONNABORTED; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci pSMB->AndXCommand = 0xFF; /* none */ 153562306a36Sopenharmony_ci pSMB->Fid = netfid; 153662306a36Sopenharmony_ci pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); 153762306a36Sopenharmony_ci if (wct == 14) 153862306a36Sopenharmony_ci pSMB->OffsetHigh = cpu_to_le32(offset >> 32); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci pSMB->Reserved = 0xFFFFFFFF; 154162306a36Sopenharmony_ci pSMB->WriteMode = 0; 154262306a36Sopenharmony_ci pSMB->Remaining = 0; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci /* Can increase buffer size if buffer is big enough in some cases ie we 154562306a36Sopenharmony_ci can send more if LARGE_WRITE_X capability returned by the server and if 154662306a36Sopenharmony_ci our buffer is big enough or if we convert to iovecs on socket writes 154762306a36Sopenharmony_ci and eliminate the copy to the CIFS buffer */ 154862306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) { 154962306a36Sopenharmony_ci bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count); 155062306a36Sopenharmony_ci } else { 155162306a36Sopenharmony_ci bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) 155262306a36Sopenharmony_ci & ~0xFF; 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci if (bytes_sent > count) 155662306a36Sopenharmony_ci bytes_sent = count; 155762306a36Sopenharmony_ci pSMB->DataOffset = 155862306a36Sopenharmony_ci cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); 155962306a36Sopenharmony_ci if (buf) 156062306a36Sopenharmony_ci memcpy(pSMB->Data, buf, bytes_sent); 156162306a36Sopenharmony_ci else if (count != 0) { 156262306a36Sopenharmony_ci /* No buffer */ 156362306a36Sopenharmony_ci cifs_buf_release(pSMB); 156462306a36Sopenharmony_ci return -EINVAL; 156562306a36Sopenharmony_ci } /* else setting file size with write of zero bytes */ 156662306a36Sopenharmony_ci if (wct == 14) 156762306a36Sopenharmony_ci byte_count = bytes_sent + 1; /* pad */ 156862306a36Sopenharmony_ci else /* wct == 12 */ 156962306a36Sopenharmony_ci byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */ 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); 157262306a36Sopenharmony_ci pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); 157362306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci if (wct == 14) 157662306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 157762306a36Sopenharmony_ci else { /* old style write has byte count 4 bytes earlier 157862306a36Sopenharmony_ci so 4 bytes pad */ 157962306a36Sopenharmony_ci struct smb_com_writex_req *pSMBW = 158062306a36Sopenharmony_ci (struct smb_com_writex_req *)pSMB; 158162306a36Sopenharmony_ci pSMBW->ByteCount = cpu_to_le16(byte_count); 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 158562306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 158662306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); 158762306a36Sopenharmony_ci if (rc) { 158862306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in write = %d\n", rc); 158962306a36Sopenharmony_ci } else { 159062306a36Sopenharmony_ci *nbytes = le16_to_cpu(pSMBr->CountHigh); 159162306a36Sopenharmony_ci *nbytes = (*nbytes) << 16; 159262306a36Sopenharmony_ci *nbytes += le16_to_cpu(pSMBr->Count); 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci /* 159562306a36Sopenharmony_ci * Mask off high 16 bits when bytes written as returned by the 159662306a36Sopenharmony_ci * server is greater than bytes requested by the client. Some 159762306a36Sopenharmony_ci * OS/2 servers are known to set incorrect CountHigh values. 159862306a36Sopenharmony_ci */ 159962306a36Sopenharmony_ci if (*nbytes > count) 160062306a36Sopenharmony_ci *nbytes &= 0xFFFF; 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci cifs_buf_release(pSMB); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci /* Note: On -EAGAIN error only caller can retry on handle based calls 160662306a36Sopenharmony_ci since file handle passed in no longer valid */ 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci return rc; 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci/* 161262306a36Sopenharmony_ci * Check the mid_state and signature on received buffer (if any), and queue the 161362306a36Sopenharmony_ci * workqueue completion task. 161462306a36Sopenharmony_ci */ 161562306a36Sopenharmony_cistatic void 161662306a36Sopenharmony_cicifs_writev_callback(struct mid_q_entry *mid) 161762306a36Sopenharmony_ci{ 161862306a36Sopenharmony_ci struct cifs_writedata *wdata = mid->callback_data; 161962306a36Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); 162062306a36Sopenharmony_ci unsigned int written; 162162306a36Sopenharmony_ci WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf; 162262306a36Sopenharmony_ci struct cifs_credits credits = { .value = 1, .instance = 0 }; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci switch (mid->mid_state) { 162562306a36Sopenharmony_ci case MID_RESPONSE_RECEIVED: 162662306a36Sopenharmony_ci wdata->result = cifs_check_receive(mid, tcon->ses->server, 0); 162762306a36Sopenharmony_ci if (wdata->result != 0) 162862306a36Sopenharmony_ci break; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci written = le16_to_cpu(smb->CountHigh); 163162306a36Sopenharmony_ci written <<= 16; 163262306a36Sopenharmony_ci written += le16_to_cpu(smb->Count); 163362306a36Sopenharmony_ci /* 163462306a36Sopenharmony_ci * Mask off high 16 bits when bytes written as returned 163562306a36Sopenharmony_ci * by the server is greater than bytes requested by the 163662306a36Sopenharmony_ci * client. OS/2 servers are known to set incorrect 163762306a36Sopenharmony_ci * CountHigh values. 163862306a36Sopenharmony_ci */ 163962306a36Sopenharmony_ci if (written > wdata->bytes) 164062306a36Sopenharmony_ci written &= 0xFFFF; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci if (written < wdata->bytes) 164362306a36Sopenharmony_ci wdata->result = -ENOSPC; 164462306a36Sopenharmony_ci else 164562306a36Sopenharmony_ci wdata->bytes = written; 164662306a36Sopenharmony_ci break; 164762306a36Sopenharmony_ci case MID_REQUEST_SUBMITTED: 164862306a36Sopenharmony_ci case MID_RETRY_NEEDED: 164962306a36Sopenharmony_ci wdata->result = -EAGAIN; 165062306a36Sopenharmony_ci break; 165162306a36Sopenharmony_ci default: 165262306a36Sopenharmony_ci wdata->result = -EIO; 165362306a36Sopenharmony_ci break; 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci queue_work(cifsiod_wq, &wdata->work); 165762306a36Sopenharmony_ci release_mid(mid); 165862306a36Sopenharmony_ci add_credits(tcon->ses->server, &credits, 0); 165962306a36Sopenharmony_ci} 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci/* cifs_async_writev - send an async write, and set up mid to handle result */ 166262306a36Sopenharmony_ciint 166362306a36Sopenharmony_cicifs_async_writev(struct cifs_writedata *wdata, 166462306a36Sopenharmony_ci void (*release)(struct kref *kref)) 166562306a36Sopenharmony_ci{ 166662306a36Sopenharmony_ci int rc = -EACCES; 166762306a36Sopenharmony_ci WRITE_REQ *smb = NULL; 166862306a36Sopenharmony_ci int wct; 166962306a36Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); 167062306a36Sopenharmony_ci struct kvec iov[2]; 167162306a36Sopenharmony_ci struct smb_rqst rqst = { }; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_LARGE_FILES) { 167462306a36Sopenharmony_ci wct = 14; 167562306a36Sopenharmony_ci } else { 167662306a36Sopenharmony_ci wct = 12; 167762306a36Sopenharmony_ci if (wdata->offset >> 32 > 0) { 167862306a36Sopenharmony_ci /* can not handle big offset for old srv */ 167962306a36Sopenharmony_ci return -EIO; 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb); 168462306a36Sopenharmony_ci if (rc) 168562306a36Sopenharmony_ci goto async_writev_out; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid); 168862306a36Sopenharmony_ci smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16)); 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci smb->AndXCommand = 0xFF; /* none */ 169162306a36Sopenharmony_ci smb->Fid = wdata->cfile->fid.netfid; 169262306a36Sopenharmony_ci smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF); 169362306a36Sopenharmony_ci if (wct == 14) 169462306a36Sopenharmony_ci smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32); 169562306a36Sopenharmony_ci smb->Reserved = 0xFFFFFFFF; 169662306a36Sopenharmony_ci smb->WriteMode = 0; 169762306a36Sopenharmony_ci smb->Remaining = 0; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci smb->DataOffset = 170062306a36Sopenharmony_ci cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci /* 4 for RFC1001 length + 1 for BCC */ 170362306a36Sopenharmony_ci iov[0].iov_len = 4; 170462306a36Sopenharmony_ci iov[0].iov_base = smb; 170562306a36Sopenharmony_ci iov[1].iov_len = get_rfc1002_length(smb) + 1; 170662306a36Sopenharmony_ci iov[1].iov_base = (char *)smb + 4; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci rqst.rq_iov = iov; 170962306a36Sopenharmony_ci rqst.rq_nvec = 2; 171062306a36Sopenharmony_ci rqst.rq_iter = wdata->iter; 171162306a36Sopenharmony_ci rqst.rq_iter_size = iov_iter_count(&wdata->iter); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci cifs_dbg(FYI, "async write at %llu %u bytes\n", 171462306a36Sopenharmony_ci wdata->offset, wdata->bytes); 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF); 171762306a36Sopenharmony_ci smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16); 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci if (wct == 14) { 172062306a36Sopenharmony_ci inc_rfc1001_len(&smb->hdr, wdata->bytes + 1); 172162306a36Sopenharmony_ci put_bcc(wdata->bytes + 1, &smb->hdr); 172262306a36Sopenharmony_ci } else { 172362306a36Sopenharmony_ci /* wct == 12 */ 172462306a36Sopenharmony_ci struct smb_com_writex_req *smbw = 172562306a36Sopenharmony_ci (struct smb_com_writex_req *)smb; 172662306a36Sopenharmony_ci inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5); 172762306a36Sopenharmony_ci put_bcc(wdata->bytes + 5, &smbw->hdr); 172862306a36Sopenharmony_ci iov[1].iov_len += 4; /* pad bigger by four bytes */ 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci kref_get(&wdata->refcount); 173262306a36Sopenharmony_ci rc = cifs_call_async(tcon->ses->server, &rqst, NULL, 173362306a36Sopenharmony_ci cifs_writev_callback, NULL, wdata, 0, NULL); 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci if (rc == 0) 173662306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); 173762306a36Sopenharmony_ci else 173862306a36Sopenharmony_ci kref_put(&wdata->refcount, release); 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ciasync_writev_out: 174162306a36Sopenharmony_ci cifs_small_buf_release(smb); 174262306a36Sopenharmony_ci return rc; 174362306a36Sopenharmony_ci} 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ciint 174662306a36Sopenharmony_ciCIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms, 174762306a36Sopenharmony_ci unsigned int *nbytes, struct kvec *iov, int n_vec) 174862306a36Sopenharmony_ci{ 174962306a36Sopenharmony_ci int rc; 175062306a36Sopenharmony_ci WRITE_REQ *pSMB = NULL; 175162306a36Sopenharmony_ci int wct; 175262306a36Sopenharmony_ci int smb_hdr_len; 175362306a36Sopenharmony_ci int resp_buf_type = 0; 175462306a36Sopenharmony_ci __u32 pid = io_parms->pid; 175562306a36Sopenharmony_ci __u16 netfid = io_parms->netfid; 175662306a36Sopenharmony_ci __u64 offset = io_parms->offset; 175762306a36Sopenharmony_ci struct cifs_tcon *tcon = io_parms->tcon; 175862306a36Sopenharmony_ci unsigned int count = io_parms->length; 175962306a36Sopenharmony_ci struct kvec rsp_iov; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci *nbytes = 0; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_LARGE_FILES) { 176662306a36Sopenharmony_ci wct = 14; 176762306a36Sopenharmony_ci } else { 176862306a36Sopenharmony_ci wct = 12; 176962306a36Sopenharmony_ci if ((offset >> 32) > 0) { 177062306a36Sopenharmony_ci /* can not handle big offset for old srv */ 177162306a36Sopenharmony_ci return -EIO; 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci } 177462306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB); 177562306a36Sopenharmony_ci if (rc) 177662306a36Sopenharmony_ci return rc; 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci pSMB->hdr.Pid = cpu_to_le16((__u16)pid); 177962306a36Sopenharmony_ci pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci /* tcon and ses pointer are checked in smb_init */ 178262306a36Sopenharmony_ci if (tcon->ses->server == NULL) 178362306a36Sopenharmony_ci return -ECONNABORTED; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci pSMB->AndXCommand = 0xFF; /* none */ 178662306a36Sopenharmony_ci pSMB->Fid = netfid; 178762306a36Sopenharmony_ci pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); 178862306a36Sopenharmony_ci if (wct == 14) 178962306a36Sopenharmony_ci pSMB->OffsetHigh = cpu_to_le32(offset >> 32); 179062306a36Sopenharmony_ci pSMB->Reserved = 0xFFFFFFFF; 179162306a36Sopenharmony_ci pSMB->WriteMode = 0; 179262306a36Sopenharmony_ci pSMB->Remaining = 0; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci pSMB->DataOffset = 179562306a36Sopenharmony_ci cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); 179862306a36Sopenharmony_ci pSMB->DataLengthHigh = cpu_to_le16(count >> 16); 179962306a36Sopenharmony_ci /* header + 1 byte pad */ 180062306a36Sopenharmony_ci smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1; 180162306a36Sopenharmony_ci if (wct == 14) 180262306a36Sopenharmony_ci inc_rfc1001_len(pSMB, count + 1); 180362306a36Sopenharmony_ci else /* wct == 12 */ 180462306a36Sopenharmony_ci inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */ 180562306a36Sopenharmony_ci if (wct == 14) 180662306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(count + 1); 180762306a36Sopenharmony_ci else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ { 180862306a36Sopenharmony_ci struct smb_com_writex_req *pSMBW = 180962306a36Sopenharmony_ci (struct smb_com_writex_req *)pSMB; 181062306a36Sopenharmony_ci pSMBW->ByteCount = cpu_to_le16(count + 5); 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci iov[0].iov_base = pSMB; 181362306a36Sopenharmony_ci if (wct == 14) 181462306a36Sopenharmony_ci iov[0].iov_len = smb_hdr_len + 4; 181562306a36Sopenharmony_ci else /* wct == 12 pad bigger by four bytes */ 181662306a36Sopenharmony_ci iov[0].iov_len = smb_hdr_len + 8; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0, 181962306a36Sopenharmony_ci &rsp_iov); 182062306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 182162306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); 182262306a36Sopenharmony_ci if (rc) { 182362306a36Sopenharmony_ci cifs_dbg(FYI, "Send error Write2 = %d\n", rc); 182462306a36Sopenharmony_ci } else if (resp_buf_type == 0) { 182562306a36Sopenharmony_ci /* presumably this can not happen, but best to be safe */ 182662306a36Sopenharmony_ci rc = -EIO; 182762306a36Sopenharmony_ci } else { 182862306a36Sopenharmony_ci WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base; 182962306a36Sopenharmony_ci *nbytes = le16_to_cpu(pSMBr->CountHigh); 183062306a36Sopenharmony_ci *nbytes = (*nbytes) << 16; 183162306a36Sopenharmony_ci *nbytes += le16_to_cpu(pSMBr->Count); 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci /* 183462306a36Sopenharmony_ci * Mask off high 16 bits when bytes written as returned by the 183562306a36Sopenharmony_ci * server is greater than bytes requested by the client. OS/2 183662306a36Sopenharmony_ci * servers are known to set incorrect CountHigh values. 183762306a36Sopenharmony_ci */ 183862306a36Sopenharmony_ci if (*nbytes > count) 183962306a36Sopenharmony_ci *nbytes &= 0xFFFF; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci free_rsp_buf(resp_buf_type, rsp_iov.iov_base); 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci /* Note: On -EAGAIN error only caller can retry on handle based calls 184562306a36Sopenharmony_ci since file handle passed in no longer valid */ 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci return rc; 184862306a36Sopenharmony_ci} 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ciint cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon, 185162306a36Sopenharmony_ci const __u16 netfid, const __u8 lock_type, const __u32 num_unlock, 185262306a36Sopenharmony_ci const __u32 num_lock, LOCKING_ANDX_RANGE *buf) 185362306a36Sopenharmony_ci{ 185462306a36Sopenharmony_ci int rc = 0; 185562306a36Sopenharmony_ci LOCK_REQ *pSMB = NULL; 185662306a36Sopenharmony_ci struct kvec iov[2]; 185762306a36Sopenharmony_ci struct kvec rsp_iov; 185862306a36Sopenharmony_ci int resp_buf_type; 185962306a36Sopenharmony_ci __u16 count; 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n", 186262306a36Sopenharmony_ci num_lock, num_unlock); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); 186562306a36Sopenharmony_ci if (rc) 186662306a36Sopenharmony_ci return rc; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci pSMB->Timeout = 0; 186962306a36Sopenharmony_ci pSMB->NumberOfLocks = cpu_to_le16(num_lock); 187062306a36Sopenharmony_ci pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock); 187162306a36Sopenharmony_ci pSMB->LockType = lock_type; 187262306a36Sopenharmony_ci pSMB->AndXCommand = 0xFF; /* none */ 187362306a36Sopenharmony_ci pSMB->Fid = netfid; /* netfid stays le */ 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); 187662306a36Sopenharmony_ci inc_rfc1001_len(pSMB, count); 187762306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(count); 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci iov[0].iov_base = (char *)pSMB; 188062306a36Sopenharmony_ci iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 - 188162306a36Sopenharmony_ci (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); 188262306a36Sopenharmony_ci iov[1].iov_base = (char *)buf; 188362306a36Sopenharmony_ci iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_locks); 188662306a36Sopenharmony_ci rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, 188762306a36Sopenharmony_ci CIFS_NO_RSP_BUF, &rsp_iov); 188862306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 188962306a36Sopenharmony_ci if (rc) 189062306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci return rc; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ciint 189662306a36Sopenharmony_ciCIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon, 189762306a36Sopenharmony_ci const __u16 smb_file_id, const __u32 netpid, const __u64 len, 189862306a36Sopenharmony_ci const __u64 offset, const __u32 numUnlock, 189962306a36Sopenharmony_ci const __u32 numLock, const __u8 lockType, 190062306a36Sopenharmony_ci const bool waitFlag, const __u8 oplock_level) 190162306a36Sopenharmony_ci{ 190262306a36Sopenharmony_ci int rc = 0; 190362306a36Sopenharmony_ci LOCK_REQ *pSMB = NULL; 190462306a36Sopenharmony_ci/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */ 190562306a36Sopenharmony_ci int bytes_returned; 190662306a36Sopenharmony_ci int flags = 0; 190762306a36Sopenharmony_ci __u16 count; 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n", 191062306a36Sopenharmony_ci (int)waitFlag, numLock); 191162306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci if (rc) 191462306a36Sopenharmony_ci return rc; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) { 191762306a36Sopenharmony_ci /* no response expected */ 191862306a36Sopenharmony_ci flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP; 191962306a36Sopenharmony_ci pSMB->Timeout = 0; 192062306a36Sopenharmony_ci } else if (waitFlag) { 192162306a36Sopenharmony_ci flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ 192262306a36Sopenharmony_ci pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */ 192362306a36Sopenharmony_ci } else { 192462306a36Sopenharmony_ci pSMB->Timeout = 0; 192562306a36Sopenharmony_ci } 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci pSMB->NumberOfLocks = cpu_to_le16(numLock); 192862306a36Sopenharmony_ci pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); 192962306a36Sopenharmony_ci pSMB->LockType = lockType; 193062306a36Sopenharmony_ci pSMB->OplockLevel = oplock_level; 193162306a36Sopenharmony_ci pSMB->AndXCommand = 0xFF; /* none */ 193262306a36Sopenharmony_ci pSMB->Fid = smb_file_id; /* netfid stays le */ 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci if ((numLock != 0) || (numUnlock != 0)) { 193562306a36Sopenharmony_ci pSMB->Locks[0].Pid = cpu_to_le16(netpid); 193662306a36Sopenharmony_ci /* BB where to store pid high? */ 193762306a36Sopenharmony_ci pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len); 193862306a36Sopenharmony_ci pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32)); 193962306a36Sopenharmony_ci pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset); 194062306a36Sopenharmony_ci pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32)); 194162306a36Sopenharmony_ci count = sizeof(LOCKING_ANDX_RANGE); 194262306a36Sopenharmony_ci } else { 194362306a36Sopenharmony_ci /* oplock break */ 194462306a36Sopenharmony_ci count = 0; 194562306a36Sopenharmony_ci } 194662306a36Sopenharmony_ci inc_rfc1001_len(pSMB, count); 194762306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(count); 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci if (waitFlag) 195062306a36Sopenharmony_ci rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, 195162306a36Sopenharmony_ci (struct smb_hdr *) pSMB, &bytes_returned); 195262306a36Sopenharmony_ci else 195362306a36Sopenharmony_ci rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags); 195462306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 195562306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_locks); 195662306a36Sopenharmony_ci if (rc) 195762306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in Lock = %d\n", rc); 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci /* Note: On -EAGAIN error only caller can retry on handle based calls 196062306a36Sopenharmony_ci since file handle passed in no longer valid */ 196162306a36Sopenharmony_ci return rc; 196262306a36Sopenharmony_ci} 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ciint 196562306a36Sopenharmony_ciCIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, 196662306a36Sopenharmony_ci const __u16 smb_file_id, const __u32 netpid, 196762306a36Sopenharmony_ci const loff_t start_offset, const __u64 len, 196862306a36Sopenharmony_ci struct file_lock *pLockData, const __u16 lock_type, 196962306a36Sopenharmony_ci const bool waitFlag) 197062306a36Sopenharmony_ci{ 197162306a36Sopenharmony_ci struct smb_com_transaction2_sfi_req *pSMB = NULL; 197262306a36Sopenharmony_ci struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; 197362306a36Sopenharmony_ci struct cifs_posix_lock *parm_data; 197462306a36Sopenharmony_ci int rc = 0; 197562306a36Sopenharmony_ci int timeout = 0; 197662306a36Sopenharmony_ci int bytes_returned = 0; 197762306a36Sopenharmony_ci int resp_buf_type = 0; 197862306a36Sopenharmony_ci __u16 params, param_offset, offset, byte_count, count; 197962306a36Sopenharmony_ci struct kvec iov[1]; 198062306a36Sopenharmony_ci struct kvec rsp_iov; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci cifs_dbg(FYI, "Posix Lock\n"); 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci if (rc) 198762306a36Sopenharmony_ci return rc; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci params = 6; 199262306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 199362306a36Sopenharmony_ci pSMB->Reserved = 0; 199462306a36Sopenharmony_ci pSMB->Flags = 0; 199562306a36Sopenharmony_ci pSMB->Reserved2 = 0; 199662306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; 199762306a36Sopenharmony_ci offset = param_offset + params; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci count = sizeof(struct cifs_posix_lock); 200062306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 200162306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */ 200262306a36Sopenharmony_ci pSMB->SetupCount = 1; 200362306a36Sopenharmony_ci pSMB->Reserved3 = 0; 200462306a36Sopenharmony_ci if (pLockData) 200562306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); 200662306a36Sopenharmony_ci else 200762306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); 200862306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + count; 200962306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(count); 201062306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 201162306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 201262306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 201362306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 201462306a36Sopenharmony_ci /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ 201562306a36Sopenharmony_ci parm_data = (struct cifs_posix_lock *) 201662306a36Sopenharmony_ci (((char *)pSMB) + offset + 4); 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci parm_data->lock_type = cpu_to_le16(lock_type); 201962306a36Sopenharmony_ci if (waitFlag) { 202062306a36Sopenharmony_ci timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ 202162306a36Sopenharmony_ci parm_data->lock_flags = cpu_to_le16(1); 202262306a36Sopenharmony_ci pSMB->Timeout = cpu_to_le32(-1); 202362306a36Sopenharmony_ci } else 202462306a36Sopenharmony_ci pSMB->Timeout = 0; 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci parm_data->pid = cpu_to_le32(netpid); 202762306a36Sopenharmony_ci parm_data->start = cpu_to_le64(start_offset); 202862306a36Sopenharmony_ci parm_data->length = cpu_to_le64(len); /* normalize negative numbers */ 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 203162306a36Sopenharmony_ci pSMB->Fid = smb_file_id; 203262306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK); 203362306a36Sopenharmony_ci pSMB->Reserved4 = 0; 203462306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 203562306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 203662306a36Sopenharmony_ci if (waitFlag) { 203762306a36Sopenharmony_ci rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, 203862306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned); 203962306a36Sopenharmony_ci } else { 204062306a36Sopenharmony_ci iov[0].iov_base = (char *)pSMB; 204162306a36Sopenharmony_ci iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; 204262306a36Sopenharmony_ci rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, 204362306a36Sopenharmony_ci &resp_buf_type, timeout, &rsp_iov); 204462306a36Sopenharmony_ci pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base; 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci if (rc) { 204962306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc); 205062306a36Sopenharmony_ci } else if (pLockData) { 205162306a36Sopenharmony_ci /* lock structure can be returned on get */ 205262306a36Sopenharmony_ci __u16 data_offset; 205362306a36Sopenharmony_ci __u16 data_count; 205462306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) { 205762306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 205862306a36Sopenharmony_ci goto plk_err_exit; 205962306a36Sopenharmony_ci } 206062306a36Sopenharmony_ci data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 206162306a36Sopenharmony_ci data_count = le16_to_cpu(pSMBr->t2.DataCount); 206262306a36Sopenharmony_ci if (data_count < sizeof(struct cifs_posix_lock)) { 206362306a36Sopenharmony_ci rc = -EIO; 206462306a36Sopenharmony_ci goto plk_err_exit; 206562306a36Sopenharmony_ci } 206662306a36Sopenharmony_ci parm_data = (struct cifs_posix_lock *) 206762306a36Sopenharmony_ci ((char *)&pSMBr->hdr.Protocol + data_offset); 206862306a36Sopenharmony_ci if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK)) 206962306a36Sopenharmony_ci pLockData->fl_type = F_UNLCK; 207062306a36Sopenharmony_ci else { 207162306a36Sopenharmony_ci if (parm_data->lock_type == 207262306a36Sopenharmony_ci cpu_to_le16(CIFS_RDLCK)) 207362306a36Sopenharmony_ci pLockData->fl_type = F_RDLCK; 207462306a36Sopenharmony_ci else if (parm_data->lock_type == 207562306a36Sopenharmony_ci cpu_to_le16(CIFS_WRLCK)) 207662306a36Sopenharmony_ci pLockData->fl_type = F_WRLCK; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci pLockData->fl_start = le64_to_cpu(parm_data->start); 207962306a36Sopenharmony_ci pLockData->fl_end = pLockData->fl_start + 208062306a36Sopenharmony_ci (le64_to_cpu(parm_data->length) ? 208162306a36Sopenharmony_ci le64_to_cpu(parm_data->length) - 1 : 0); 208262306a36Sopenharmony_ci pLockData->fl_pid = -le32_to_cpu(parm_data->pid); 208362306a36Sopenharmony_ci } 208462306a36Sopenharmony_ci } 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ciplk_err_exit: 208762306a36Sopenharmony_ci free_rsp_buf(resp_buf_type, rsp_iov.iov_base); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci /* Note: On -EAGAIN error only caller can retry on handle based calls 209062306a36Sopenharmony_ci since file handle passed in no longer valid */ 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci return rc; 209362306a36Sopenharmony_ci} 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ciint 209762306a36Sopenharmony_ciCIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id) 209862306a36Sopenharmony_ci{ 209962306a36Sopenharmony_ci int rc = 0; 210062306a36Sopenharmony_ci CLOSE_REQ *pSMB = NULL; 210162306a36Sopenharmony_ci cifs_dbg(FYI, "In CIFSSMBClose\n"); 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci/* do not retry on dead session on close */ 210462306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB); 210562306a36Sopenharmony_ci if (rc == -EAGAIN) 210662306a36Sopenharmony_ci return 0; 210762306a36Sopenharmony_ci if (rc) 210862306a36Sopenharmony_ci return rc; 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci pSMB->FileID = (__u16) smb_file_id; 211162306a36Sopenharmony_ci pSMB->LastWriteTime = 0xFFFFFFFF; 211262306a36Sopenharmony_ci pSMB->ByteCount = 0; 211362306a36Sopenharmony_ci rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); 211462306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 211562306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_closes); 211662306a36Sopenharmony_ci if (rc) { 211762306a36Sopenharmony_ci if (rc != -EINTR) { 211862306a36Sopenharmony_ci /* EINTR is expected when user ctl-c to kill app */ 211962306a36Sopenharmony_ci cifs_dbg(VFS, "Send error in Close = %d\n", rc); 212062306a36Sopenharmony_ci } 212162306a36Sopenharmony_ci } 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci /* Since session is dead, file will be closed on server already */ 212462306a36Sopenharmony_ci if (rc == -EAGAIN) 212562306a36Sopenharmony_ci rc = 0; 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci return rc; 212862306a36Sopenharmony_ci} 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ciint 213162306a36Sopenharmony_ciCIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id) 213262306a36Sopenharmony_ci{ 213362306a36Sopenharmony_ci int rc = 0; 213462306a36Sopenharmony_ci FLUSH_REQ *pSMB = NULL; 213562306a36Sopenharmony_ci cifs_dbg(FYI, "In CIFSSMBFlush\n"); 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB); 213862306a36Sopenharmony_ci if (rc) 213962306a36Sopenharmony_ci return rc; 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci pSMB->FileID = (__u16) smb_file_id; 214262306a36Sopenharmony_ci pSMB->ByteCount = 0; 214362306a36Sopenharmony_ci rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); 214462306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 214562306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes); 214662306a36Sopenharmony_ci if (rc) 214762306a36Sopenharmony_ci cifs_dbg(VFS, "Send error in Flush = %d\n", rc); 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci return rc; 215062306a36Sopenharmony_ci} 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ciint CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, 215362306a36Sopenharmony_ci struct dentry *source_dentry, 215462306a36Sopenharmony_ci const char *from_name, const char *to_name, 215562306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 215662306a36Sopenharmony_ci{ 215762306a36Sopenharmony_ci int rc = 0; 215862306a36Sopenharmony_ci RENAME_REQ *pSMB = NULL; 215962306a36Sopenharmony_ci RENAME_RSP *pSMBr = NULL; 216062306a36Sopenharmony_ci int bytes_returned; 216162306a36Sopenharmony_ci int name_len, name_len2; 216262306a36Sopenharmony_ci __u16 count; 216362306a36Sopenharmony_ci int remap = cifs_remap(cifs_sb); 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci cifs_dbg(FYI, "In CIFSSMBRename\n"); 216662306a36Sopenharmony_cirenameRetry: 216762306a36Sopenharmony_ci rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB, 216862306a36Sopenharmony_ci (void **) &pSMBr); 216962306a36Sopenharmony_ci if (rc) 217062306a36Sopenharmony_ci return rc; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci pSMB->BufferFormat = 0x04; 217362306a36Sopenharmony_ci pSMB->SearchAttributes = 217462306a36Sopenharmony_ci cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | 217562306a36Sopenharmony_ci ATTR_DIRECTORY); 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 217862306a36Sopenharmony_ci name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName, 217962306a36Sopenharmony_ci from_name, PATH_MAX, 218062306a36Sopenharmony_ci cifs_sb->local_nls, remap); 218162306a36Sopenharmony_ci name_len++; /* trailing null */ 218262306a36Sopenharmony_ci name_len *= 2; 218362306a36Sopenharmony_ci pSMB->OldFileName[name_len] = 0x04; /* pad */ 218462306a36Sopenharmony_ci /* protocol requires ASCII signature byte on Unicode string */ 218562306a36Sopenharmony_ci pSMB->OldFileName[name_len + 1] = 0x00; 218662306a36Sopenharmony_ci name_len2 = 218762306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], 218862306a36Sopenharmony_ci to_name, PATH_MAX, cifs_sb->local_nls, 218962306a36Sopenharmony_ci remap); 219062306a36Sopenharmony_ci name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; 219162306a36Sopenharmony_ci name_len2 *= 2; /* convert to bytes */ 219262306a36Sopenharmony_ci } else { 219362306a36Sopenharmony_ci name_len = copy_path_name(pSMB->OldFileName, from_name); 219462306a36Sopenharmony_ci name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name); 219562306a36Sopenharmony_ci pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ 219662306a36Sopenharmony_ci name_len2++; /* signature byte */ 219762306a36Sopenharmony_ci } 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci count = 1 /* 1st signature byte */ + name_len + name_len2; 220062306a36Sopenharmony_ci inc_rfc1001_len(pSMB, count); 220162306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(count); 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 220462306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 220562306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_renames); 220662306a36Sopenharmony_ci if (rc) 220762306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in rename = %d\n", rc); 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci cifs_buf_release(pSMB); 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci if (rc == -EAGAIN) 221262306a36Sopenharmony_ci goto renameRetry; 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci return rc; 221562306a36Sopenharmony_ci} 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ciint CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, 221862306a36Sopenharmony_ci int netfid, const char *target_name, 221962306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 222062306a36Sopenharmony_ci{ 222162306a36Sopenharmony_ci struct smb_com_transaction2_sfi_req *pSMB = NULL; 222262306a36Sopenharmony_ci struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; 222362306a36Sopenharmony_ci struct set_file_rename *rename_info; 222462306a36Sopenharmony_ci char *data_offset; 222562306a36Sopenharmony_ci char dummy_string[30]; 222662306a36Sopenharmony_ci int rc = 0; 222762306a36Sopenharmony_ci int bytes_returned = 0; 222862306a36Sopenharmony_ci int len_of_str; 222962306a36Sopenharmony_ci __u16 params, param_offset, offset, count, byte_count; 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci cifs_dbg(FYI, "Rename to File by handle\n"); 223262306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, 223362306a36Sopenharmony_ci (void **) &pSMBr); 223462306a36Sopenharmony_ci if (rc) 223562306a36Sopenharmony_ci return rc; 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci params = 6; 223862306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 223962306a36Sopenharmony_ci pSMB->Reserved = 0; 224062306a36Sopenharmony_ci pSMB->Flags = 0; 224162306a36Sopenharmony_ci pSMB->Timeout = 0; 224262306a36Sopenharmony_ci pSMB->Reserved2 = 0; 224362306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; 224462306a36Sopenharmony_ci offset = param_offset + params; 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ 224762306a36Sopenharmony_ci data_offset = (char *)(pSMB) + offset + 4; 224862306a36Sopenharmony_ci rename_info = (struct set_file_rename *) data_offset; 224962306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 225062306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */ 225162306a36Sopenharmony_ci pSMB->SetupCount = 1; 225262306a36Sopenharmony_ci pSMB->Reserved3 = 0; 225362306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); 225462306a36Sopenharmony_ci byte_count = 3 /* pad */ + params; 225562306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 225662306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 225762306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 225862306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 225962306a36Sopenharmony_ci /* construct random name ".cifs_tmp<inodenum><mid>" */ 226062306a36Sopenharmony_ci rename_info->overwrite = cpu_to_le32(1); 226162306a36Sopenharmony_ci rename_info->root_fid = 0; 226262306a36Sopenharmony_ci /* unicode only call */ 226362306a36Sopenharmony_ci if (target_name == NULL) { 226462306a36Sopenharmony_ci sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid); 226562306a36Sopenharmony_ci len_of_str = 226662306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *)rename_info->target_name, 226762306a36Sopenharmony_ci dummy_string, 24, nls_codepage, remap); 226862306a36Sopenharmony_ci } else { 226962306a36Sopenharmony_ci len_of_str = 227062306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *)rename_info->target_name, 227162306a36Sopenharmony_ci target_name, PATH_MAX, nls_codepage, 227262306a36Sopenharmony_ci remap); 227362306a36Sopenharmony_ci } 227462306a36Sopenharmony_ci rename_info->target_name_len = cpu_to_le32(2 * len_of_str); 227562306a36Sopenharmony_ci count = sizeof(struct set_file_rename) + (2 * len_of_str); 227662306a36Sopenharmony_ci byte_count += count; 227762306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(count); 227862306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 227962306a36Sopenharmony_ci pSMB->Fid = netfid; 228062306a36Sopenharmony_ci pSMB->InformationLevel = 228162306a36Sopenharmony_ci cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); 228262306a36Sopenharmony_ci pSMB->Reserved4 = 0; 228362306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 228462306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 228562306a36Sopenharmony_ci rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, 228662306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 228762306a36Sopenharmony_ci cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames); 228862306a36Sopenharmony_ci if (rc) 228962306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n", 229062306a36Sopenharmony_ci rc); 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci cifs_buf_release(pSMB); 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci /* Note: On -EAGAIN error only caller can retry on handle based calls 229562306a36Sopenharmony_ci since file handle passed in no longer valid */ 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci return rc; 229862306a36Sopenharmony_ci} 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ciint 230162306a36Sopenharmony_ciCIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon, 230262306a36Sopenharmony_ci const char *fromName, const __u16 target_tid, const char *toName, 230362306a36Sopenharmony_ci const int flags, const struct nls_table *nls_codepage, int remap) 230462306a36Sopenharmony_ci{ 230562306a36Sopenharmony_ci int rc = 0; 230662306a36Sopenharmony_ci COPY_REQ *pSMB = NULL; 230762306a36Sopenharmony_ci COPY_RSP *pSMBr = NULL; 230862306a36Sopenharmony_ci int bytes_returned; 230962306a36Sopenharmony_ci int name_len, name_len2; 231062306a36Sopenharmony_ci __u16 count; 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci cifs_dbg(FYI, "In CIFSSMBCopy\n"); 231362306a36Sopenharmony_cicopyRetry: 231462306a36Sopenharmony_ci rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB, 231562306a36Sopenharmony_ci (void **) &pSMBr); 231662306a36Sopenharmony_ci if (rc) 231762306a36Sopenharmony_ci return rc; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci pSMB->BufferFormat = 0x04; 232062306a36Sopenharmony_ci pSMB->Tid2 = target_tid; 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci pSMB->Flags = cpu_to_le16(flags & COPY_TREE); 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 232562306a36Sopenharmony_ci name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName, 232662306a36Sopenharmony_ci fromName, PATH_MAX, nls_codepage, 232762306a36Sopenharmony_ci remap); 232862306a36Sopenharmony_ci name_len++; /* trailing null */ 232962306a36Sopenharmony_ci name_len *= 2; 233062306a36Sopenharmony_ci pSMB->OldFileName[name_len] = 0x04; /* pad */ 233162306a36Sopenharmony_ci /* protocol requires ASCII signature byte on Unicode string */ 233262306a36Sopenharmony_ci pSMB->OldFileName[name_len + 1] = 0x00; 233362306a36Sopenharmony_ci name_len2 = 233462306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], 233562306a36Sopenharmony_ci toName, PATH_MAX, nls_codepage, remap); 233662306a36Sopenharmony_ci name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; 233762306a36Sopenharmony_ci name_len2 *= 2; /* convert to bytes */ 233862306a36Sopenharmony_ci } else { 233962306a36Sopenharmony_ci name_len = copy_path_name(pSMB->OldFileName, fromName); 234062306a36Sopenharmony_ci pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ 234162306a36Sopenharmony_ci name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName); 234262306a36Sopenharmony_ci name_len2++; /* signature byte */ 234362306a36Sopenharmony_ci } 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci count = 1 /* 1st signature byte */ + name_len + name_len2; 234662306a36Sopenharmony_ci inc_rfc1001_len(pSMB, count); 234762306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(count); 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 235062306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 235162306a36Sopenharmony_ci if (rc) { 235262306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n", 235362306a36Sopenharmony_ci rc, le16_to_cpu(pSMBr->CopyCount)); 235462306a36Sopenharmony_ci } 235562306a36Sopenharmony_ci cifs_buf_release(pSMB); 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci if (rc == -EAGAIN) 235862306a36Sopenharmony_ci goto copyRetry; 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci return rc; 236162306a36Sopenharmony_ci} 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ciint 236462306a36Sopenharmony_ciCIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, 236562306a36Sopenharmony_ci const char *fromName, const char *toName, 236662306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 236762306a36Sopenharmony_ci{ 236862306a36Sopenharmony_ci TRANSACTION2_SPI_REQ *pSMB = NULL; 236962306a36Sopenharmony_ci TRANSACTION2_SPI_RSP *pSMBr = NULL; 237062306a36Sopenharmony_ci char *data_offset; 237162306a36Sopenharmony_ci int name_len; 237262306a36Sopenharmony_ci int name_len_target; 237362306a36Sopenharmony_ci int rc = 0; 237462306a36Sopenharmony_ci int bytes_returned = 0; 237562306a36Sopenharmony_ci __u16 params, param_offset, offset, byte_count; 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci cifs_dbg(FYI, "In Symlink Unix style\n"); 237862306a36Sopenharmony_cicreateSymLinkRetry: 237962306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 238062306a36Sopenharmony_ci (void **) &pSMBr); 238162306a36Sopenharmony_ci if (rc) 238262306a36Sopenharmony_ci return rc; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 238562306a36Sopenharmony_ci name_len = 238662306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName, 238762306a36Sopenharmony_ci /* find define for this maxpathcomponent */ 238862306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 238962306a36Sopenharmony_ci name_len++; /* trailing null */ 239062306a36Sopenharmony_ci name_len *= 2; 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci } else { 239362306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, fromName); 239462306a36Sopenharmony_ci } 239562306a36Sopenharmony_ci params = 6 + name_len; 239662306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 239762306a36Sopenharmony_ci pSMB->Reserved = 0; 239862306a36Sopenharmony_ci pSMB->Flags = 0; 239962306a36Sopenharmony_ci pSMB->Timeout = 0; 240062306a36Sopenharmony_ci pSMB->Reserved2 = 0; 240162306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_spi_req, 240262306a36Sopenharmony_ci InformationLevel) - 4; 240362306a36Sopenharmony_ci offset = param_offset + params; 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ 240662306a36Sopenharmony_ci data_offset = (char *)pSMB + offset + 4; 240762306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 240862306a36Sopenharmony_ci name_len_target = 240962306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) data_offset, toName, 241062306a36Sopenharmony_ci /* find define for this maxpathcomponent */ 241162306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 241262306a36Sopenharmony_ci name_len_target++; /* trailing null */ 241362306a36Sopenharmony_ci name_len_target *= 2; 241462306a36Sopenharmony_ci } else { 241562306a36Sopenharmony_ci name_len_target = copy_path_name(data_offset, toName); 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 241962306a36Sopenharmony_ci /* BB find exact max on data count below from sess */ 242062306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 242162306a36Sopenharmony_ci pSMB->SetupCount = 1; 242262306a36Sopenharmony_ci pSMB->Reserved3 = 0; 242362306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); 242462306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + name_len_target; 242562306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(name_len_target); 242662306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 242762306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 242862306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 242962306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 243062306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 243162306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); 243262306a36Sopenharmony_ci pSMB->Reserved4 = 0; 243362306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 243462306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 243562306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 243662306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 243762306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks); 243862306a36Sopenharmony_ci if (rc) 243962306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n", 244062306a36Sopenharmony_ci rc); 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci cifs_buf_release(pSMB); 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci if (rc == -EAGAIN) 244562306a36Sopenharmony_ci goto createSymLinkRetry; 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci return rc; 244862306a36Sopenharmony_ci} 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ciint 245162306a36Sopenharmony_ciCIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, 245262306a36Sopenharmony_ci const char *fromName, const char *toName, 245362306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 245462306a36Sopenharmony_ci{ 245562306a36Sopenharmony_ci TRANSACTION2_SPI_REQ *pSMB = NULL; 245662306a36Sopenharmony_ci TRANSACTION2_SPI_RSP *pSMBr = NULL; 245762306a36Sopenharmony_ci char *data_offset; 245862306a36Sopenharmony_ci int name_len; 245962306a36Sopenharmony_ci int name_len_target; 246062306a36Sopenharmony_ci int rc = 0; 246162306a36Sopenharmony_ci int bytes_returned = 0; 246262306a36Sopenharmony_ci __u16 params, param_offset, offset, byte_count; 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci cifs_dbg(FYI, "In Create Hard link Unix style\n"); 246562306a36Sopenharmony_cicreateHardLinkRetry: 246662306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 246762306a36Sopenharmony_ci (void **) &pSMBr); 246862306a36Sopenharmony_ci if (rc) 246962306a36Sopenharmony_ci return rc; 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 247262306a36Sopenharmony_ci name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName, 247362306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 247462306a36Sopenharmony_ci name_len++; /* trailing null */ 247562306a36Sopenharmony_ci name_len *= 2; 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci } else { 247862306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, toName); 247962306a36Sopenharmony_ci } 248062306a36Sopenharmony_ci params = 6 + name_len; 248162306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 248262306a36Sopenharmony_ci pSMB->Reserved = 0; 248362306a36Sopenharmony_ci pSMB->Flags = 0; 248462306a36Sopenharmony_ci pSMB->Timeout = 0; 248562306a36Sopenharmony_ci pSMB->Reserved2 = 0; 248662306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_spi_req, 248762306a36Sopenharmony_ci InformationLevel) - 4; 248862306a36Sopenharmony_ci offset = param_offset + params; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ 249162306a36Sopenharmony_ci data_offset = (char *)pSMB + offset + 4; 249262306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 249362306a36Sopenharmony_ci name_len_target = 249462306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) data_offset, fromName, 249562306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 249662306a36Sopenharmony_ci name_len_target++; /* trailing null */ 249762306a36Sopenharmony_ci name_len_target *= 2; 249862306a36Sopenharmony_ci } else { 249962306a36Sopenharmony_ci name_len_target = copy_path_name(data_offset, fromName); 250062306a36Sopenharmony_ci } 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 250362306a36Sopenharmony_ci /* BB find exact max on data count below from sess*/ 250462306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 250562306a36Sopenharmony_ci pSMB->SetupCount = 1; 250662306a36Sopenharmony_ci pSMB->Reserved3 = 0; 250762306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); 250862306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + name_len_target; 250962306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 251062306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 251162306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(name_len_target); 251262306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 251362306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 251462306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 251562306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); 251662306a36Sopenharmony_ci pSMB->Reserved4 = 0; 251762306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 251862306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 251962306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 252062306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 252162306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks); 252262306a36Sopenharmony_ci if (rc) 252362306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n", 252462306a36Sopenharmony_ci rc); 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci cifs_buf_release(pSMB); 252762306a36Sopenharmony_ci if (rc == -EAGAIN) 252862306a36Sopenharmony_ci goto createHardLinkRetry; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci return rc; 253162306a36Sopenharmony_ci} 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ciint CIFSCreateHardLink(const unsigned int xid, 253462306a36Sopenharmony_ci struct cifs_tcon *tcon, 253562306a36Sopenharmony_ci struct dentry *source_dentry, 253662306a36Sopenharmony_ci const char *from_name, const char *to_name, 253762306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 253862306a36Sopenharmony_ci{ 253962306a36Sopenharmony_ci int rc = 0; 254062306a36Sopenharmony_ci NT_RENAME_REQ *pSMB = NULL; 254162306a36Sopenharmony_ci RENAME_RSP *pSMBr = NULL; 254262306a36Sopenharmony_ci int bytes_returned; 254362306a36Sopenharmony_ci int name_len, name_len2; 254462306a36Sopenharmony_ci __u16 count; 254562306a36Sopenharmony_ci int remap = cifs_remap(cifs_sb); 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ci cifs_dbg(FYI, "In CIFSCreateHardLink\n"); 254862306a36Sopenharmony_ciwinCreateHardLinkRetry: 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB, 255162306a36Sopenharmony_ci (void **) &pSMBr); 255262306a36Sopenharmony_ci if (rc) 255362306a36Sopenharmony_ci return rc; 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci pSMB->SearchAttributes = 255662306a36Sopenharmony_ci cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | 255762306a36Sopenharmony_ci ATTR_DIRECTORY); 255862306a36Sopenharmony_ci pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK); 255962306a36Sopenharmony_ci pSMB->ClusterCount = 0; 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci pSMB->BufferFormat = 0x04; 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 256462306a36Sopenharmony_ci name_len = 256562306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name, 256662306a36Sopenharmony_ci PATH_MAX, cifs_sb->local_nls, remap); 256762306a36Sopenharmony_ci name_len++; /* trailing null */ 256862306a36Sopenharmony_ci name_len *= 2; 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci /* protocol specifies ASCII buffer format (0x04) for unicode */ 257162306a36Sopenharmony_ci pSMB->OldFileName[name_len] = 0x04; 257262306a36Sopenharmony_ci pSMB->OldFileName[name_len + 1] = 0x00; /* pad */ 257362306a36Sopenharmony_ci name_len2 = 257462306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], 257562306a36Sopenharmony_ci to_name, PATH_MAX, cifs_sb->local_nls, 257662306a36Sopenharmony_ci remap); 257762306a36Sopenharmony_ci name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; 257862306a36Sopenharmony_ci name_len2 *= 2; /* convert to bytes */ 257962306a36Sopenharmony_ci } else { 258062306a36Sopenharmony_ci name_len = copy_path_name(pSMB->OldFileName, from_name); 258162306a36Sopenharmony_ci pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ 258262306a36Sopenharmony_ci name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name); 258362306a36Sopenharmony_ci name_len2++; /* signature byte */ 258462306a36Sopenharmony_ci } 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci count = 1 /* string type byte */ + name_len + name_len2; 258762306a36Sopenharmony_ci inc_rfc1001_len(pSMB, count); 258862306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(count); 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 259162306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 259262306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks); 259362306a36Sopenharmony_ci if (rc) 259462306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc); 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci cifs_buf_release(pSMB); 259762306a36Sopenharmony_ci if (rc == -EAGAIN) 259862306a36Sopenharmony_ci goto winCreateHardLinkRetry; 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci return rc; 260162306a36Sopenharmony_ci} 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ciint 260462306a36Sopenharmony_ciCIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, 260562306a36Sopenharmony_ci const unsigned char *searchName, char **symlinkinfo, 260662306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 260762306a36Sopenharmony_ci{ 260862306a36Sopenharmony_ci/* SMB_QUERY_FILE_UNIX_LINK */ 260962306a36Sopenharmony_ci TRANSACTION2_QPI_REQ *pSMB = NULL; 261062306a36Sopenharmony_ci TRANSACTION2_QPI_RSP *pSMBr = NULL; 261162306a36Sopenharmony_ci int rc = 0; 261262306a36Sopenharmony_ci int bytes_returned; 261362306a36Sopenharmony_ci int name_len; 261462306a36Sopenharmony_ci __u16 params, byte_count; 261562306a36Sopenharmony_ci char *data_start; 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName); 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ciquerySymLinkRetry: 262062306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 262162306a36Sopenharmony_ci (void **) &pSMBr); 262262306a36Sopenharmony_ci if (rc) 262362306a36Sopenharmony_ci return rc; 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 262662306a36Sopenharmony_ci name_len = 262762306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, 262862306a36Sopenharmony_ci searchName, PATH_MAX, nls_codepage, 262962306a36Sopenharmony_ci remap); 263062306a36Sopenharmony_ci name_len++; /* trailing null */ 263162306a36Sopenharmony_ci name_len *= 2; 263262306a36Sopenharmony_ci } else { 263362306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, searchName); 263462306a36Sopenharmony_ci } 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_ci params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; 263762306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 263862306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 263962306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize); 264062306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 264162306a36Sopenharmony_ci pSMB->Reserved = 0; 264262306a36Sopenharmony_ci pSMB->Flags = 0; 264362306a36Sopenharmony_ci pSMB->Timeout = 0; 264462306a36Sopenharmony_ci pSMB->Reserved2 = 0; 264562306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof( 264662306a36Sopenharmony_ci struct smb_com_transaction2_qpi_req, InformationLevel) - 4); 264762306a36Sopenharmony_ci pSMB->DataCount = 0; 264862306a36Sopenharmony_ci pSMB->DataOffset = 0; 264962306a36Sopenharmony_ci pSMB->SetupCount = 1; 265062306a36Sopenharmony_ci pSMB->Reserved3 = 0; 265162306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); 265262306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 265362306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 265462306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 265562306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); 265662306a36Sopenharmony_ci pSMB->Reserved4 = 0; 265762306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 265862306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 266162306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 266262306a36Sopenharmony_ci if (rc) { 266362306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc); 266462306a36Sopenharmony_ci } else { 266562306a36Sopenharmony_ci /* decode response */ 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 266862306a36Sopenharmony_ci /* BB also check enough total bytes returned */ 266962306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 2) 267062306a36Sopenharmony_ci rc = -EIO; 267162306a36Sopenharmony_ci else { 267262306a36Sopenharmony_ci bool is_unicode; 267362306a36Sopenharmony_ci u16 count = le16_to_cpu(pSMBr->t2.DataCount); 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci data_start = ((char *) &pSMBr->hdr.Protocol) + 267662306a36Sopenharmony_ci le16_to_cpu(pSMBr->t2.DataOffset); 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ci if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) 267962306a36Sopenharmony_ci is_unicode = true; 268062306a36Sopenharmony_ci else 268162306a36Sopenharmony_ci is_unicode = false; 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci /* BB FIXME investigate remapping reserved chars here */ 268462306a36Sopenharmony_ci *symlinkinfo = cifs_strndup_from_utf16(data_start, 268562306a36Sopenharmony_ci count, is_unicode, nls_codepage); 268662306a36Sopenharmony_ci if (!*symlinkinfo) 268762306a36Sopenharmony_ci rc = -ENOMEM; 268862306a36Sopenharmony_ci } 268962306a36Sopenharmony_ci } 269062306a36Sopenharmony_ci cifs_buf_release(pSMB); 269162306a36Sopenharmony_ci if (rc == -EAGAIN) 269262306a36Sopenharmony_ci goto querySymLinkRetry; 269362306a36Sopenharmony_ci return rc; 269462306a36Sopenharmony_ci} 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ciint cifs_query_reparse_point(const unsigned int xid, 269762306a36Sopenharmony_ci struct cifs_tcon *tcon, 269862306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb, 269962306a36Sopenharmony_ci const char *full_path, 270062306a36Sopenharmony_ci u32 *tag, struct kvec *rsp, 270162306a36Sopenharmony_ci int *rsp_buftype) 270262306a36Sopenharmony_ci{ 270362306a36Sopenharmony_ci struct cifs_open_parms oparms; 270462306a36Sopenharmony_ci TRANSACT_IOCTL_REQ *io_req = NULL; 270562306a36Sopenharmony_ci TRANSACT_IOCTL_RSP *io_rsp = NULL; 270662306a36Sopenharmony_ci struct cifs_fid fid; 270762306a36Sopenharmony_ci __u32 data_offset, data_count; 270862306a36Sopenharmony_ci __u8 *start, *end; 270962306a36Sopenharmony_ci int io_rsp_len; 271062306a36Sopenharmony_ci int oplock = 0; 271162306a36Sopenharmony_ci int rc; 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_ci cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path); 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci if (cap_unix(tcon->ses)) 271662306a36Sopenharmony_ci return -EOPNOTSUPP; 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci oparms = (struct cifs_open_parms) { 271962306a36Sopenharmony_ci .tcon = tcon, 272062306a36Sopenharmony_ci .cifs_sb = cifs_sb, 272162306a36Sopenharmony_ci .desired_access = FILE_READ_ATTRIBUTES, 272262306a36Sopenharmony_ci .create_options = cifs_create_options(cifs_sb, 272362306a36Sopenharmony_ci OPEN_REPARSE_POINT), 272462306a36Sopenharmony_ci .disposition = FILE_OPEN, 272562306a36Sopenharmony_ci .path = full_path, 272662306a36Sopenharmony_ci .fid = &fid, 272762306a36Sopenharmony_ci }; 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci rc = CIFS_open(xid, &oparms, &oplock, NULL); 273062306a36Sopenharmony_ci if (rc) 273162306a36Sopenharmony_ci return rc; 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, 273462306a36Sopenharmony_ci (void **)&io_req, (void **)&io_rsp); 273562306a36Sopenharmony_ci if (rc) 273662306a36Sopenharmony_ci goto error; 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci io_req->TotalParameterCount = 0; 273962306a36Sopenharmony_ci io_req->TotalDataCount = 0; 274062306a36Sopenharmony_ci io_req->MaxParameterCount = cpu_to_le32(2); 274162306a36Sopenharmony_ci /* BB find exact data count max from sess structure BB */ 274262306a36Sopenharmony_ci io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); 274362306a36Sopenharmony_ci io_req->MaxSetupCount = 4; 274462306a36Sopenharmony_ci io_req->Reserved = 0; 274562306a36Sopenharmony_ci io_req->ParameterOffset = 0; 274662306a36Sopenharmony_ci io_req->DataCount = 0; 274762306a36Sopenharmony_ci io_req->DataOffset = 0; 274862306a36Sopenharmony_ci io_req->SetupCount = 4; 274962306a36Sopenharmony_ci io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); 275062306a36Sopenharmony_ci io_req->ParameterCount = io_req->TotalParameterCount; 275162306a36Sopenharmony_ci io_req->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT); 275262306a36Sopenharmony_ci io_req->IsFsctl = 1; 275362306a36Sopenharmony_ci io_req->IsRootFlag = 0; 275462306a36Sopenharmony_ci io_req->Fid = fid.netfid; 275562306a36Sopenharmony_ci io_req->ByteCount = 0; 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req, 275862306a36Sopenharmony_ci (struct smb_hdr *)io_rsp, &io_rsp_len, 0); 275962306a36Sopenharmony_ci if (rc) 276062306a36Sopenharmony_ci goto error; 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci data_offset = le32_to_cpu(io_rsp->DataOffset); 276362306a36Sopenharmony_ci data_count = le32_to_cpu(io_rsp->DataCount); 276462306a36Sopenharmony_ci if (get_bcc(&io_rsp->hdr) < 2 || data_offset > 512 || 276562306a36Sopenharmony_ci !data_count || data_count > 2048) { 276662306a36Sopenharmony_ci rc = -EIO; 276762306a36Sopenharmony_ci goto error; 276862306a36Sopenharmony_ci } 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount; 277162306a36Sopenharmony_ci start = (__u8 *)&io_rsp->hdr.Protocol + data_offset; 277262306a36Sopenharmony_ci if (start >= end) { 277362306a36Sopenharmony_ci rc = -EIO; 277462306a36Sopenharmony_ci goto error; 277562306a36Sopenharmony_ci } 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci *tag = le32_to_cpu(((struct reparse_data_buffer *)start)->ReparseTag); 277862306a36Sopenharmony_ci rsp->iov_base = io_rsp; 277962306a36Sopenharmony_ci rsp->iov_len = io_rsp_len; 278062306a36Sopenharmony_ci *rsp_buftype = CIFS_LARGE_BUFFER; 278162306a36Sopenharmony_ci CIFSSMBClose(xid, tcon, fid.netfid); 278262306a36Sopenharmony_ci return 0; 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_cierror: 278562306a36Sopenharmony_ci cifs_buf_release(io_req); 278662306a36Sopenharmony_ci CIFSSMBClose(xid, tcon, fid.netfid); 278762306a36Sopenharmony_ci return rc; 278862306a36Sopenharmony_ci} 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ciint 279162306a36Sopenharmony_ciCIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon, 279262306a36Sopenharmony_ci __u16 fid) 279362306a36Sopenharmony_ci{ 279462306a36Sopenharmony_ci int rc = 0; 279562306a36Sopenharmony_ci int bytes_returned; 279662306a36Sopenharmony_ci struct smb_com_transaction_compr_ioctl_req *pSMB; 279762306a36Sopenharmony_ci struct smb_com_transaction_ioctl_rsp *pSMBr; 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci cifs_dbg(FYI, "Set compression for %u\n", fid); 280062306a36Sopenharmony_ci rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, 280162306a36Sopenharmony_ci (void **) &pSMBr); 280262306a36Sopenharmony_ci if (rc) 280362306a36Sopenharmony_ci return rc; 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT); 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci pSMB->TotalParameterCount = 0; 280862306a36Sopenharmony_ci pSMB->TotalDataCount = cpu_to_le32(2); 280962306a36Sopenharmony_ci pSMB->MaxParameterCount = 0; 281062306a36Sopenharmony_ci pSMB->MaxDataCount = 0; 281162306a36Sopenharmony_ci pSMB->MaxSetupCount = 4; 281262306a36Sopenharmony_ci pSMB->Reserved = 0; 281362306a36Sopenharmony_ci pSMB->ParameterOffset = 0; 281462306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le32(2); 281562306a36Sopenharmony_ci pSMB->DataOffset = 281662306a36Sopenharmony_ci cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req, 281762306a36Sopenharmony_ci compression_state) - 4); /* 84 */ 281862306a36Sopenharmony_ci pSMB->SetupCount = 4; 281962306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); 282062306a36Sopenharmony_ci pSMB->ParameterCount = 0; 282162306a36Sopenharmony_ci pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION); 282262306a36Sopenharmony_ci pSMB->IsFsctl = 1; /* FSCTL */ 282362306a36Sopenharmony_ci pSMB->IsRootFlag = 0; 282462306a36Sopenharmony_ci pSMB->Fid = fid; /* file handle always le */ 282562306a36Sopenharmony_ci /* 3 byte pad, followed by 2 byte compress state */ 282662306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(5); 282762306a36Sopenharmony_ci inc_rfc1001_len(pSMB, 5); 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 283062306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 283162306a36Sopenharmony_ci if (rc) 283262306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc); 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_ci cifs_buf_release(pSMB); 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci /* 283762306a36Sopenharmony_ci * Note: On -EAGAIN error only caller can retry on handle based calls 283862306a36Sopenharmony_ci * since file handle passed in no longer valid. 283962306a36Sopenharmony_ci */ 284062306a36Sopenharmony_ci return rc; 284162306a36Sopenharmony_ci} 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci#ifdef CONFIG_CIFS_POSIX 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci#ifdef CONFIG_FS_POSIX_ACL 284762306a36Sopenharmony_ci/** 284862306a36Sopenharmony_ci * cifs_init_posix_acl - convert ACL from cifs to POSIX ACL format 284962306a36Sopenharmony_ci * @ace: POSIX ACL entry to store converted ACL into 285062306a36Sopenharmony_ci * @cifs_ace: ACL in cifs format 285162306a36Sopenharmony_ci * 285262306a36Sopenharmony_ci * Convert an Access Control Entry from wire format to local POSIX xattr 285362306a36Sopenharmony_ci * format. 285462306a36Sopenharmony_ci * 285562306a36Sopenharmony_ci * Note that the @cifs_uid member is used to store both {g,u}id_t. 285662306a36Sopenharmony_ci */ 285762306a36Sopenharmony_cistatic void cifs_init_posix_acl(struct posix_acl_entry *ace, 285862306a36Sopenharmony_ci struct cifs_posix_ace *cifs_ace) 285962306a36Sopenharmony_ci{ 286062306a36Sopenharmony_ci /* u8 cifs fields do not need le conversion */ 286162306a36Sopenharmony_ci ace->e_perm = cifs_ace->cifs_e_perm; 286262306a36Sopenharmony_ci ace->e_tag = cifs_ace->cifs_e_tag; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ci switch (ace->e_tag) { 286562306a36Sopenharmony_ci case ACL_USER: 286662306a36Sopenharmony_ci ace->e_uid = make_kuid(&init_user_ns, 286762306a36Sopenharmony_ci le64_to_cpu(cifs_ace->cifs_uid)); 286862306a36Sopenharmony_ci break; 286962306a36Sopenharmony_ci case ACL_GROUP: 287062306a36Sopenharmony_ci ace->e_gid = make_kgid(&init_user_ns, 287162306a36Sopenharmony_ci le64_to_cpu(cifs_ace->cifs_uid)); 287262306a36Sopenharmony_ci break; 287362306a36Sopenharmony_ci } 287462306a36Sopenharmony_ci return; 287562306a36Sopenharmony_ci} 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci/** 287862306a36Sopenharmony_ci * cifs_to_posix_acl - copy cifs ACL format to POSIX ACL format 287962306a36Sopenharmony_ci * @acl: ACLs returned in POSIX ACL format 288062306a36Sopenharmony_ci * @src: ACLs in cifs format 288162306a36Sopenharmony_ci * @acl_type: type of POSIX ACL requested 288262306a36Sopenharmony_ci * @size_of_data_area: size of SMB we got 288362306a36Sopenharmony_ci * 288462306a36Sopenharmony_ci * This function converts ACLs from cifs format to POSIX ACL format. 288562306a36Sopenharmony_ci * If @acl is NULL then the size of the buffer required to store POSIX ACLs in 288662306a36Sopenharmony_ci * their uapi format is returned. 288762306a36Sopenharmony_ci */ 288862306a36Sopenharmony_cistatic int cifs_to_posix_acl(struct posix_acl **acl, char *src, 288962306a36Sopenharmony_ci const int acl_type, const int size_of_data_area) 289062306a36Sopenharmony_ci{ 289162306a36Sopenharmony_ci int size = 0; 289262306a36Sopenharmony_ci __u16 count; 289362306a36Sopenharmony_ci struct cifs_posix_ace *pACE; 289462306a36Sopenharmony_ci struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src; 289562306a36Sopenharmony_ci struct posix_acl *kacl = NULL; 289662306a36Sopenharmony_ci struct posix_acl_entry *pa, *pe; 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION) 289962306a36Sopenharmony_ci return -EOPNOTSUPP; 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_ci if (acl_type == ACL_TYPE_ACCESS) { 290262306a36Sopenharmony_ci count = le16_to_cpu(cifs_acl->access_entry_count); 290362306a36Sopenharmony_ci pACE = &cifs_acl->ace_array[0]; 290462306a36Sopenharmony_ci size = sizeof(struct cifs_posix_acl); 290562306a36Sopenharmony_ci size += sizeof(struct cifs_posix_ace) * count; 290662306a36Sopenharmony_ci /* check if we would go beyond end of SMB */ 290762306a36Sopenharmony_ci if (size_of_data_area < size) { 290862306a36Sopenharmony_ci cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n", 290962306a36Sopenharmony_ci size_of_data_area, size); 291062306a36Sopenharmony_ci return -EINVAL; 291162306a36Sopenharmony_ci } 291262306a36Sopenharmony_ci } else if (acl_type == ACL_TYPE_DEFAULT) { 291362306a36Sopenharmony_ci count = le16_to_cpu(cifs_acl->access_entry_count); 291462306a36Sopenharmony_ci size = sizeof(struct cifs_posix_acl); 291562306a36Sopenharmony_ci size += sizeof(struct cifs_posix_ace) * count; 291662306a36Sopenharmony_ci /* skip past access ACEs to get to default ACEs */ 291762306a36Sopenharmony_ci pACE = &cifs_acl->ace_array[count]; 291862306a36Sopenharmony_ci count = le16_to_cpu(cifs_acl->default_entry_count); 291962306a36Sopenharmony_ci size += sizeof(struct cifs_posix_ace) * count; 292062306a36Sopenharmony_ci /* check if we would go beyond end of SMB */ 292162306a36Sopenharmony_ci if (size_of_data_area < size) 292262306a36Sopenharmony_ci return -EINVAL; 292362306a36Sopenharmony_ci } else { 292462306a36Sopenharmony_ci /* illegal type */ 292562306a36Sopenharmony_ci return -EINVAL; 292662306a36Sopenharmony_ci } 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci /* Allocate number of POSIX ACLs to store in VFS format. */ 292962306a36Sopenharmony_ci kacl = posix_acl_alloc(count, GFP_NOFS); 293062306a36Sopenharmony_ci if (!kacl) 293162306a36Sopenharmony_ci return -ENOMEM; 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci FOREACH_ACL_ENTRY(pa, kacl, pe) { 293462306a36Sopenharmony_ci cifs_init_posix_acl(pa, pACE); 293562306a36Sopenharmony_ci pACE++; 293662306a36Sopenharmony_ci } 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci *acl = kacl; 293962306a36Sopenharmony_ci return 0; 294062306a36Sopenharmony_ci} 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci/** 294362306a36Sopenharmony_ci * cifs_init_ace - convert ACL entry from POSIX ACL to cifs format 294462306a36Sopenharmony_ci * @cifs_ace: the cifs ACL entry to store into 294562306a36Sopenharmony_ci * @local_ace: the POSIX ACL entry to convert 294662306a36Sopenharmony_ci */ 294762306a36Sopenharmony_cistatic void cifs_init_ace(struct cifs_posix_ace *cifs_ace, 294862306a36Sopenharmony_ci const struct posix_acl_entry *local_ace) 294962306a36Sopenharmony_ci{ 295062306a36Sopenharmony_ci cifs_ace->cifs_e_perm = local_ace->e_perm; 295162306a36Sopenharmony_ci cifs_ace->cifs_e_tag = local_ace->e_tag; 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci switch (local_ace->e_tag) { 295462306a36Sopenharmony_ci case ACL_USER: 295562306a36Sopenharmony_ci cifs_ace->cifs_uid = 295662306a36Sopenharmony_ci cpu_to_le64(from_kuid(&init_user_ns, local_ace->e_uid)); 295762306a36Sopenharmony_ci break; 295862306a36Sopenharmony_ci case ACL_GROUP: 295962306a36Sopenharmony_ci cifs_ace->cifs_uid = 296062306a36Sopenharmony_ci cpu_to_le64(from_kgid(&init_user_ns, local_ace->e_gid)); 296162306a36Sopenharmony_ci break; 296262306a36Sopenharmony_ci default: 296362306a36Sopenharmony_ci cifs_ace->cifs_uid = cpu_to_le64(-1); 296462306a36Sopenharmony_ci } 296562306a36Sopenharmony_ci} 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci/** 296862306a36Sopenharmony_ci * posix_acl_to_cifs - convert ACLs from POSIX ACL to cifs format 296962306a36Sopenharmony_ci * @parm_data: ACLs in cifs format to conver to 297062306a36Sopenharmony_ci * @acl: ACLs in POSIX ACL format to convert from 297162306a36Sopenharmony_ci * @acl_type: the type of POSIX ACLs stored in @acl 297262306a36Sopenharmony_ci * 297362306a36Sopenharmony_ci * Return: the number cifs ACL entries after conversion 297462306a36Sopenharmony_ci */ 297562306a36Sopenharmony_cistatic __u16 posix_acl_to_cifs(char *parm_data, const struct posix_acl *acl, 297662306a36Sopenharmony_ci const int acl_type) 297762306a36Sopenharmony_ci{ 297862306a36Sopenharmony_ci __u16 rc = 0; 297962306a36Sopenharmony_ci struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data; 298062306a36Sopenharmony_ci const struct posix_acl_entry *pa, *pe; 298162306a36Sopenharmony_ci int count; 298262306a36Sopenharmony_ci int i = 0; 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci if ((acl == NULL) || (cifs_acl == NULL)) 298562306a36Sopenharmony_ci return 0; 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci count = acl->a_count; 298862306a36Sopenharmony_ci cifs_dbg(FYI, "setting acl with %d entries\n", count); 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci /* 299162306a36Sopenharmony_ci * Note that the uapi POSIX ACL version is verified by the VFS and is 299262306a36Sopenharmony_ci * independent of the cifs ACL version. Changing the POSIX ACL version 299362306a36Sopenharmony_ci * is a uapi change and if it's changed we will pass down the POSIX ACL 299462306a36Sopenharmony_ci * version in struct posix_acl from the VFS. For now there's really 299562306a36Sopenharmony_ci * only one that all filesystems know how to deal with. 299662306a36Sopenharmony_ci */ 299762306a36Sopenharmony_ci cifs_acl->version = cpu_to_le16(1); 299862306a36Sopenharmony_ci if (acl_type == ACL_TYPE_ACCESS) { 299962306a36Sopenharmony_ci cifs_acl->access_entry_count = cpu_to_le16(count); 300062306a36Sopenharmony_ci cifs_acl->default_entry_count = cpu_to_le16(0xFFFF); 300162306a36Sopenharmony_ci } else if (acl_type == ACL_TYPE_DEFAULT) { 300262306a36Sopenharmony_ci cifs_acl->default_entry_count = cpu_to_le16(count); 300362306a36Sopenharmony_ci cifs_acl->access_entry_count = cpu_to_le16(0xFFFF); 300462306a36Sopenharmony_ci } else { 300562306a36Sopenharmony_ci cifs_dbg(FYI, "unknown ACL type %d\n", acl_type); 300662306a36Sopenharmony_ci return 0; 300762306a36Sopenharmony_ci } 300862306a36Sopenharmony_ci FOREACH_ACL_ENTRY(pa, acl, pe) { 300962306a36Sopenharmony_ci cifs_init_ace(&cifs_acl->ace_array[i++], pa); 301062306a36Sopenharmony_ci } 301162306a36Sopenharmony_ci if (rc == 0) { 301262306a36Sopenharmony_ci rc = (__u16)(count * sizeof(struct cifs_posix_ace)); 301362306a36Sopenharmony_ci rc += sizeof(struct cifs_posix_acl); 301462306a36Sopenharmony_ci /* BB add check to make sure ACL does not overflow SMB */ 301562306a36Sopenharmony_ci } 301662306a36Sopenharmony_ci return rc; 301762306a36Sopenharmony_ci} 301862306a36Sopenharmony_ci 301962306a36Sopenharmony_ciint cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon, 302062306a36Sopenharmony_ci const unsigned char *searchName, struct posix_acl **acl, 302162306a36Sopenharmony_ci const int acl_type, const struct nls_table *nls_codepage, 302262306a36Sopenharmony_ci int remap) 302362306a36Sopenharmony_ci{ 302462306a36Sopenharmony_ci/* SMB_QUERY_POSIX_ACL */ 302562306a36Sopenharmony_ci TRANSACTION2_QPI_REQ *pSMB = NULL; 302662306a36Sopenharmony_ci TRANSACTION2_QPI_RSP *pSMBr = NULL; 302762306a36Sopenharmony_ci int rc = 0; 302862306a36Sopenharmony_ci int bytes_returned; 302962306a36Sopenharmony_ci int name_len; 303062306a36Sopenharmony_ci __u16 params, byte_count; 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName); 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ciqueryAclRetry: 303562306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 303662306a36Sopenharmony_ci (void **) &pSMBr); 303762306a36Sopenharmony_ci if (rc) 303862306a36Sopenharmony_ci return rc; 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 304162306a36Sopenharmony_ci name_len = 304262306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, 304362306a36Sopenharmony_ci searchName, PATH_MAX, nls_codepage, 304462306a36Sopenharmony_ci remap); 304562306a36Sopenharmony_ci name_len++; /* trailing null */ 304662306a36Sopenharmony_ci name_len *= 2; 304762306a36Sopenharmony_ci pSMB->FileName[name_len] = 0; 304862306a36Sopenharmony_ci pSMB->FileName[name_len+1] = 0; 304962306a36Sopenharmony_ci } else { 305062306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, searchName); 305162306a36Sopenharmony_ci } 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; 305462306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 305562306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 305662306a36Sopenharmony_ci /* BB find exact max data count below from sess structure BB */ 305762306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(4000); 305862306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 305962306a36Sopenharmony_ci pSMB->Reserved = 0; 306062306a36Sopenharmony_ci pSMB->Flags = 0; 306162306a36Sopenharmony_ci pSMB->Timeout = 0; 306262306a36Sopenharmony_ci pSMB->Reserved2 = 0; 306362306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16( 306462306a36Sopenharmony_ci offsetof(struct smb_com_transaction2_qpi_req, 306562306a36Sopenharmony_ci InformationLevel) - 4); 306662306a36Sopenharmony_ci pSMB->DataCount = 0; 306762306a36Sopenharmony_ci pSMB->DataOffset = 0; 306862306a36Sopenharmony_ci pSMB->SetupCount = 1; 306962306a36Sopenharmony_ci pSMB->Reserved3 = 0; 307062306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); 307162306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 307262306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 307362306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 307462306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL); 307562306a36Sopenharmony_ci pSMB->Reserved4 = 0; 307662306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 307762306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 308062306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 308162306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get); 308262306a36Sopenharmony_ci if (rc) { 308362306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc); 308462306a36Sopenharmony_ci } else { 308562306a36Sopenharmony_ci /* decode response */ 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 308862306a36Sopenharmony_ci /* BB also check enough total bytes returned */ 308962306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 2) 309062306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 309162306a36Sopenharmony_ci else { 309262306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 309362306a36Sopenharmony_ci __u16 count = le16_to_cpu(pSMBr->t2.DataCount); 309462306a36Sopenharmony_ci rc = cifs_to_posix_acl(acl, 309562306a36Sopenharmony_ci (char *)&pSMBr->hdr.Protocol+data_offset, 309662306a36Sopenharmony_ci acl_type, count); 309762306a36Sopenharmony_ci } 309862306a36Sopenharmony_ci } 309962306a36Sopenharmony_ci cifs_buf_release(pSMB); 310062306a36Sopenharmony_ci /* 310162306a36Sopenharmony_ci * The else branch after SendReceive() doesn't return EAGAIN so if we 310262306a36Sopenharmony_ci * allocated @acl in cifs_to_posix_acl() we are guaranteed to return 310362306a36Sopenharmony_ci * here and don't leak POSIX ACLs. 310462306a36Sopenharmony_ci */ 310562306a36Sopenharmony_ci if (rc == -EAGAIN) 310662306a36Sopenharmony_ci goto queryAclRetry; 310762306a36Sopenharmony_ci return rc; 310862306a36Sopenharmony_ci} 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ciint cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon, 311162306a36Sopenharmony_ci const unsigned char *fileName, const struct posix_acl *acl, 311262306a36Sopenharmony_ci const int acl_type, const struct nls_table *nls_codepage, 311362306a36Sopenharmony_ci int remap) 311462306a36Sopenharmony_ci{ 311562306a36Sopenharmony_ci struct smb_com_transaction2_spi_req *pSMB = NULL; 311662306a36Sopenharmony_ci struct smb_com_transaction2_spi_rsp *pSMBr = NULL; 311762306a36Sopenharmony_ci char *parm_data; 311862306a36Sopenharmony_ci int name_len; 311962306a36Sopenharmony_ci int rc = 0; 312062306a36Sopenharmony_ci int bytes_returned = 0; 312162306a36Sopenharmony_ci __u16 params, byte_count, data_count, param_offset, offset; 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName); 312462306a36Sopenharmony_cisetAclRetry: 312562306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 312662306a36Sopenharmony_ci (void **) &pSMBr); 312762306a36Sopenharmony_ci if (rc) 312862306a36Sopenharmony_ci return rc; 312962306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 313062306a36Sopenharmony_ci name_len = 313162306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, 313262306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 313362306a36Sopenharmony_ci name_len++; /* trailing null */ 313462306a36Sopenharmony_ci name_len *= 2; 313562306a36Sopenharmony_ci } else { 313662306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, fileName); 313762306a36Sopenharmony_ci } 313862306a36Sopenharmony_ci params = 6 + name_len; 313962306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 314062306a36Sopenharmony_ci /* BB find max SMB size from sess */ 314162306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 314262306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 314362306a36Sopenharmony_ci pSMB->Reserved = 0; 314462306a36Sopenharmony_ci pSMB->Flags = 0; 314562306a36Sopenharmony_ci pSMB->Timeout = 0; 314662306a36Sopenharmony_ci pSMB->Reserved2 = 0; 314762306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_spi_req, 314862306a36Sopenharmony_ci InformationLevel) - 4; 314962306a36Sopenharmony_ci offset = param_offset + params; 315062306a36Sopenharmony_ci parm_data = ((char *)pSMB) + sizeof(pSMB->hdr.smb_buf_length) + offset; 315162306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci /* convert to on the wire format for POSIX ACL */ 315462306a36Sopenharmony_ci data_count = posix_acl_to_cifs(parm_data, acl, acl_type); 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci if (data_count == 0) { 315762306a36Sopenharmony_ci rc = -EOPNOTSUPP; 315862306a36Sopenharmony_ci goto setACLerrorExit; 315962306a36Sopenharmony_ci } 316062306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 316162306a36Sopenharmony_ci pSMB->SetupCount = 1; 316262306a36Sopenharmony_ci pSMB->Reserved3 = 0; 316362306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); 316462306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL); 316562306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + data_count; 316662306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(data_count); 316762306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 316862306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 316962306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 317062306a36Sopenharmony_ci pSMB->Reserved4 = 0; 317162306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 317262306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 317362306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 317462306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 317562306a36Sopenharmony_ci if (rc) 317662306a36Sopenharmony_ci cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc); 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_cisetACLerrorExit: 317962306a36Sopenharmony_ci cifs_buf_release(pSMB); 318062306a36Sopenharmony_ci if (rc == -EAGAIN) 318162306a36Sopenharmony_ci goto setAclRetry; 318262306a36Sopenharmony_ci return rc; 318362306a36Sopenharmony_ci} 318462306a36Sopenharmony_ci#else 318562306a36Sopenharmony_ciint cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon, 318662306a36Sopenharmony_ci const unsigned char *searchName, struct posix_acl **acl, 318762306a36Sopenharmony_ci const int acl_type, const struct nls_table *nls_codepage, 318862306a36Sopenharmony_ci int remap) 318962306a36Sopenharmony_ci{ 319062306a36Sopenharmony_ci return -EOPNOTSUPP; 319162306a36Sopenharmony_ci} 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ciint cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon, 319462306a36Sopenharmony_ci const unsigned char *fileName, const struct posix_acl *acl, 319562306a36Sopenharmony_ci const int acl_type, const struct nls_table *nls_codepage, 319662306a36Sopenharmony_ci int remap) 319762306a36Sopenharmony_ci{ 319862306a36Sopenharmony_ci return -EOPNOTSUPP; 319962306a36Sopenharmony_ci} 320062306a36Sopenharmony_ci#endif /* CONFIG_FS_POSIX_ACL */ 320162306a36Sopenharmony_ci 320262306a36Sopenharmony_ciint 320362306a36Sopenharmony_ciCIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon, 320462306a36Sopenharmony_ci const int netfid, __u64 *pExtAttrBits, __u64 *pMask) 320562306a36Sopenharmony_ci{ 320662306a36Sopenharmony_ci int rc = 0; 320762306a36Sopenharmony_ci struct smb_t2_qfi_req *pSMB = NULL; 320862306a36Sopenharmony_ci struct smb_t2_qfi_rsp *pSMBr = NULL; 320962306a36Sopenharmony_ci int bytes_returned; 321062306a36Sopenharmony_ci __u16 params, byte_count; 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ci cifs_dbg(FYI, "In GetExtAttr\n"); 321362306a36Sopenharmony_ci if (tcon == NULL) 321462306a36Sopenharmony_ci return -ENODEV; 321562306a36Sopenharmony_ci 321662306a36Sopenharmony_ciGetExtAttrRetry: 321762306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 321862306a36Sopenharmony_ci (void **) &pSMBr); 321962306a36Sopenharmony_ci if (rc) 322062306a36Sopenharmony_ci return rc; 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci params = 2 /* level */ + 2 /* fid */; 322362306a36Sopenharmony_ci pSMB->t2.TotalDataCount = 0; 322462306a36Sopenharmony_ci pSMB->t2.MaxParameterCount = cpu_to_le16(4); 322562306a36Sopenharmony_ci /* BB find exact max data count below from sess structure BB */ 322662306a36Sopenharmony_ci pSMB->t2.MaxDataCount = cpu_to_le16(4000); 322762306a36Sopenharmony_ci pSMB->t2.MaxSetupCount = 0; 322862306a36Sopenharmony_ci pSMB->t2.Reserved = 0; 322962306a36Sopenharmony_ci pSMB->t2.Flags = 0; 323062306a36Sopenharmony_ci pSMB->t2.Timeout = 0; 323162306a36Sopenharmony_ci pSMB->t2.Reserved2 = 0; 323262306a36Sopenharmony_ci pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, 323362306a36Sopenharmony_ci Fid) - 4); 323462306a36Sopenharmony_ci pSMB->t2.DataCount = 0; 323562306a36Sopenharmony_ci pSMB->t2.DataOffset = 0; 323662306a36Sopenharmony_ci pSMB->t2.SetupCount = 1; 323762306a36Sopenharmony_ci pSMB->t2.Reserved3 = 0; 323862306a36Sopenharmony_ci pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); 323962306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 324062306a36Sopenharmony_ci pSMB->t2.TotalParameterCount = cpu_to_le16(params); 324162306a36Sopenharmony_ci pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; 324262306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS); 324362306a36Sopenharmony_ci pSMB->Pad = 0; 324462306a36Sopenharmony_ci pSMB->Fid = netfid; 324562306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 324662306a36Sopenharmony_ci pSMB->t2.ByteCount = cpu_to_le16(byte_count); 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 324962306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 325062306a36Sopenharmony_ci if (rc) { 325162306a36Sopenharmony_ci cifs_dbg(FYI, "error %d in GetExtAttr\n", rc); 325262306a36Sopenharmony_ci } else { 325362306a36Sopenharmony_ci /* decode response */ 325462306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 325562306a36Sopenharmony_ci /* BB also check enough total bytes returned */ 325662306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 2) 325762306a36Sopenharmony_ci /* If rc should we check for EOPNOSUPP and 325862306a36Sopenharmony_ci disable the srvino flag? or in caller? */ 325962306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 326062306a36Sopenharmony_ci else { 326162306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 326262306a36Sopenharmony_ci __u16 count = le16_to_cpu(pSMBr->t2.DataCount); 326362306a36Sopenharmony_ci struct file_chattr_info *pfinfo; 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci if (count != 16) { 326662306a36Sopenharmony_ci cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n"); 326762306a36Sopenharmony_ci rc = -EIO; 326862306a36Sopenharmony_ci goto GetExtAttrOut; 326962306a36Sopenharmony_ci } 327062306a36Sopenharmony_ci pfinfo = (struct file_chattr_info *) 327162306a36Sopenharmony_ci (data_offset + (char *) &pSMBr->hdr.Protocol); 327262306a36Sopenharmony_ci *pExtAttrBits = le64_to_cpu(pfinfo->mode); 327362306a36Sopenharmony_ci *pMask = le64_to_cpu(pfinfo->mask); 327462306a36Sopenharmony_ci } 327562306a36Sopenharmony_ci } 327662306a36Sopenharmony_ciGetExtAttrOut: 327762306a36Sopenharmony_ci cifs_buf_release(pSMB); 327862306a36Sopenharmony_ci if (rc == -EAGAIN) 327962306a36Sopenharmony_ci goto GetExtAttrRetry; 328062306a36Sopenharmony_ci return rc; 328162306a36Sopenharmony_ci} 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_ci#endif /* CONFIG_POSIX */ 328462306a36Sopenharmony_ci 328562306a36Sopenharmony_ci/* 328662306a36Sopenharmony_ci * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that 328762306a36Sopenharmony_ci * all NT TRANSACTS that we init here have total parm and data under about 400 328862306a36Sopenharmony_ci * bytes (to fit in small cifs buffer size), which is the case so far, it 328962306a36Sopenharmony_ci * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of 329062306a36Sopenharmony_ci * returned setup area) and MaxParameterCount (returned parms size) must be set 329162306a36Sopenharmony_ci * by caller 329262306a36Sopenharmony_ci */ 329362306a36Sopenharmony_cistatic int 329462306a36Sopenharmony_cismb_init_nttransact(const __u16 sub_command, const int setup_count, 329562306a36Sopenharmony_ci const int parm_len, struct cifs_tcon *tcon, 329662306a36Sopenharmony_ci void **ret_buf) 329762306a36Sopenharmony_ci{ 329862306a36Sopenharmony_ci int rc; 329962306a36Sopenharmony_ci __u32 temp_offset; 330062306a36Sopenharmony_ci struct smb_com_ntransact_req *pSMB; 330162306a36Sopenharmony_ci 330262306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, 330362306a36Sopenharmony_ci (void **)&pSMB); 330462306a36Sopenharmony_ci if (rc) 330562306a36Sopenharmony_ci return rc; 330662306a36Sopenharmony_ci *ret_buf = (void *)pSMB; 330762306a36Sopenharmony_ci pSMB->Reserved = 0; 330862306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le32(parm_len); 330962306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 331062306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); 331162306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 331262306a36Sopenharmony_ci pSMB->DataCount = pSMB->TotalDataCount; 331362306a36Sopenharmony_ci temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + 331462306a36Sopenharmony_ci (setup_count * 2) - 4 /* for rfc1001 length itself */; 331562306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le32(temp_offset); 331662306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); 331762306a36Sopenharmony_ci pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ 331862306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(sub_command); 331962306a36Sopenharmony_ci return 0; 332062306a36Sopenharmony_ci} 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_cistatic int 332362306a36Sopenharmony_civalidate_ntransact(char *buf, char **ppparm, char **ppdata, 332462306a36Sopenharmony_ci __u32 *pparmlen, __u32 *pdatalen) 332562306a36Sopenharmony_ci{ 332662306a36Sopenharmony_ci char *end_of_smb; 332762306a36Sopenharmony_ci __u32 data_count, data_offset, parm_count, parm_offset; 332862306a36Sopenharmony_ci struct smb_com_ntransact_rsp *pSMBr; 332962306a36Sopenharmony_ci u16 bcc; 333062306a36Sopenharmony_ci 333162306a36Sopenharmony_ci *pdatalen = 0; 333262306a36Sopenharmony_ci *pparmlen = 0; 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci if (buf == NULL) 333562306a36Sopenharmony_ci return -EINVAL; 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci pSMBr = (struct smb_com_ntransact_rsp *)buf; 333862306a36Sopenharmony_ci 333962306a36Sopenharmony_ci bcc = get_bcc(&pSMBr->hdr); 334062306a36Sopenharmony_ci end_of_smb = 2 /* sizeof byte count */ + bcc + 334162306a36Sopenharmony_ci (char *)&pSMBr->ByteCount; 334262306a36Sopenharmony_ci 334362306a36Sopenharmony_ci data_offset = le32_to_cpu(pSMBr->DataOffset); 334462306a36Sopenharmony_ci data_count = le32_to_cpu(pSMBr->DataCount); 334562306a36Sopenharmony_ci parm_offset = le32_to_cpu(pSMBr->ParameterOffset); 334662306a36Sopenharmony_ci parm_count = le32_to_cpu(pSMBr->ParameterCount); 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; 334962306a36Sopenharmony_ci *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci /* should we also check that parm and data areas do not overlap? */ 335262306a36Sopenharmony_ci if (*ppparm > end_of_smb) { 335362306a36Sopenharmony_ci cifs_dbg(FYI, "parms start after end of smb\n"); 335462306a36Sopenharmony_ci return -EINVAL; 335562306a36Sopenharmony_ci } else if (parm_count + *ppparm > end_of_smb) { 335662306a36Sopenharmony_ci cifs_dbg(FYI, "parm end after end of smb\n"); 335762306a36Sopenharmony_ci return -EINVAL; 335862306a36Sopenharmony_ci } else if (*ppdata > end_of_smb) { 335962306a36Sopenharmony_ci cifs_dbg(FYI, "data starts after end of smb\n"); 336062306a36Sopenharmony_ci return -EINVAL; 336162306a36Sopenharmony_ci } else if (data_count + *ppdata > end_of_smb) { 336262306a36Sopenharmony_ci cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n", 336362306a36Sopenharmony_ci *ppdata, data_count, (data_count + *ppdata), 336462306a36Sopenharmony_ci end_of_smb, pSMBr); 336562306a36Sopenharmony_ci return -EINVAL; 336662306a36Sopenharmony_ci } else if (parm_count + data_count > bcc) { 336762306a36Sopenharmony_ci cifs_dbg(FYI, "parm count and data count larger than SMB\n"); 336862306a36Sopenharmony_ci return -EINVAL; 336962306a36Sopenharmony_ci } 337062306a36Sopenharmony_ci *pdatalen = data_count; 337162306a36Sopenharmony_ci *pparmlen = parm_count; 337262306a36Sopenharmony_ci return 0; 337362306a36Sopenharmony_ci} 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci/* Get Security Descriptor (by handle) from remote server for a file or dir */ 337662306a36Sopenharmony_ciint 337762306a36Sopenharmony_ciCIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, 337862306a36Sopenharmony_ci struct cifs_ntsd **acl_inf, __u32 *pbuflen) 337962306a36Sopenharmony_ci{ 338062306a36Sopenharmony_ci int rc = 0; 338162306a36Sopenharmony_ci int buf_type = 0; 338262306a36Sopenharmony_ci QUERY_SEC_DESC_REQ *pSMB; 338362306a36Sopenharmony_ci struct kvec iov[1]; 338462306a36Sopenharmony_ci struct kvec rsp_iov; 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci cifs_dbg(FYI, "GetCifsACL\n"); 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci *pbuflen = 0; 338962306a36Sopenharmony_ci *acl_inf = NULL; 339062306a36Sopenharmony_ci 339162306a36Sopenharmony_ci rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 339262306a36Sopenharmony_ci 8 /* parm len */, tcon, (void **) &pSMB); 339362306a36Sopenharmony_ci if (rc) 339462306a36Sopenharmony_ci return rc; 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le32(4); 339762306a36Sopenharmony_ci /* BB TEST with big acls that might need to be e.g. larger than 16K */ 339862306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 339962306a36Sopenharmony_ci pSMB->Fid = fid; /* file handle always le */ 340062306a36Sopenharmony_ci pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP | 340162306a36Sopenharmony_ci CIFS_ACL_DACL); 340262306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */ 340362306a36Sopenharmony_ci inc_rfc1001_len(pSMB, 11); 340462306a36Sopenharmony_ci iov[0].iov_base = (char *)pSMB; 340562306a36Sopenharmony_ci iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 340862306a36Sopenharmony_ci 0, &rsp_iov); 340962306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 341062306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get); 341162306a36Sopenharmony_ci if (rc) { 341262306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc); 341362306a36Sopenharmony_ci } else { /* decode response */ 341462306a36Sopenharmony_ci __le32 *parm; 341562306a36Sopenharmony_ci __u32 parm_len; 341662306a36Sopenharmony_ci __u32 acl_len; 341762306a36Sopenharmony_ci struct smb_com_ntransact_rsp *pSMBr; 341862306a36Sopenharmony_ci char *pdata; 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci/* validate_nttransact */ 342162306a36Sopenharmony_ci rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm, 342262306a36Sopenharmony_ci &pdata, &parm_len, pbuflen); 342362306a36Sopenharmony_ci if (rc) 342462306a36Sopenharmony_ci goto qsec_out; 342562306a36Sopenharmony_ci pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base; 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci cifs_dbg(FYI, "smb %p parm %p data %p\n", 342862306a36Sopenharmony_ci pSMBr, parm, *acl_inf); 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci if (le32_to_cpu(pSMBr->ParameterCount) != 4) { 343162306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 343262306a36Sopenharmony_ci *pbuflen = 0; 343362306a36Sopenharmony_ci goto qsec_out; 343462306a36Sopenharmony_ci } 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci/* BB check that data area is minimum length and as big as acl_len */ 343762306a36Sopenharmony_ci 343862306a36Sopenharmony_ci acl_len = le32_to_cpu(*parm); 343962306a36Sopenharmony_ci if (acl_len != *pbuflen) { 344062306a36Sopenharmony_ci cifs_dbg(VFS, "acl length %d does not match %d\n", 344162306a36Sopenharmony_ci acl_len, *pbuflen); 344262306a36Sopenharmony_ci if (*pbuflen > acl_len) 344362306a36Sopenharmony_ci *pbuflen = acl_len; 344462306a36Sopenharmony_ci } 344562306a36Sopenharmony_ci 344662306a36Sopenharmony_ci /* check if buffer is big enough for the acl 344762306a36Sopenharmony_ci header followed by the smallest SID */ 344862306a36Sopenharmony_ci if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) || 344962306a36Sopenharmony_ci (*pbuflen >= 64 * 1024)) { 345062306a36Sopenharmony_ci cifs_dbg(VFS, "bad acl length %d\n", *pbuflen); 345162306a36Sopenharmony_ci rc = -EINVAL; 345262306a36Sopenharmony_ci *pbuflen = 0; 345362306a36Sopenharmony_ci } else { 345462306a36Sopenharmony_ci *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL); 345562306a36Sopenharmony_ci if (*acl_inf == NULL) { 345662306a36Sopenharmony_ci *pbuflen = 0; 345762306a36Sopenharmony_ci rc = -ENOMEM; 345862306a36Sopenharmony_ci } 345962306a36Sopenharmony_ci } 346062306a36Sopenharmony_ci } 346162306a36Sopenharmony_ciqsec_out: 346262306a36Sopenharmony_ci free_rsp_buf(buf_type, rsp_iov.iov_base); 346362306a36Sopenharmony_ci return rc; 346462306a36Sopenharmony_ci} 346562306a36Sopenharmony_ci 346662306a36Sopenharmony_ciint 346762306a36Sopenharmony_ciCIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, 346862306a36Sopenharmony_ci struct cifs_ntsd *pntsd, __u32 acllen, int aclflag) 346962306a36Sopenharmony_ci{ 347062306a36Sopenharmony_ci __u16 byte_count, param_count, data_count, param_offset, data_offset; 347162306a36Sopenharmony_ci int rc = 0; 347262306a36Sopenharmony_ci int bytes_returned = 0; 347362306a36Sopenharmony_ci SET_SEC_DESC_REQ *pSMB = NULL; 347462306a36Sopenharmony_ci void *pSMBr; 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_cisetCifsAclRetry: 347762306a36Sopenharmony_ci rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr); 347862306a36Sopenharmony_ci if (rc) 347962306a36Sopenharmony_ci return rc; 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 348262306a36Sopenharmony_ci pSMB->Reserved = 0; 348362306a36Sopenharmony_ci 348462306a36Sopenharmony_ci param_count = 8; 348562306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4; 348662306a36Sopenharmony_ci data_count = acllen; 348762306a36Sopenharmony_ci data_offset = param_offset + param_count; 348862306a36Sopenharmony_ci byte_count = 3 /* pad */ + param_count; 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le32(data_count); 349162306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 349262306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le32(4); 349362306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le32(16384); 349462306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le32(param_count); 349562306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le32(param_offset); 349662306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 349762306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le32(data_offset); 349862306a36Sopenharmony_ci pSMB->SetupCount = 0; 349962306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC); 350062306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count+data_count); 350162306a36Sopenharmony_ci 350262306a36Sopenharmony_ci pSMB->Fid = fid; /* file handle always le */ 350362306a36Sopenharmony_ci pSMB->Reserved2 = 0; 350462306a36Sopenharmony_ci pSMB->AclFlags = cpu_to_le32(aclflag); 350562306a36Sopenharmony_ci 350662306a36Sopenharmony_ci if (pntsd && acllen) { 350762306a36Sopenharmony_ci memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) + 350862306a36Sopenharmony_ci data_offset, pntsd, acllen); 350962306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count + data_count); 351062306a36Sopenharmony_ci } else 351162306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 351462306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_ci cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n", 351762306a36Sopenharmony_ci bytes_returned, rc); 351862306a36Sopenharmony_ci if (rc) 351962306a36Sopenharmony_ci cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc); 352062306a36Sopenharmony_ci cifs_buf_release(pSMB); 352162306a36Sopenharmony_ci 352262306a36Sopenharmony_ci if (rc == -EAGAIN) 352362306a36Sopenharmony_ci goto setCifsAclRetry; 352462306a36Sopenharmony_ci 352562306a36Sopenharmony_ci return (rc); 352662306a36Sopenharmony_ci} 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci 352962306a36Sopenharmony_ci/* Legacy Query Path Information call for lookup to old servers such 353062306a36Sopenharmony_ci as Win9x/WinME */ 353162306a36Sopenharmony_ciint 353262306a36Sopenharmony_ciSMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon, 353362306a36Sopenharmony_ci const char *search_name, FILE_ALL_INFO *data, 353462306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 353562306a36Sopenharmony_ci{ 353662306a36Sopenharmony_ci QUERY_INFORMATION_REQ *pSMB; 353762306a36Sopenharmony_ci QUERY_INFORMATION_RSP *pSMBr; 353862306a36Sopenharmony_ci int rc = 0; 353962306a36Sopenharmony_ci int bytes_returned; 354062306a36Sopenharmony_ci int name_len; 354162306a36Sopenharmony_ci 354262306a36Sopenharmony_ci cifs_dbg(FYI, "In SMBQPath path %s\n", search_name); 354362306a36Sopenharmony_ciQInfRetry: 354462306a36Sopenharmony_ci rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB, 354562306a36Sopenharmony_ci (void **) &pSMBr); 354662306a36Sopenharmony_ci if (rc) 354762306a36Sopenharmony_ci return rc; 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 355062306a36Sopenharmony_ci name_len = 355162306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, 355262306a36Sopenharmony_ci search_name, PATH_MAX, nls_codepage, 355362306a36Sopenharmony_ci remap); 355462306a36Sopenharmony_ci name_len++; /* trailing null */ 355562306a36Sopenharmony_ci name_len *= 2; 355662306a36Sopenharmony_ci } else { 355762306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, search_name); 355862306a36Sopenharmony_ci } 355962306a36Sopenharmony_ci pSMB->BufferFormat = 0x04; 356062306a36Sopenharmony_ci name_len++; /* account for buffer type byte */ 356162306a36Sopenharmony_ci inc_rfc1001_len(pSMB, (__u16)name_len); 356262306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(name_len); 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 356562306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 356662306a36Sopenharmony_ci if (rc) { 356762306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc); 356862306a36Sopenharmony_ci } else if (data) { 356962306a36Sopenharmony_ci struct timespec64 ts; 357062306a36Sopenharmony_ci __u32 time = le32_to_cpu(pSMBr->last_write_time); 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci /* decode response */ 357362306a36Sopenharmony_ci /* BB FIXME - add time zone adjustment BB */ 357462306a36Sopenharmony_ci memset(data, 0, sizeof(FILE_ALL_INFO)); 357562306a36Sopenharmony_ci ts.tv_nsec = 0; 357662306a36Sopenharmony_ci ts.tv_sec = time; 357762306a36Sopenharmony_ci /* decode time fields */ 357862306a36Sopenharmony_ci data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts)); 357962306a36Sopenharmony_ci data->LastWriteTime = data->ChangeTime; 358062306a36Sopenharmony_ci data->LastAccessTime = 0; 358162306a36Sopenharmony_ci data->AllocationSize = 358262306a36Sopenharmony_ci cpu_to_le64(le32_to_cpu(pSMBr->size)); 358362306a36Sopenharmony_ci data->EndOfFile = data->AllocationSize; 358462306a36Sopenharmony_ci data->Attributes = 358562306a36Sopenharmony_ci cpu_to_le32(le16_to_cpu(pSMBr->attr)); 358662306a36Sopenharmony_ci } else 358762306a36Sopenharmony_ci rc = -EIO; /* bad buffer passed in */ 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_ci cifs_buf_release(pSMB); 359062306a36Sopenharmony_ci 359162306a36Sopenharmony_ci if (rc == -EAGAIN) 359262306a36Sopenharmony_ci goto QInfRetry; 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci return rc; 359562306a36Sopenharmony_ci} 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_ciint 359862306a36Sopenharmony_ciCIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, 359962306a36Sopenharmony_ci u16 netfid, FILE_ALL_INFO *pFindData) 360062306a36Sopenharmony_ci{ 360162306a36Sopenharmony_ci struct smb_t2_qfi_req *pSMB = NULL; 360262306a36Sopenharmony_ci struct smb_t2_qfi_rsp *pSMBr = NULL; 360362306a36Sopenharmony_ci int rc = 0; 360462306a36Sopenharmony_ci int bytes_returned; 360562306a36Sopenharmony_ci __u16 params, byte_count; 360662306a36Sopenharmony_ci 360762306a36Sopenharmony_ciQFileInfoRetry: 360862306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 360962306a36Sopenharmony_ci (void **) &pSMBr); 361062306a36Sopenharmony_ci if (rc) 361162306a36Sopenharmony_ci return rc; 361262306a36Sopenharmony_ci 361362306a36Sopenharmony_ci params = 2 /* level */ + 2 /* fid */; 361462306a36Sopenharmony_ci pSMB->t2.TotalDataCount = 0; 361562306a36Sopenharmony_ci pSMB->t2.MaxParameterCount = cpu_to_le16(4); 361662306a36Sopenharmony_ci /* BB find exact max data count below from sess structure BB */ 361762306a36Sopenharmony_ci pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize); 361862306a36Sopenharmony_ci pSMB->t2.MaxSetupCount = 0; 361962306a36Sopenharmony_ci pSMB->t2.Reserved = 0; 362062306a36Sopenharmony_ci pSMB->t2.Flags = 0; 362162306a36Sopenharmony_ci pSMB->t2.Timeout = 0; 362262306a36Sopenharmony_ci pSMB->t2.Reserved2 = 0; 362362306a36Sopenharmony_ci pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, 362462306a36Sopenharmony_ci Fid) - 4); 362562306a36Sopenharmony_ci pSMB->t2.DataCount = 0; 362662306a36Sopenharmony_ci pSMB->t2.DataOffset = 0; 362762306a36Sopenharmony_ci pSMB->t2.SetupCount = 1; 362862306a36Sopenharmony_ci pSMB->t2.Reserved3 = 0; 362962306a36Sopenharmony_ci pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); 363062306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 363162306a36Sopenharmony_ci pSMB->t2.TotalParameterCount = cpu_to_le16(params); 363262306a36Sopenharmony_ci pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; 363362306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); 363462306a36Sopenharmony_ci pSMB->Pad = 0; 363562306a36Sopenharmony_ci pSMB->Fid = netfid; 363662306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 363762306a36Sopenharmony_ci pSMB->t2.ByteCount = cpu_to_le16(byte_count); 363862306a36Sopenharmony_ci 363962306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 364062306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 364162306a36Sopenharmony_ci if (rc) { 364262306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc); 364362306a36Sopenharmony_ci } else { /* decode response */ 364462306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 364562306a36Sopenharmony_ci 364662306a36Sopenharmony_ci if (rc) /* BB add auto retry on EOPNOTSUPP? */ 364762306a36Sopenharmony_ci rc = -EIO; 364862306a36Sopenharmony_ci else if (get_bcc(&pSMBr->hdr) < 40) 364962306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 365062306a36Sopenharmony_ci else if (pFindData) { 365162306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 365262306a36Sopenharmony_ci memcpy((char *) pFindData, 365362306a36Sopenharmony_ci (char *) &pSMBr->hdr.Protocol + 365462306a36Sopenharmony_ci data_offset, sizeof(FILE_ALL_INFO)); 365562306a36Sopenharmony_ci } else 365662306a36Sopenharmony_ci rc = -ENOMEM; 365762306a36Sopenharmony_ci } 365862306a36Sopenharmony_ci cifs_buf_release(pSMB); 365962306a36Sopenharmony_ci if (rc == -EAGAIN) 366062306a36Sopenharmony_ci goto QFileInfoRetry; 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci return rc; 366362306a36Sopenharmony_ci} 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ciint 366662306a36Sopenharmony_ciCIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, 366762306a36Sopenharmony_ci const char *search_name, FILE_ALL_INFO *data, 366862306a36Sopenharmony_ci int legacy /* old style infolevel */, 366962306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 367062306a36Sopenharmony_ci{ 367162306a36Sopenharmony_ci /* level 263 SMB_QUERY_FILE_ALL_INFO */ 367262306a36Sopenharmony_ci TRANSACTION2_QPI_REQ *pSMB = NULL; 367362306a36Sopenharmony_ci TRANSACTION2_QPI_RSP *pSMBr = NULL; 367462306a36Sopenharmony_ci int rc = 0; 367562306a36Sopenharmony_ci int bytes_returned; 367662306a36Sopenharmony_ci int name_len; 367762306a36Sopenharmony_ci __u16 params, byte_count; 367862306a36Sopenharmony_ci 367962306a36Sopenharmony_ci /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */ 368062306a36Sopenharmony_ciQPathInfoRetry: 368162306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 368262306a36Sopenharmony_ci (void **) &pSMBr); 368362306a36Sopenharmony_ci if (rc) 368462306a36Sopenharmony_ci return rc; 368562306a36Sopenharmony_ci 368662306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 368762306a36Sopenharmony_ci name_len = 368862306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name, 368962306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 369062306a36Sopenharmony_ci name_len++; /* trailing null */ 369162306a36Sopenharmony_ci name_len *= 2; 369262306a36Sopenharmony_ci } else { 369362306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, search_name); 369462306a36Sopenharmony_ci } 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; 369762306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 369862306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 369962306a36Sopenharmony_ci /* BB find exact max SMB PDU from sess structure BB */ 370062306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(4000); 370162306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 370262306a36Sopenharmony_ci pSMB->Reserved = 0; 370362306a36Sopenharmony_ci pSMB->Flags = 0; 370462306a36Sopenharmony_ci pSMB->Timeout = 0; 370562306a36Sopenharmony_ci pSMB->Reserved2 = 0; 370662306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof( 370762306a36Sopenharmony_ci struct smb_com_transaction2_qpi_req, InformationLevel) - 4); 370862306a36Sopenharmony_ci pSMB->DataCount = 0; 370962306a36Sopenharmony_ci pSMB->DataOffset = 0; 371062306a36Sopenharmony_ci pSMB->SetupCount = 1; 371162306a36Sopenharmony_ci pSMB->Reserved3 = 0; 371262306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); 371362306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 371462306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 371562306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 371662306a36Sopenharmony_ci if (legacy) 371762306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD); 371862306a36Sopenharmony_ci else 371962306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); 372062306a36Sopenharmony_ci pSMB->Reserved4 = 0; 372162306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 372262306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 372362306a36Sopenharmony_ci 372462306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 372562306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 372662306a36Sopenharmony_ci if (rc) { 372762306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc); 372862306a36Sopenharmony_ci } else { /* decode response */ 372962306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci if (rc) /* BB add auto retry on EOPNOTSUPP? */ 373262306a36Sopenharmony_ci rc = -EIO; 373362306a36Sopenharmony_ci else if (!legacy && get_bcc(&pSMBr->hdr) < 40) 373462306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 373562306a36Sopenharmony_ci else if (legacy && get_bcc(&pSMBr->hdr) < 24) 373662306a36Sopenharmony_ci rc = -EIO; /* 24 or 26 expected but we do not read 373762306a36Sopenharmony_ci last field */ 373862306a36Sopenharmony_ci else if (data) { 373962306a36Sopenharmony_ci int size; 374062306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 374162306a36Sopenharmony_ci 374262306a36Sopenharmony_ci /* 374362306a36Sopenharmony_ci * On legacy responses we do not read the last field, 374462306a36Sopenharmony_ci * EAsize, fortunately since it varies by subdialect and 374562306a36Sopenharmony_ci * also note it differs on Set vs Get, ie two bytes or 4 374662306a36Sopenharmony_ci * bytes depending but we don't care here. 374762306a36Sopenharmony_ci */ 374862306a36Sopenharmony_ci if (legacy) 374962306a36Sopenharmony_ci size = sizeof(FILE_INFO_STANDARD); 375062306a36Sopenharmony_ci else 375162306a36Sopenharmony_ci size = sizeof(FILE_ALL_INFO); 375262306a36Sopenharmony_ci memcpy((char *) data, (char *) &pSMBr->hdr.Protocol + 375362306a36Sopenharmony_ci data_offset, size); 375462306a36Sopenharmony_ci } else 375562306a36Sopenharmony_ci rc = -ENOMEM; 375662306a36Sopenharmony_ci } 375762306a36Sopenharmony_ci cifs_buf_release(pSMB); 375862306a36Sopenharmony_ci if (rc == -EAGAIN) 375962306a36Sopenharmony_ci goto QPathInfoRetry; 376062306a36Sopenharmony_ci 376162306a36Sopenharmony_ci return rc; 376262306a36Sopenharmony_ci} 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_ciint 376562306a36Sopenharmony_ciCIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, 376662306a36Sopenharmony_ci u16 netfid, FILE_UNIX_BASIC_INFO *pFindData) 376762306a36Sopenharmony_ci{ 376862306a36Sopenharmony_ci struct smb_t2_qfi_req *pSMB = NULL; 376962306a36Sopenharmony_ci struct smb_t2_qfi_rsp *pSMBr = NULL; 377062306a36Sopenharmony_ci int rc = 0; 377162306a36Sopenharmony_ci int bytes_returned; 377262306a36Sopenharmony_ci __u16 params, byte_count; 377362306a36Sopenharmony_ci 377462306a36Sopenharmony_ciUnixQFileInfoRetry: 377562306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 377662306a36Sopenharmony_ci (void **) &pSMBr); 377762306a36Sopenharmony_ci if (rc) 377862306a36Sopenharmony_ci return rc; 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci params = 2 /* level */ + 2 /* fid */; 378162306a36Sopenharmony_ci pSMB->t2.TotalDataCount = 0; 378262306a36Sopenharmony_ci pSMB->t2.MaxParameterCount = cpu_to_le16(4); 378362306a36Sopenharmony_ci /* BB find exact max data count below from sess structure BB */ 378462306a36Sopenharmony_ci pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize); 378562306a36Sopenharmony_ci pSMB->t2.MaxSetupCount = 0; 378662306a36Sopenharmony_ci pSMB->t2.Reserved = 0; 378762306a36Sopenharmony_ci pSMB->t2.Flags = 0; 378862306a36Sopenharmony_ci pSMB->t2.Timeout = 0; 378962306a36Sopenharmony_ci pSMB->t2.Reserved2 = 0; 379062306a36Sopenharmony_ci pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, 379162306a36Sopenharmony_ci Fid) - 4); 379262306a36Sopenharmony_ci pSMB->t2.DataCount = 0; 379362306a36Sopenharmony_ci pSMB->t2.DataOffset = 0; 379462306a36Sopenharmony_ci pSMB->t2.SetupCount = 1; 379562306a36Sopenharmony_ci pSMB->t2.Reserved3 = 0; 379662306a36Sopenharmony_ci pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); 379762306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 379862306a36Sopenharmony_ci pSMB->t2.TotalParameterCount = cpu_to_le16(params); 379962306a36Sopenharmony_ci pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; 380062306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); 380162306a36Sopenharmony_ci pSMB->Pad = 0; 380262306a36Sopenharmony_ci pSMB->Fid = netfid; 380362306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 380462306a36Sopenharmony_ci pSMB->t2.ByteCount = cpu_to_le16(byte_count); 380562306a36Sopenharmony_ci 380662306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 380762306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 380862306a36Sopenharmony_ci if (rc) { 380962306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc); 381062306a36Sopenharmony_ci } else { /* decode response */ 381162306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 381262306a36Sopenharmony_ci 381362306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { 381462306a36Sopenharmony_ci cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n"); 381562306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 381662306a36Sopenharmony_ci } else { 381762306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 381862306a36Sopenharmony_ci memcpy((char *) pFindData, 381962306a36Sopenharmony_ci (char *) &pSMBr->hdr.Protocol + 382062306a36Sopenharmony_ci data_offset, 382162306a36Sopenharmony_ci sizeof(FILE_UNIX_BASIC_INFO)); 382262306a36Sopenharmony_ci } 382362306a36Sopenharmony_ci } 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci cifs_buf_release(pSMB); 382662306a36Sopenharmony_ci if (rc == -EAGAIN) 382762306a36Sopenharmony_ci goto UnixQFileInfoRetry; 382862306a36Sopenharmony_ci 382962306a36Sopenharmony_ci return rc; 383062306a36Sopenharmony_ci} 383162306a36Sopenharmony_ci 383262306a36Sopenharmony_ciint 383362306a36Sopenharmony_ciCIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, 383462306a36Sopenharmony_ci const unsigned char *searchName, 383562306a36Sopenharmony_ci FILE_UNIX_BASIC_INFO *pFindData, 383662306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 383762306a36Sopenharmony_ci{ 383862306a36Sopenharmony_ci/* SMB_QUERY_FILE_UNIX_BASIC */ 383962306a36Sopenharmony_ci TRANSACTION2_QPI_REQ *pSMB = NULL; 384062306a36Sopenharmony_ci TRANSACTION2_QPI_RSP *pSMBr = NULL; 384162306a36Sopenharmony_ci int rc = 0; 384262306a36Sopenharmony_ci int bytes_returned = 0; 384362306a36Sopenharmony_ci int name_len; 384462306a36Sopenharmony_ci __u16 params, byte_count; 384562306a36Sopenharmony_ci 384662306a36Sopenharmony_ci cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName); 384762306a36Sopenharmony_ciUnixQPathInfoRetry: 384862306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 384962306a36Sopenharmony_ci (void **) &pSMBr); 385062306a36Sopenharmony_ci if (rc) 385162306a36Sopenharmony_ci return rc; 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 385462306a36Sopenharmony_ci name_len = 385562306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, 385662306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 385762306a36Sopenharmony_ci name_len++; /* trailing null */ 385862306a36Sopenharmony_ci name_len *= 2; 385962306a36Sopenharmony_ci } else { 386062306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, searchName); 386162306a36Sopenharmony_ci } 386262306a36Sopenharmony_ci 386362306a36Sopenharmony_ci params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; 386462306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 386562306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 386662306a36Sopenharmony_ci /* BB find exact max SMB PDU from sess structure BB */ 386762306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(4000); 386862306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 386962306a36Sopenharmony_ci pSMB->Reserved = 0; 387062306a36Sopenharmony_ci pSMB->Flags = 0; 387162306a36Sopenharmony_ci pSMB->Timeout = 0; 387262306a36Sopenharmony_ci pSMB->Reserved2 = 0; 387362306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof( 387462306a36Sopenharmony_ci struct smb_com_transaction2_qpi_req, InformationLevel) - 4); 387562306a36Sopenharmony_ci pSMB->DataCount = 0; 387662306a36Sopenharmony_ci pSMB->DataOffset = 0; 387762306a36Sopenharmony_ci pSMB->SetupCount = 1; 387862306a36Sopenharmony_ci pSMB->Reserved3 = 0; 387962306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); 388062306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 388162306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 388262306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 388362306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); 388462306a36Sopenharmony_ci pSMB->Reserved4 = 0; 388562306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 388662306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 388762306a36Sopenharmony_ci 388862306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 388962306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 389062306a36Sopenharmony_ci if (rc) { 389162306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc); 389262306a36Sopenharmony_ci } else { /* decode response */ 389362306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { 389662306a36Sopenharmony_ci cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n"); 389762306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 389862306a36Sopenharmony_ci } else { 389962306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 390062306a36Sopenharmony_ci memcpy((char *) pFindData, 390162306a36Sopenharmony_ci (char *) &pSMBr->hdr.Protocol + 390262306a36Sopenharmony_ci data_offset, 390362306a36Sopenharmony_ci sizeof(FILE_UNIX_BASIC_INFO)); 390462306a36Sopenharmony_ci } 390562306a36Sopenharmony_ci } 390662306a36Sopenharmony_ci cifs_buf_release(pSMB); 390762306a36Sopenharmony_ci if (rc == -EAGAIN) 390862306a36Sopenharmony_ci goto UnixQPathInfoRetry; 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_ci return rc; 391162306a36Sopenharmony_ci} 391262306a36Sopenharmony_ci 391362306a36Sopenharmony_ci/* xid, tcon, searchName and codepage are input parms, rest are returned */ 391462306a36Sopenharmony_ciint 391562306a36Sopenharmony_ciCIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, 391662306a36Sopenharmony_ci const char *searchName, struct cifs_sb_info *cifs_sb, 391762306a36Sopenharmony_ci __u16 *pnetfid, __u16 search_flags, 391862306a36Sopenharmony_ci struct cifs_search_info *psrch_inf, bool msearch) 391962306a36Sopenharmony_ci{ 392062306a36Sopenharmony_ci/* level 257 SMB_ */ 392162306a36Sopenharmony_ci TRANSACTION2_FFIRST_REQ *pSMB = NULL; 392262306a36Sopenharmony_ci TRANSACTION2_FFIRST_RSP *pSMBr = NULL; 392362306a36Sopenharmony_ci T2_FFIRST_RSP_PARMS *parms; 392462306a36Sopenharmony_ci struct nls_table *nls_codepage; 392562306a36Sopenharmony_ci unsigned int lnoff; 392662306a36Sopenharmony_ci __u16 params, byte_count; 392762306a36Sopenharmony_ci int bytes_returned = 0; 392862306a36Sopenharmony_ci int name_len, remap; 392962306a36Sopenharmony_ci int rc = 0; 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ci cifs_dbg(FYI, "In FindFirst for %s\n", searchName); 393262306a36Sopenharmony_ci 393362306a36Sopenharmony_cifindFirstRetry: 393462306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 393562306a36Sopenharmony_ci (void **) &pSMBr); 393662306a36Sopenharmony_ci if (rc) 393762306a36Sopenharmony_ci return rc; 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ci nls_codepage = cifs_sb->local_nls; 394062306a36Sopenharmony_ci remap = cifs_remap(cifs_sb); 394162306a36Sopenharmony_ci 394262306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 394362306a36Sopenharmony_ci name_len = 394462306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, 394562306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 394662306a36Sopenharmony_ci /* We can not add the asterik earlier in case 394762306a36Sopenharmony_ci it got remapped to 0xF03A as if it were part of the 394862306a36Sopenharmony_ci directory name instead of a wildcard */ 394962306a36Sopenharmony_ci name_len *= 2; 395062306a36Sopenharmony_ci if (msearch) { 395162306a36Sopenharmony_ci pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb); 395262306a36Sopenharmony_ci pSMB->FileName[name_len+1] = 0; 395362306a36Sopenharmony_ci pSMB->FileName[name_len+2] = '*'; 395462306a36Sopenharmony_ci pSMB->FileName[name_len+3] = 0; 395562306a36Sopenharmony_ci name_len += 4; /* now the trailing null */ 395662306a36Sopenharmony_ci /* null terminate just in case */ 395762306a36Sopenharmony_ci pSMB->FileName[name_len] = 0; 395862306a36Sopenharmony_ci pSMB->FileName[name_len+1] = 0; 395962306a36Sopenharmony_ci name_len += 2; 396062306a36Sopenharmony_ci } 396162306a36Sopenharmony_ci } else { 396262306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, searchName); 396362306a36Sopenharmony_ci if (msearch) { 396462306a36Sopenharmony_ci if (WARN_ON_ONCE(name_len > PATH_MAX-2)) 396562306a36Sopenharmony_ci name_len = PATH_MAX-2; 396662306a36Sopenharmony_ci /* overwrite nul byte */ 396762306a36Sopenharmony_ci pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb); 396862306a36Sopenharmony_ci pSMB->FileName[name_len] = '*'; 396962306a36Sopenharmony_ci pSMB->FileName[name_len+1] = 0; 397062306a36Sopenharmony_ci name_len += 2; 397162306a36Sopenharmony_ci } 397262306a36Sopenharmony_ci } 397362306a36Sopenharmony_ci 397462306a36Sopenharmony_ci params = 12 + name_len /* includes null */ ; 397562306a36Sopenharmony_ci pSMB->TotalDataCount = 0; /* no EAs */ 397662306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(10); 397762306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00); 397862306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 397962306a36Sopenharmony_ci pSMB->Reserved = 0; 398062306a36Sopenharmony_ci pSMB->Flags = 0; 398162306a36Sopenharmony_ci pSMB->Timeout = 0; 398262306a36Sopenharmony_ci pSMB->Reserved2 = 0; 398362306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 398462306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 398562306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 398662306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16( 398762306a36Sopenharmony_ci offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) 398862306a36Sopenharmony_ci - 4); 398962306a36Sopenharmony_ci pSMB->DataCount = 0; 399062306a36Sopenharmony_ci pSMB->DataOffset = 0; 399162306a36Sopenharmony_ci pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */ 399262306a36Sopenharmony_ci pSMB->Reserved3 = 0; 399362306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); 399462306a36Sopenharmony_ci pSMB->SearchAttributes = 399562306a36Sopenharmony_ci cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | 399662306a36Sopenharmony_ci ATTR_DIRECTORY); 399762306a36Sopenharmony_ci pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO)); 399862306a36Sopenharmony_ci pSMB->SearchFlags = cpu_to_le16(search_flags); 399962306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); 400062306a36Sopenharmony_ci 400162306a36Sopenharmony_ci /* BB what should we set StorageType to? Does it matter? BB */ 400262306a36Sopenharmony_ci pSMB->SearchStorageType = 0; 400362306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 400462306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 400562306a36Sopenharmony_ci 400662306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 400762306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 400862306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst); 400962306a36Sopenharmony_ci 401062306a36Sopenharmony_ci if (rc) { 401162306a36Sopenharmony_ci /* 401262306a36Sopenharmony_ci * BB: add logic to retry regular search if Unix search rejected 401362306a36Sopenharmony_ci * unexpectedly by server. 401462306a36Sopenharmony_ci */ 401562306a36Sopenharmony_ci /* BB: add code to handle unsupported level rc */ 401662306a36Sopenharmony_ci cifs_dbg(FYI, "Error in FindFirst = %d\n", rc); 401762306a36Sopenharmony_ci cifs_buf_release(pSMB); 401862306a36Sopenharmony_ci /* 401962306a36Sopenharmony_ci * BB: eventually could optimize out free and realloc of buf for 402062306a36Sopenharmony_ci * this case. 402162306a36Sopenharmony_ci */ 402262306a36Sopenharmony_ci if (rc == -EAGAIN) 402362306a36Sopenharmony_ci goto findFirstRetry; 402462306a36Sopenharmony_ci return rc; 402562306a36Sopenharmony_ci } 402662306a36Sopenharmony_ci /* decode response */ 402762306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 402862306a36Sopenharmony_ci if (rc) { 402962306a36Sopenharmony_ci cifs_buf_release(pSMB); 403062306a36Sopenharmony_ci return rc; 403162306a36Sopenharmony_ci } 403262306a36Sopenharmony_ci 403362306a36Sopenharmony_ci psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE); 403462306a36Sopenharmony_ci psrch_inf->ntwrk_buf_start = (char *)pSMBr; 403562306a36Sopenharmony_ci psrch_inf->smallBuf = false; 403662306a36Sopenharmony_ci psrch_inf->srch_entries_start = (char *)&pSMBr->hdr.Protocol + 403762306a36Sopenharmony_ci le16_to_cpu(pSMBr->t2.DataOffset); 403862306a36Sopenharmony_ci 403962306a36Sopenharmony_ci parms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol + 404062306a36Sopenharmony_ci le16_to_cpu(pSMBr->t2.ParameterOffset)); 404162306a36Sopenharmony_ci psrch_inf->endOfSearch = !!parms->EndofSearch; 404262306a36Sopenharmony_ci 404362306a36Sopenharmony_ci psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); 404462306a36Sopenharmony_ci psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + 404562306a36Sopenharmony_ci psrch_inf->entries_in_buffer; 404662306a36Sopenharmony_ci lnoff = le16_to_cpu(parms->LastNameOffset); 404762306a36Sopenharmony_ci if (CIFSMaxBufSize < lnoff) { 404862306a36Sopenharmony_ci cifs_dbg(VFS, "ignoring corrupt resume name\n"); 404962306a36Sopenharmony_ci psrch_inf->last_entry = NULL; 405062306a36Sopenharmony_ci } else { 405162306a36Sopenharmony_ci psrch_inf->last_entry = psrch_inf->srch_entries_start + lnoff; 405262306a36Sopenharmony_ci if (pnetfid) 405362306a36Sopenharmony_ci *pnetfid = parms->SearchHandle; 405462306a36Sopenharmony_ci } 405562306a36Sopenharmony_ci return 0; 405662306a36Sopenharmony_ci} 405762306a36Sopenharmony_ci 405862306a36Sopenharmony_ciint CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, 405962306a36Sopenharmony_ci __u16 searchHandle, __u16 search_flags, 406062306a36Sopenharmony_ci struct cifs_search_info *psrch_inf) 406162306a36Sopenharmony_ci{ 406262306a36Sopenharmony_ci TRANSACTION2_FNEXT_REQ *pSMB = NULL; 406362306a36Sopenharmony_ci TRANSACTION2_FNEXT_RSP *pSMBr = NULL; 406462306a36Sopenharmony_ci T2_FNEXT_RSP_PARMS *parms; 406562306a36Sopenharmony_ci unsigned int name_len; 406662306a36Sopenharmony_ci unsigned int lnoff; 406762306a36Sopenharmony_ci __u16 params, byte_count; 406862306a36Sopenharmony_ci char *response_data; 406962306a36Sopenharmony_ci int bytes_returned; 407062306a36Sopenharmony_ci int rc = 0; 407162306a36Sopenharmony_ci 407262306a36Sopenharmony_ci cifs_dbg(FYI, "In FindNext\n"); 407362306a36Sopenharmony_ci 407462306a36Sopenharmony_ci if (psrch_inf->endOfSearch) 407562306a36Sopenharmony_ci return -ENOENT; 407662306a36Sopenharmony_ci 407762306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 407862306a36Sopenharmony_ci (void **) &pSMBr); 407962306a36Sopenharmony_ci if (rc) 408062306a36Sopenharmony_ci return rc; 408162306a36Sopenharmony_ci 408262306a36Sopenharmony_ci params = 14; /* includes 2 bytes of null string, converted to LE below*/ 408362306a36Sopenharmony_ci byte_count = 0; 408462306a36Sopenharmony_ci pSMB->TotalDataCount = 0; /* no EAs */ 408562306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(8); 408662306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00); 408762306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 408862306a36Sopenharmony_ci pSMB->Reserved = 0; 408962306a36Sopenharmony_ci pSMB->Flags = 0; 409062306a36Sopenharmony_ci pSMB->Timeout = 0; 409162306a36Sopenharmony_ci pSMB->Reserved2 = 0; 409262306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16( 409362306a36Sopenharmony_ci offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4); 409462306a36Sopenharmony_ci pSMB->DataCount = 0; 409562306a36Sopenharmony_ci pSMB->DataOffset = 0; 409662306a36Sopenharmony_ci pSMB->SetupCount = 1; 409762306a36Sopenharmony_ci pSMB->Reserved3 = 0; 409862306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT); 409962306a36Sopenharmony_ci pSMB->SearchHandle = searchHandle; /* always kept as le */ 410062306a36Sopenharmony_ci pSMB->SearchCount = 410162306a36Sopenharmony_ci cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO)); 410262306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); 410362306a36Sopenharmony_ci pSMB->ResumeKey = psrch_inf->resume_key; 410462306a36Sopenharmony_ci pSMB->SearchFlags = cpu_to_le16(search_flags); 410562306a36Sopenharmony_ci 410662306a36Sopenharmony_ci name_len = psrch_inf->resume_name_len; 410762306a36Sopenharmony_ci params += name_len; 410862306a36Sopenharmony_ci if (name_len < PATH_MAX) { 410962306a36Sopenharmony_ci memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len); 411062306a36Sopenharmony_ci byte_count += name_len; 411162306a36Sopenharmony_ci /* 14 byte parm len above enough for 2 byte null terminator */ 411262306a36Sopenharmony_ci pSMB->ResumeFileName[name_len] = 0; 411362306a36Sopenharmony_ci pSMB->ResumeFileName[name_len+1] = 0; 411462306a36Sopenharmony_ci } else { 411562306a36Sopenharmony_ci cifs_buf_release(pSMB); 411662306a36Sopenharmony_ci return -EINVAL; 411762306a36Sopenharmony_ci } 411862306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 411962306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 412062306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 412162306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 412262306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 412362306a36Sopenharmony_ci 412462306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 412562306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 412662306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext); 412762306a36Sopenharmony_ci 412862306a36Sopenharmony_ci if (rc) { 412962306a36Sopenharmony_ci cifs_buf_release(pSMB); 413062306a36Sopenharmony_ci if (rc == -EBADF) { 413162306a36Sopenharmony_ci psrch_inf->endOfSearch = true; 413262306a36Sopenharmony_ci rc = 0; /* search probably was closed at end of search*/ 413362306a36Sopenharmony_ci } else { 413462306a36Sopenharmony_ci cifs_dbg(FYI, "FindNext returned = %d\n", rc); 413562306a36Sopenharmony_ci } 413662306a36Sopenharmony_ci return rc; 413762306a36Sopenharmony_ci } 413862306a36Sopenharmony_ci 413962306a36Sopenharmony_ci /* decode response */ 414062306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 414162306a36Sopenharmony_ci if (rc) { 414262306a36Sopenharmony_ci cifs_buf_release(pSMB); 414362306a36Sopenharmony_ci return rc; 414462306a36Sopenharmony_ci } 414562306a36Sopenharmony_ci /* BB fixme add lock for file (srch_info) struct here */ 414662306a36Sopenharmony_ci psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE); 414762306a36Sopenharmony_ci response_data = (char *)&pSMBr->hdr.Protocol + 414862306a36Sopenharmony_ci le16_to_cpu(pSMBr->t2.ParameterOffset); 414962306a36Sopenharmony_ci parms = (T2_FNEXT_RSP_PARMS *)response_data; 415062306a36Sopenharmony_ci response_data = (char *)&pSMBr->hdr.Protocol + 415162306a36Sopenharmony_ci le16_to_cpu(pSMBr->t2.DataOffset); 415262306a36Sopenharmony_ci 415362306a36Sopenharmony_ci if (psrch_inf->smallBuf) 415462306a36Sopenharmony_ci cifs_small_buf_release(psrch_inf->ntwrk_buf_start); 415562306a36Sopenharmony_ci else 415662306a36Sopenharmony_ci cifs_buf_release(psrch_inf->ntwrk_buf_start); 415762306a36Sopenharmony_ci 415862306a36Sopenharmony_ci psrch_inf->srch_entries_start = response_data; 415962306a36Sopenharmony_ci psrch_inf->ntwrk_buf_start = (char *)pSMB; 416062306a36Sopenharmony_ci psrch_inf->smallBuf = false; 416162306a36Sopenharmony_ci psrch_inf->endOfSearch = !!parms->EndofSearch; 416262306a36Sopenharmony_ci psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); 416362306a36Sopenharmony_ci psrch_inf->index_of_last_entry += psrch_inf->entries_in_buffer; 416462306a36Sopenharmony_ci lnoff = le16_to_cpu(parms->LastNameOffset); 416562306a36Sopenharmony_ci if (CIFSMaxBufSize < lnoff) { 416662306a36Sopenharmony_ci cifs_dbg(VFS, "ignoring corrupt resume name\n"); 416762306a36Sopenharmony_ci psrch_inf->last_entry = NULL; 416862306a36Sopenharmony_ci } else { 416962306a36Sopenharmony_ci psrch_inf->last_entry = 417062306a36Sopenharmony_ci psrch_inf->srch_entries_start + lnoff; 417162306a36Sopenharmony_ci } 417262306a36Sopenharmony_ci /* BB fixme add unlock here */ 417362306a36Sopenharmony_ci 417462306a36Sopenharmony_ci /* 417562306a36Sopenharmony_ci * BB: On error, should we leave previous search buf 417662306a36Sopenharmony_ci * (and count and last entry fields) intact or free the previous one? 417762306a36Sopenharmony_ci * 417862306a36Sopenharmony_ci * Note: On -EAGAIN error only caller can retry on handle based calls 417962306a36Sopenharmony_ci * since file handle passed in no longer valid. 418062306a36Sopenharmony_ci */ 418162306a36Sopenharmony_ci return 0; 418262306a36Sopenharmony_ci} 418362306a36Sopenharmony_ci 418462306a36Sopenharmony_ciint 418562306a36Sopenharmony_ciCIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon, 418662306a36Sopenharmony_ci const __u16 searchHandle) 418762306a36Sopenharmony_ci{ 418862306a36Sopenharmony_ci int rc = 0; 418962306a36Sopenharmony_ci FINDCLOSE_REQ *pSMB = NULL; 419062306a36Sopenharmony_ci 419162306a36Sopenharmony_ci cifs_dbg(FYI, "In CIFSSMBFindClose\n"); 419262306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB); 419362306a36Sopenharmony_ci 419462306a36Sopenharmony_ci /* no sense returning error if session restarted 419562306a36Sopenharmony_ci as file handle has been closed */ 419662306a36Sopenharmony_ci if (rc == -EAGAIN) 419762306a36Sopenharmony_ci return 0; 419862306a36Sopenharmony_ci if (rc) 419962306a36Sopenharmony_ci return rc; 420062306a36Sopenharmony_ci 420162306a36Sopenharmony_ci pSMB->FileID = searchHandle; 420262306a36Sopenharmony_ci pSMB->ByteCount = 0; 420362306a36Sopenharmony_ci rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); 420462306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 420562306a36Sopenharmony_ci if (rc) 420662306a36Sopenharmony_ci cifs_dbg(VFS, "Send error in FindClose = %d\n", rc); 420762306a36Sopenharmony_ci 420862306a36Sopenharmony_ci cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose); 420962306a36Sopenharmony_ci 421062306a36Sopenharmony_ci /* Since session is dead, search handle closed on server already */ 421162306a36Sopenharmony_ci if (rc == -EAGAIN) 421262306a36Sopenharmony_ci rc = 0; 421362306a36Sopenharmony_ci 421462306a36Sopenharmony_ci return rc; 421562306a36Sopenharmony_ci} 421662306a36Sopenharmony_ci 421762306a36Sopenharmony_ciint 421862306a36Sopenharmony_ciCIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, 421962306a36Sopenharmony_ci const char *search_name, __u64 *inode_number, 422062306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 422162306a36Sopenharmony_ci{ 422262306a36Sopenharmony_ci int rc = 0; 422362306a36Sopenharmony_ci TRANSACTION2_QPI_REQ *pSMB = NULL; 422462306a36Sopenharmony_ci TRANSACTION2_QPI_RSP *pSMBr = NULL; 422562306a36Sopenharmony_ci int name_len, bytes_returned; 422662306a36Sopenharmony_ci __u16 params, byte_count; 422762306a36Sopenharmony_ci 422862306a36Sopenharmony_ci cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name); 422962306a36Sopenharmony_ci if (tcon == NULL) 423062306a36Sopenharmony_ci return -ENODEV; 423162306a36Sopenharmony_ci 423262306a36Sopenharmony_ciGetInodeNumberRetry: 423362306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 423462306a36Sopenharmony_ci (void **) &pSMBr); 423562306a36Sopenharmony_ci if (rc) 423662306a36Sopenharmony_ci return rc; 423762306a36Sopenharmony_ci 423862306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 423962306a36Sopenharmony_ci name_len = 424062306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, 424162306a36Sopenharmony_ci search_name, PATH_MAX, nls_codepage, 424262306a36Sopenharmony_ci remap); 424362306a36Sopenharmony_ci name_len++; /* trailing null */ 424462306a36Sopenharmony_ci name_len *= 2; 424562306a36Sopenharmony_ci } else { 424662306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, search_name); 424762306a36Sopenharmony_ci } 424862306a36Sopenharmony_ci 424962306a36Sopenharmony_ci params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; 425062306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 425162306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 425262306a36Sopenharmony_ci /* BB find exact max data count below from sess structure BB */ 425362306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(4000); 425462306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 425562306a36Sopenharmony_ci pSMB->Reserved = 0; 425662306a36Sopenharmony_ci pSMB->Flags = 0; 425762306a36Sopenharmony_ci pSMB->Timeout = 0; 425862306a36Sopenharmony_ci pSMB->Reserved2 = 0; 425962306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof( 426062306a36Sopenharmony_ci struct smb_com_transaction2_qpi_req, InformationLevel) - 4); 426162306a36Sopenharmony_ci pSMB->DataCount = 0; 426262306a36Sopenharmony_ci pSMB->DataOffset = 0; 426362306a36Sopenharmony_ci pSMB->SetupCount = 1; 426462306a36Sopenharmony_ci pSMB->Reserved3 = 0; 426562306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); 426662306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 426762306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 426862306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 426962306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO); 427062306a36Sopenharmony_ci pSMB->Reserved4 = 0; 427162306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 427262306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 427362306a36Sopenharmony_ci 427462306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 427562306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 427662306a36Sopenharmony_ci if (rc) { 427762306a36Sopenharmony_ci cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc); 427862306a36Sopenharmony_ci } else { 427962306a36Sopenharmony_ci /* decode response */ 428062306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 428162306a36Sopenharmony_ci /* BB also check enough total bytes returned */ 428262306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 2) 428362306a36Sopenharmony_ci /* If rc should we check for EOPNOSUPP and 428462306a36Sopenharmony_ci disable the srvino flag? or in caller? */ 428562306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 428662306a36Sopenharmony_ci else { 428762306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 428862306a36Sopenharmony_ci __u16 count = le16_to_cpu(pSMBr->t2.DataCount); 428962306a36Sopenharmony_ci struct file_internal_info *pfinfo; 429062306a36Sopenharmony_ci /* BB Do we need a cast or hash here ? */ 429162306a36Sopenharmony_ci if (count < 8) { 429262306a36Sopenharmony_ci cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n"); 429362306a36Sopenharmony_ci rc = -EIO; 429462306a36Sopenharmony_ci goto GetInodeNumOut; 429562306a36Sopenharmony_ci } 429662306a36Sopenharmony_ci pfinfo = (struct file_internal_info *) 429762306a36Sopenharmony_ci (data_offset + (char *) &pSMBr->hdr.Protocol); 429862306a36Sopenharmony_ci *inode_number = le64_to_cpu(pfinfo->UniqueId); 429962306a36Sopenharmony_ci } 430062306a36Sopenharmony_ci } 430162306a36Sopenharmony_ciGetInodeNumOut: 430262306a36Sopenharmony_ci cifs_buf_release(pSMB); 430362306a36Sopenharmony_ci if (rc == -EAGAIN) 430462306a36Sopenharmony_ci goto GetInodeNumberRetry; 430562306a36Sopenharmony_ci return rc; 430662306a36Sopenharmony_ci} 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_ciint 430962306a36Sopenharmony_ciCIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, 431062306a36Sopenharmony_ci const char *search_name, struct dfs_info3_param **target_nodes, 431162306a36Sopenharmony_ci unsigned int *num_of_nodes, 431262306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 431362306a36Sopenharmony_ci{ 431462306a36Sopenharmony_ci/* TRANS2_GET_DFS_REFERRAL */ 431562306a36Sopenharmony_ci TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; 431662306a36Sopenharmony_ci TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; 431762306a36Sopenharmony_ci int rc = 0; 431862306a36Sopenharmony_ci int bytes_returned; 431962306a36Sopenharmony_ci int name_len; 432062306a36Sopenharmony_ci __u16 params, byte_count; 432162306a36Sopenharmony_ci *num_of_nodes = 0; 432262306a36Sopenharmony_ci *target_nodes = NULL; 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_ci cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name); 432562306a36Sopenharmony_ci if (ses == NULL || ses->tcon_ipc == NULL) 432662306a36Sopenharmony_ci return -ENODEV; 432762306a36Sopenharmony_ci 432862306a36Sopenharmony_cigetDFSRetry: 432962306a36Sopenharmony_ci /* 433062306a36Sopenharmony_ci * Use smb_init_no_reconnect() instead of smb_init() as 433162306a36Sopenharmony_ci * CIFSGetDFSRefer() may be called from cifs_reconnect_tcon() and thus 433262306a36Sopenharmony_ci * causing an infinite recursion. 433362306a36Sopenharmony_ci */ 433462306a36Sopenharmony_ci rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, 433562306a36Sopenharmony_ci (void **)&pSMB, (void **)&pSMBr); 433662306a36Sopenharmony_ci if (rc) 433762306a36Sopenharmony_ci return rc; 433862306a36Sopenharmony_ci 433962306a36Sopenharmony_ci /* server pointer checked in called function, 434062306a36Sopenharmony_ci but should never be null here anyway */ 434162306a36Sopenharmony_ci pSMB->hdr.Mid = get_next_mid(ses->server); 434262306a36Sopenharmony_ci pSMB->hdr.Tid = ses->tcon_ipc->tid; 434362306a36Sopenharmony_ci pSMB->hdr.Uid = ses->Suid; 434462306a36Sopenharmony_ci if (ses->capabilities & CAP_STATUS32) 434562306a36Sopenharmony_ci pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS; 434662306a36Sopenharmony_ci if (ses->capabilities & CAP_DFS) 434762306a36Sopenharmony_ci pSMB->hdr.Flags2 |= SMBFLG2_DFS; 434862306a36Sopenharmony_ci 434962306a36Sopenharmony_ci if (ses->capabilities & CAP_UNICODE) { 435062306a36Sopenharmony_ci pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; 435162306a36Sopenharmony_ci name_len = 435262306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->RequestFileName, 435362306a36Sopenharmony_ci search_name, PATH_MAX, nls_codepage, 435462306a36Sopenharmony_ci remap); 435562306a36Sopenharmony_ci name_len++; /* trailing null */ 435662306a36Sopenharmony_ci name_len *= 2; 435762306a36Sopenharmony_ci } else { /* BB improve the check for buffer overruns BB */ 435862306a36Sopenharmony_ci name_len = copy_path_name(pSMB->RequestFileName, search_name); 435962306a36Sopenharmony_ci } 436062306a36Sopenharmony_ci 436162306a36Sopenharmony_ci if (ses->server->sign) 436262306a36Sopenharmony_ci pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; 436362306a36Sopenharmony_ci 436462306a36Sopenharmony_ci pSMB->hdr.Uid = ses->Suid; 436562306a36Sopenharmony_ci 436662306a36Sopenharmony_ci params = 2 /* level */ + name_len /*includes null */ ; 436762306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 436862306a36Sopenharmony_ci pSMB->DataCount = 0; 436962306a36Sopenharmony_ci pSMB->DataOffset = 0; 437062306a36Sopenharmony_ci pSMB->MaxParameterCount = 0; 437162306a36Sopenharmony_ci /* BB find exact max SMB PDU from sess structure BB */ 437262306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(4000); 437362306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 437462306a36Sopenharmony_ci pSMB->Reserved = 0; 437562306a36Sopenharmony_ci pSMB->Flags = 0; 437662306a36Sopenharmony_ci pSMB->Timeout = 0; 437762306a36Sopenharmony_ci pSMB->Reserved2 = 0; 437862306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof( 437962306a36Sopenharmony_ci struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4); 438062306a36Sopenharmony_ci pSMB->SetupCount = 1; 438162306a36Sopenharmony_ci pSMB->Reserved3 = 0; 438262306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL); 438362306a36Sopenharmony_ci byte_count = params + 3 /* pad */ ; 438462306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 438562306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 438662306a36Sopenharmony_ci pSMB->MaxReferralLevel = cpu_to_le16(3); 438762306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 438862306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 438962306a36Sopenharmony_ci 439062306a36Sopenharmony_ci rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, 439162306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 439262306a36Sopenharmony_ci if (rc) { 439362306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc); 439462306a36Sopenharmony_ci goto GetDFSRefExit; 439562306a36Sopenharmony_ci } 439662306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 439762306a36Sopenharmony_ci 439862306a36Sopenharmony_ci /* BB Also check if enough total bytes returned? */ 439962306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 17) { 440062306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 440162306a36Sopenharmony_ci goto GetDFSRefExit; 440262306a36Sopenharmony_ci } 440362306a36Sopenharmony_ci 440462306a36Sopenharmony_ci cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n", 440562306a36Sopenharmony_ci get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset)); 440662306a36Sopenharmony_ci 440762306a36Sopenharmony_ci /* parse returned result into more usable form */ 440862306a36Sopenharmony_ci rc = parse_dfs_referrals(&pSMBr->dfs_data, 440962306a36Sopenharmony_ci le16_to_cpu(pSMBr->t2.DataCount), 441062306a36Sopenharmony_ci num_of_nodes, target_nodes, nls_codepage, 441162306a36Sopenharmony_ci remap, search_name, 441262306a36Sopenharmony_ci (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0); 441362306a36Sopenharmony_ci 441462306a36Sopenharmony_ciGetDFSRefExit: 441562306a36Sopenharmony_ci cifs_buf_release(pSMB); 441662306a36Sopenharmony_ci 441762306a36Sopenharmony_ci if (rc == -EAGAIN) 441862306a36Sopenharmony_ci goto getDFSRetry; 441962306a36Sopenharmony_ci 442062306a36Sopenharmony_ci return rc; 442162306a36Sopenharmony_ci} 442262306a36Sopenharmony_ci 442362306a36Sopenharmony_ci/* Query File System Info such as free space to old servers such as Win 9x */ 442462306a36Sopenharmony_ciint 442562306a36Sopenharmony_ciSMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, 442662306a36Sopenharmony_ci struct kstatfs *FSData) 442762306a36Sopenharmony_ci{ 442862306a36Sopenharmony_ci/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */ 442962306a36Sopenharmony_ci TRANSACTION2_QFSI_REQ *pSMB = NULL; 443062306a36Sopenharmony_ci TRANSACTION2_QFSI_RSP *pSMBr = NULL; 443162306a36Sopenharmony_ci FILE_SYSTEM_ALLOC_INFO *response_data; 443262306a36Sopenharmony_ci int rc = 0; 443362306a36Sopenharmony_ci int bytes_returned = 0; 443462306a36Sopenharmony_ci __u16 params, byte_count; 443562306a36Sopenharmony_ci 443662306a36Sopenharmony_ci cifs_dbg(FYI, "OldQFSInfo\n"); 443762306a36Sopenharmony_cioldQFSInfoRetry: 443862306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 443962306a36Sopenharmony_ci (void **) &pSMBr); 444062306a36Sopenharmony_ci if (rc) 444162306a36Sopenharmony_ci return rc; 444262306a36Sopenharmony_ci 444362306a36Sopenharmony_ci params = 2; /* level */ 444462306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 444562306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 444662306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 444762306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 444862306a36Sopenharmony_ci pSMB->Reserved = 0; 444962306a36Sopenharmony_ci pSMB->Flags = 0; 445062306a36Sopenharmony_ci pSMB->Timeout = 0; 445162306a36Sopenharmony_ci pSMB->Reserved2 = 0; 445262306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 445362306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 445462306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 445562306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof( 445662306a36Sopenharmony_ci struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); 445762306a36Sopenharmony_ci pSMB->DataCount = 0; 445862306a36Sopenharmony_ci pSMB->DataOffset = 0; 445962306a36Sopenharmony_ci pSMB->SetupCount = 1; 446062306a36Sopenharmony_ci pSMB->Reserved3 = 0; 446162306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); 446262306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION); 446362306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 446462306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 446562306a36Sopenharmony_ci 446662306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 446762306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 446862306a36Sopenharmony_ci if (rc) { 446962306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc); 447062306a36Sopenharmony_ci } else { /* decode response */ 447162306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 447262306a36Sopenharmony_ci 447362306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 18) 447462306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 447562306a36Sopenharmony_ci else { 447662306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 447762306a36Sopenharmony_ci cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n", 447862306a36Sopenharmony_ci get_bcc(&pSMBr->hdr), data_offset); 447962306a36Sopenharmony_ci 448062306a36Sopenharmony_ci response_data = (FILE_SYSTEM_ALLOC_INFO *) 448162306a36Sopenharmony_ci (((char *) &pSMBr->hdr.Protocol) + data_offset); 448262306a36Sopenharmony_ci FSData->f_bsize = 448362306a36Sopenharmony_ci le16_to_cpu(response_data->BytesPerSector) * 448462306a36Sopenharmony_ci le32_to_cpu(response_data-> 448562306a36Sopenharmony_ci SectorsPerAllocationUnit); 448662306a36Sopenharmony_ci /* 448762306a36Sopenharmony_ci * much prefer larger but if server doesn't report 448862306a36Sopenharmony_ci * a valid size than 4K is a reasonable minimum 448962306a36Sopenharmony_ci */ 449062306a36Sopenharmony_ci if (FSData->f_bsize < 512) 449162306a36Sopenharmony_ci FSData->f_bsize = 4096; 449262306a36Sopenharmony_ci 449362306a36Sopenharmony_ci FSData->f_blocks = 449462306a36Sopenharmony_ci le32_to_cpu(response_data->TotalAllocationUnits); 449562306a36Sopenharmony_ci FSData->f_bfree = FSData->f_bavail = 449662306a36Sopenharmony_ci le32_to_cpu(response_data->FreeAllocationUnits); 449762306a36Sopenharmony_ci cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n", 449862306a36Sopenharmony_ci (unsigned long long)FSData->f_blocks, 449962306a36Sopenharmony_ci (unsigned long long)FSData->f_bfree, 450062306a36Sopenharmony_ci FSData->f_bsize); 450162306a36Sopenharmony_ci } 450262306a36Sopenharmony_ci } 450362306a36Sopenharmony_ci cifs_buf_release(pSMB); 450462306a36Sopenharmony_ci 450562306a36Sopenharmony_ci if (rc == -EAGAIN) 450662306a36Sopenharmony_ci goto oldQFSInfoRetry; 450762306a36Sopenharmony_ci 450862306a36Sopenharmony_ci return rc; 450962306a36Sopenharmony_ci} 451062306a36Sopenharmony_ci 451162306a36Sopenharmony_ciint 451262306a36Sopenharmony_ciCIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, 451362306a36Sopenharmony_ci struct kstatfs *FSData) 451462306a36Sopenharmony_ci{ 451562306a36Sopenharmony_ci/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ 451662306a36Sopenharmony_ci TRANSACTION2_QFSI_REQ *pSMB = NULL; 451762306a36Sopenharmony_ci TRANSACTION2_QFSI_RSP *pSMBr = NULL; 451862306a36Sopenharmony_ci FILE_SYSTEM_INFO *response_data; 451962306a36Sopenharmony_ci int rc = 0; 452062306a36Sopenharmony_ci int bytes_returned = 0; 452162306a36Sopenharmony_ci __u16 params, byte_count; 452262306a36Sopenharmony_ci 452362306a36Sopenharmony_ci cifs_dbg(FYI, "In QFSInfo\n"); 452462306a36Sopenharmony_ciQFSInfoRetry: 452562306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 452662306a36Sopenharmony_ci (void **) &pSMBr); 452762306a36Sopenharmony_ci if (rc) 452862306a36Sopenharmony_ci return rc; 452962306a36Sopenharmony_ci 453062306a36Sopenharmony_ci params = 2; /* level */ 453162306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 453262306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 453362306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 453462306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 453562306a36Sopenharmony_ci pSMB->Reserved = 0; 453662306a36Sopenharmony_ci pSMB->Flags = 0; 453762306a36Sopenharmony_ci pSMB->Timeout = 0; 453862306a36Sopenharmony_ci pSMB->Reserved2 = 0; 453962306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 454062306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 454162306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 454262306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof( 454362306a36Sopenharmony_ci struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); 454462306a36Sopenharmony_ci pSMB->DataCount = 0; 454562306a36Sopenharmony_ci pSMB->DataOffset = 0; 454662306a36Sopenharmony_ci pSMB->SetupCount = 1; 454762306a36Sopenharmony_ci pSMB->Reserved3 = 0; 454862306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); 454962306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); 455062306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 455162306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 455262306a36Sopenharmony_ci 455362306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 455462306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 455562306a36Sopenharmony_ci if (rc) { 455662306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc); 455762306a36Sopenharmony_ci } else { /* decode response */ 455862306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 455962306a36Sopenharmony_ci 456062306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 24) 456162306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 456262306a36Sopenharmony_ci else { 456362306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 456462306a36Sopenharmony_ci 456562306a36Sopenharmony_ci response_data = 456662306a36Sopenharmony_ci (FILE_SYSTEM_INFO 456762306a36Sopenharmony_ci *) (((char *) &pSMBr->hdr.Protocol) + 456862306a36Sopenharmony_ci data_offset); 456962306a36Sopenharmony_ci FSData->f_bsize = 457062306a36Sopenharmony_ci le32_to_cpu(response_data->BytesPerSector) * 457162306a36Sopenharmony_ci le32_to_cpu(response_data-> 457262306a36Sopenharmony_ci SectorsPerAllocationUnit); 457362306a36Sopenharmony_ci /* 457462306a36Sopenharmony_ci * much prefer larger but if server doesn't report 457562306a36Sopenharmony_ci * a valid size than 4K is a reasonable minimum 457662306a36Sopenharmony_ci */ 457762306a36Sopenharmony_ci if (FSData->f_bsize < 512) 457862306a36Sopenharmony_ci FSData->f_bsize = 4096; 457962306a36Sopenharmony_ci 458062306a36Sopenharmony_ci FSData->f_blocks = 458162306a36Sopenharmony_ci le64_to_cpu(response_data->TotalAllocationUnits); 458262306a36Sopenharmony_ci FSData->f_bfree = FSData->f_bavail = 458362306a36Sopenharmony_ci le64_to_cpu(response_data->FreeAllocationUnits); 458462306a36Sopenharmony_ci cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n", 458562306a36Sopenharmony_ci (unsigned long long)FSData->f_blocks, 458662306a36Sopenharmony_ci (unsigned long long)FSData->f_bfree, 458762306a36Sopenharmony_ci FSData->f_bsize); 458862306a36Sopenharmony_ci } 458962306a36Sopenharmony_ci } 459062306a36Sopenharmony_ci cifs_buf_release(pSMB); 459162306a36Sopenharmony_ci 459262306a36Sopenharmony_ci if (rc == -EAGAIN) 459362306a36Sopenharmony_ci goto QFSInfoRetry; 459462306a36Sopenharmony_ci 459562306a36Sopenharmony_ci return rc; 459662306a36Sopenharmony_ci} 459762306a36Sopenharmony_ci 459862306a36Sopenharmony_ciint 459962306a36Sopenharmony_ciCIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon) 460062306a36Sopenharmony_ci{ 460162306a36Sopenharmony_ci/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */ 460262306a36Sopenharmony_ci TRANSACTION2_QFSI_REQ *pSMB = NULL; 460362306a36Sopenharmony_ci TRANSACTION2_QFSI_RSP *pSMBr = NULL; 460462306a36Sopenharmony_ci FILE_SYSTEM_ATTRIBUTE_INFO *response_data; 460562306a36Sopenharmony_ci int rc = 0; 460662306a36Sopenharmony_ci int bytes_returned = 0; 460762306a36Sopenharmony_ci __u16 params, byte_count; 460862306a36Sopenharmony_ci 460962306a36Sopenharmony_ci cifs_dbg(FYI, "In QFSAttributeInfo\n"); 461062306a36Sopenharmony_ciQFSAttributeRetry: 461162306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 461262306a36Sopenharmony_ci (void **) &pSMBr); 461362306a36Sopenharmony_ci if (rc) 461462306a36Sopenharmony_ci return rc; 461562306a36Sopenharmony_ci 461662306a36Sopenharmony_ci params = 2; /* level */ 461762306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 461862306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 461962306a36Sopenharmony_ci /* BB find exact max SMB PDU from sess structure BB */ 462062306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 462162306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 462262306a36Sopenharmony_ci pSMB->Reserved = 0; 462362306a36Sopenharmony_ci pSMB->Flags = 0; 462462306a36Sopenharmony_ci pSMB->Timeout = 0; 462562306a36Sopenharmony_ci pSMB->Reserved2 = 0; 462662306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 462762306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 462862306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 462962306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof( 463062306a36Sopenharmony_ci struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); 463162306a36Sopenharmony_ci pSMB->DataCount = 0; 463262306a36Sopenharmony_ci pSMB->DataOffset = 0; 463362306a36Sopenharmony_ci pSMB->SetupCount = 1; 463462306a36Sopenharmony_ci pSMB->Reserved3 = 0; 463562306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); 463662306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); 463762306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 463862306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 463962306a36Sopenharmony_ci 464062306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 464162306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 464262306a36Sopenharmony_ci if (rc) { 464362306a36Sopenharmony_ci cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc); 464462306a36Sopenharmony_ci } else { /* decode response */ 464562306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 464662306a36Sopenharmony_ci 464762306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 13) { 464862306a36Sopenharmony_ci /* BB also check if enough bytes returned */ 464962306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 465062306a36Sopenharmony_ci } else { 465162306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 465262306a36Sopenharmony_ci response_data = 465362306a36Sopenharmony_ci (FILE_SYSTEM_ATTRIBUTE_INFO 465462306a36Sopenharmony_ci *) (((char *) &pSMBr->hdr.Protocol) + 465562306a36Sopenharmony_ci data_offset); 465662306a36Sopenharmony_ci memcpy(&tcon->fsAttrInfo, response_data, 465762306a36Sopenharmony_ci sizeof(FILE_SYSTEM_ATTRIBUTE_INFO)); 465862306a36Sopenharmony_ci } 465962306a36Sopenharmony_ci } 466062306a36Sopenharmony_ci cifs_buf_release(pSMB); 466162306a36Sopenharmony_ci 466262306a36Sopenharmony_ci if (rc == -EAGAIN) 466362306a36Sopenharmony_ci goto QFSAttributeRetry; 466462306a36Sopenharmony_ci 466562306a36Sopenharmony_ci return rc; 466662306a36Sopenharmony_ci} 466762306a36Sopenharmony_ci 466862306a36Sopenharmony_ciint 466962306a36Sopenharmony_ciCIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon) 467062306a36Sopenharmony_ci{ 467162306a36Sopenharmony_ci/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ 467262306a36Sopenharmony_ci TRANSACTION2_QFSI_REQ *pSMB = NULL; 467362306a36Sopenharmony_ci TRANSACTION2_QFSI_RSP *pSMBr = NULL; 467462306a36Sopenharmony_ci FILE_SYSTEM_DEVICE_INFO *response_data; 467562306a36Sopenharmony_ci int rc = 0; 467662306a36Sopenharmony_ci int bytes_returned = 0; 467762306a36Sopenharmony_ci __u16 params, byte_count; 467862306a36Sopenharmony_ci 467962306a36Sopenharmony_ci cifs_dbg(FYI, "In QFSDeviceInfo\n"); 468062306a36Sopenharmony_ciQFSDeviceRetry: 468162306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 468262306a36Sopenharmony_ci (void **) &pSMBr); 468362306a36Sopenharmony_ci if (rc) 468462306a36Sopenharmony_ci return rc; 468562306a36Sopenharmony_ci 468662306a36Sopenharmony_ci params = 2; /* level */ 468762306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 468862306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 468962306a36Sopenharmony_ci /* BB find exact max SMB PDU from sess structure BB */ 469062306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 469162306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 469262306a36Sopenharmony_ci pSMB->Reserved = 0; 469362306a36Sopenharmony_ci pSMB->Flags = 0; 469462306a36Sopenharmony_ci pSMB->Timeout = 0; 469562306a36Sopenharmony_ci pSMB->Reserved2 = 0; 469662306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 469762306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 469862306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 469962306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof( 470062306a36Sopenharmony_ci struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); 470162306a36Sopenharmony_ci 470262306a36Sopenharmony_ci pSMB->DataCount = 0; 470362306a36Sopenharmony_ci pSMB->DataOffset = 0; 470462306a36Sopenharmony_ci pSMB->SetupCount = 1; 470562306a36Sopenharmony_ci pSMB->Reserved3 = 0; 470662306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); 470762306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); 470862306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 470962306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 471062306a36Sopenharmony_ci 471162306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 471262306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 471362306a36Sopenharmony_ci if (rc) { 471462306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc); 471562306a36Sopenharmony_ci } else { /* decode response */ 471662306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 471762306a36Sopenharmony_ci 471862306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 471962306a36Sopenharmony_ci sizeof(FILE_SYSTEM_DEVICE_INFO)) 472062306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 472162306a36Sopenharmony_ci else { 472262306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 472362306a36Sopenharmony_ci response_data = 472462306a36Sopenharmony_ci (FILE_SYSTEM_DEVICE_INFO *) 472562306a36Sopenharmony_ci (((char *) &pSMBr->hdr.Protocol) + 472662306a36Sopenharmony_ci data_offset); 472762306a36Sopenharmony_ci memcpy(&tcon->fsDevInfo, response_data, 472862306a36Sopenharmony_ci sizeof(FILE_SYSTEM_DEVICE_INFO)); 472962306a36Sopenharmony_ci } 473062306a36Sopenharmony_ci } 473162306a36Sopenharmony_ci cifs_buf_release(pSMB); 473262306a36Sopenharmony_ci 473362306a36Sopenharmony_ci if (rc == -EAGAIN) 473462306a36Sopenharmony_ci goto QFSDeviceRetry; 473562306a36Sopenharmony_ci 473662306a36Sopenharmony_ci return rc; 473762306a36Sopenharmony_ci} 473862306a36Sopenharmony_ci 473962306a36Sopenharmony_ciint 474062306a36Sopenharmony_ciCIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon) 474162306a36Sopenharmony_ci{ 474262306a36Sopenharmony_ci/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */ 474362306a36Sopenharmony_ci TRANSACTION2_QFSI_REQ *pSMB = NULL; 474462306a36Sopenharmony_ci TRANSACTION2_QFSI_RSP *pSMBr = NULL; 474562306a36Sopenharmony_ci FILE_SYSTEM_UNIX_INFO *response_data; 474662306a36Sopenharmony_ci int rc = 0; 474762306a36Sopenharmony_ci int bytes_returned = 0; 474862306a36Sopenharmony_ci __u16 params, byte_count; 474962306a36Sopenharmony_ci 475062306a36Sopenharmony_ci cifs_dbg(FYI, "In QFSUnixInfo\n"); 475162306a36Sopenharmony_ciQFSUnixRetry: 475262306a36Sopenharmony_ci rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon, 475362306a36Sopenharmony_ci (void **) &pSMB, (void **) &pSMBr); 475462306a36Sopenharmony_ci if (rc) 475562306a36Sopenharmony_ci return rc; 475662306a36Sopenharmony_ci 475762306a36Sopenharmony_ci params = 2; /* level */ 475862306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 475962306a36Sopenharmony_ci pSMB->DataCount = 0; 476062306a36Sopenharmony_ci pSMB->DataOffset = 0; 476162306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 476262306a36Sopenharmony_ci /* BB find exact max SMB PDU from sess structure BB */ 476362306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(100); 476462306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 476562306a36Sopenharmony_ci pSMB->Reserved = 0; 476662306a36Sopenharmony_ci pSMB->Flags = 0; 476762306a36Sopenharmony_ci pSMB->Timeout = 0; 476862306a36Sopenharmony_ci pSMB->Reserved2 = 0; 476962306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 477062306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 477162306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 477262306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 477362306a36Sopenharmony_ci smb_com_transaction2_qfsi_req, InformationLevel) - 4); 477462306a36Sopenharmony_ci pSMB->SetupCount = 1; 477562306a36Sopenharmony_ci pSMB->Reserved3 = 0; 477662306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); 477762306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); 477862306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 477962306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 478062306a36Sopenharmony_ci 478162306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 478262306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 478362306a36Sopenharmony_ci if (rc) { 478462306a36Sopenharmony_ci cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc); 478562306a36Sopenharmony_ci } else { /* decode response */ 478662306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 478762306a36Sopenharmony_ci 478862306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 13) { 478962306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 479062306a36Sopenharmony_ci } else { 479162306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 479262306a36Sopenharmony_ci response_data = 479362306a36Sopenharmony_ci (FILE_SYSTEM_UNIX_INFO 479462306a36Sopenharmony_ci *) (((char *) &pSMBr->hdr.Protocol) + 479562306a36Sopenharmony_ci data_offset); 479662306a36Sopenharmony_ci memcpy(&tcon->fsUnixInfo, response_data, 479762306a36Sopenharmony_ci sizeof(FILE_SYSTEM_UNIX_INFO)); 479862306a36Sopenharmony_ci } 479962306a36Sopenharmony_ci } 480062306a36Sopenharmony_ci cifs_buf_release(pSMB); 480162306a36Sopenharmony_ci 480262306a36Sopenharmony_ci if (rc == -EAGAIN) 480362306a36Sopenharmony_ci goto QFSUnixRetry; 480462306a36Sopenharmony_ci 480562306a36Sopenharmony_ci 480662306a36Sopenharmony_ci return rc; 480762306a36Sopenharmony_ci} 480862306a36Sopenharmony_ci 480962306a36Sopenharmony_ciint 481062306a36Sopenharmony_ciCIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap) 481162306a36Sopenharmony_ci{ 481262306a36Sopenharmony_ci/* level 0x200 SMB_SET_CIFS_UNIX_INFO */ 481362306a36Sopenharmony_ci TRANSACTION2_SETFSI_REQ *pSMB = NULL; 481462306a36Sopenharmony_ci TRANSACTION2_SETFSI_RSP *pSMBr = NULL; 481562306a36Sopenharmony_ci int rc = 0; 481662306a36Sopenharmony_ci int bytes_returned = 0; 481762306a36Sopenharmony_ci __u16 params, param_offset, offset, byte_count; 481862306a36Sopenharmony_ci 481962306a36Sopenharmony_ci cifs_dbg(FYI, "In SETFSUnixInfo\n"); 482062306a36Sopenharmony_ciSETFSUnixRetry: 482162306a36Sopenharmony_ci /* BB switch to small buf init to save memory */ 482262306a36Sopenharmony_ci rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon, 482362306a36Sopenharmony_ci (void **) &pSMB, (void **) &pSMBr); 482462306a36Sopenharmony_ci if (rc) 482562306a36Sopenharmony_ci return rc; 482662306a36Sopenharmony_ci 482762306a36Sopenharmony_ci params = 4; /* 2 bytes zero followed by info level. */ 482862306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 482962306a36Sopenharmony_ci pSMB->Reserved = 0; 483062306a36Sopenharmony_ci pSMB->Flags = 0; 483162306a36Sopenharmony_ci pSMB->Timeout = 0; 483262306a36Sopenharmony_ci pSMB->Reserved2 = 0; 483362306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) 483462306a36Sopenharmony_ci - 4; 483562306a36Sopenharmony_ci offset = param_offset + params; 483662306a36Sopenharmony_ci 483762306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(4); 483862306a36Sopenharmony_ci /* BB find exact max SMB PDU from sess structure BB */ 483962306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(100); 484062306a36Sopenharmony_ci pSMB->SetupCount = 1; 484162306a36Sopenharmony_ci pSMB->Reserved3 = 0; 484262306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); 484362306a36Sopenharmony_ci byte_count = 1 /* pad */ + params + 12; 484462306a36Sopenharmony_ci 484562306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(12); 484662306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 484762306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 484862306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 484962306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 485062306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 485162306a36Sopenharmony_ci 485262306a36Sopenharmony_ci /* Params. */ 485362306a36Sopenharmony_ci pSMB->FileNum = 0; 485462306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO); 485562306a36Sopenharmony_ci 485662306a36Sopenharmony_ci /* Data. */ 485762306a36Sopenharmony_ci pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION); 485862306a36Sopenharmony_ci pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); 485962306a36Sopenharmony_ci pSMB->ClientUnixCap = cpu_to_le64(cap); 486062306a36Sopenharmony_ci 486162306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 486262306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 486362306a36Sopenharmony_ci 486462306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 486562306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 486662306a36Sopenharmony_ci if (rc) { 486762306a36Sopenharmony_ci cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc); 486862306a36Sopenharmony_ci } else { /* decode response */ 486962306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 487062306a36Sopenharmony_ci if (rc) 487162306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 487262306a36Sopenharmony_ci } 487362306a36Sopenharmony_ci cifs_buf_release(pSMB); 487462306a36Sopenharmony_ci 487562306a36Sopenharmony_ci if (rc == -EAGAIN) 487662306a36Sopenharmony_ci goto SETFSUnixRetry; 487762306a36Sopenharmony_ci 487862306a36Sopenharmony_ci return rc; 487962306a36Sopenharmony_ci} 488062306a36Sopenharmony_ci 488162306a36Sopenharmony_ci 488262306a36Sopenharmony_ci 488362306a36Sopenharmony_ciint 488462306a36Sopenharmony_ciCIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon, 488562306a36Sopenharmony_ci struct kstatfs *FSData) 488662306a36Sopenharmony_ci{ 488762306a36Sopenharmony_ci/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */ 488862306a36Sopenharmony_ci TRANSACTION2_QFSI_REQ *pSMB = NULL; 488962306a36Sopenharmony_ci TRANSACTION2_QFSI_RSP *pSMBr = NULL; 489062306a36Sopenharmony_ci FILE_SYSTEM_POSIX_INFO *response_data; 489162306a36Sopenharmony_ci int rc = 0; 489262306a36Sopenharmony_ci int bytes_returned = 0; 489362306a36Sopenharmony_ci __u16 params, byte_count; 489462306a36Sopenharmony_ci 489562306a36Sopenharmony_ci cifs_dbg(FYI, "In QFSPosixInfo\n"); 489662306a36Sopenharmony_ciQFSPosixRetry: 489762306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 489862306a36Sopenharmony_ci (void **) &pSMBr); 489962306a36Sopenharmony_ci if (rc) 490062306a36Sopenharmony_ci return rc; 490162306a36Sopenharmony_ci 490262306a36Sopenharmony_ci params = 2; /* level */ 490362306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 490462306a36Sopenharmony_ci pSMB->DataCount = 0; 490562306a36Sopenharmony_ci pSMB->DataOffset = 0; 490662306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 490762306a36Sopenharmony_ci /* BB find exact max SMB PDU from sess structure BB */ 490862306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(100); 490962306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 491062306a36Sopenharmony_ci pSMB->Reserved = 0; 491162306a36Sopenharmony_ci pSMB->Flags = 0; 491262306a36Sopenharmony_ci pSMB->Timeout = 0; 491362306a36Sopenharmony_ci pSMB->Reserved2 = 0; 491462306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 491562306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 491662306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 491762306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 491862306a36Sopenharmony_ci smb_com_transaction2_qfsi_req, InformationLevel) - 4); 491962306a36Sopenharmony_ci pSMB->SetupCount = 1; 492062306a36Sopenharmony_ci pSMB->Reserved3 = 0; 492162306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); 492262306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO); 492362306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 492462306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 492562306a36Sopenharmony_ci 492662306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 492762306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 492862306a36Sopenharmony_ci if (rc) { 492962306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc); 493062306a36Sopenharmony_ci } else { /* decode response */ 493162306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 493262306a36Sopenharmony_ci 493362306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 13) { 493462306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 493562306a36Sopenharmony_ci } else { 493662306a36Sopenharmony_ci __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 493762306a36Sopenharmony_ci response_data = 493862306a36Sopenharmony_ci (FILE_SYSTEM_POSIX_INFO 493962306a36Sopenharmony_ci *) (((char *) &pSMBr->hdr.Protocol) + 494062306a36Sopenharmony_ci data_offset); 494162306a36Sopenharmony_ci FSData->f_bsize = 494262306a36Sopenharmony_ci le32_to_cpu(response_data->BlockSize); 494362306a36Sopenharmony_ci /* 494462306a36Sopenharmony_ci * much prefer larger but if server doesn't report 494562306a36Sopenharmony_ci * a valid size than 4K is a reasonable minimum 494662306a36Sopenharmony_ci */ 494762306a36Sopenharmony_ci if (FSData->f_bsize < 512) 494862306a36Sopenharmony_ci FSData->f_bsize = 4096; 494962306a36Sopenharmony_ci 495062306a36Sopenharmony_ci FSData->f_blocks = 495162306a36Sopenharmony_ci le64_to_cpu(response_data->TotalBlocks); 495262306a36Sopenharmony_ci FSData->f_bfree = 495362306a36Sopenharmony_ci le64_to_cpu(response_data->BlocksAvail); 495462306a36Sopenharmony_ci if (response_data->UserBlocksAvail == cpu_to_le64(-1)) { 495562306a36Sopenharmony_ci FSData->f_bavail = FSData->f_bfree; 495662306a36Sopenharmony_ci } else { 495762306a36Sopenharmony_ci FSData->f_bavail = 495862306a36Sopenharmony_ci le64_to_cpu(response_data->UserBlocksAvail); 495962306a36Sopenharmony_ci } 496062306a36Sopenharmony_ci if (response_data->TotalFileNodes != cpu_to_le64(-1)) 496162306a36Sopenharmony_ci FSData->f_files = 496262306a36Sopenharmony_ci le64_to_cpu(response_data->TotalFileNodes); 496362306a36Sopenharmony_ci if (response_data->FreeFileNodes != cpu_to_le64(-1)) 496462306a36Sopenharmony_ci FSData->f_ffree = 496562306a36Sopenharmony_ci le64_to_cpu(response_data->FreeFileNodes); 496662306a36Sopenharmony_ci } 496762306a36Sopenharmony_ci } 496862306a36Sopenharmony_ci cifs_buf_release(pSMB); 496962306a36Sopenharmony_ci 497062306a36Sopenharmony_ci if (rc == -EAGAIN) 497162306a36Sopenharmony_ci goto QFSPosixRetry; 497262306a36Sopenharmony_ci 497362306a36Sopenharmony_ci return rc; 497462306a36Sopenharmony_ci} 497562306a36Sopenharmony_ci 497662306a36Sopenharmony_ci 497762306a36Sopenharmony_ci/* 497862306a36Sopenharmony_ci * We can not use write of zero bytes trick to set file size due to need for 497962306a36Sopenharmony_ci * large file support. Also note that this SetPathInfo is preferred to 498062306a36Sopenharmony_ci * SetFileInfo based method in next routine which is only needed to work around 498162306a36Sopenharmony_ci * a sharing violation bugin Samba which this routine can run into. 498262306a36Sopenharmony_ci */ 498362306a36Sopenharmony_ciint 498462306a36Sopenharmony_ciCIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon, 498562306a36Sopenharmony_ci const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb, 498662306a36Sopenharmony_ci bool set_allocation) 498762306a36Sopenharmony_ci{ 498862306a36Sopenharmony_ci struct smb_com_transaction2_spi_req *pSMB = NULL; 498962306a36Sopenharmony_ci struct smb_com_transaction2_spi_rsp *pSMBr = NULL; 499062306a36Sopenharmony_ci struct file_end_of_file_info *parm_data; 499162306a36Sopenharmony_ci int name_len; 499262306a36Sopenharmony_ci int rc = 0; 499362306a36Sopenharmony_ci int bytes_returned = 0; 499462306a36Sopenharmony_ci int remap = cifs_remap(cifs_sb); 499562306a36Sopenharmony_ci 499662306a36Sopenharmony_ci __u16 params, byte_count, data_count, param_offset, offset; 499762306a36Sopenharmony_ci 499862306a36Sopenharmony_ci cifs_dbg(FYI, "In SetEOF\n"); 499962306a36Sopenharmony_ciSetEOFRetry: 500062306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 500162306a36Sopenharmony_ci (void **) &pSMBr); 500262306a36Sopenharmony_ci if (rc) 500362306a36Sopenharmony_ci return rc; 500462306a36Sopenharmony_ci 500562306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 500662306a36Sopenharmony_ci name_len = 500762306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name, 500862306a36Sopenharmony_ci PATH_MAX, cifs_sb->local_nls, remap); 500962306a36Sopenharmony_ci name_len++; /* trailing null */ 501062306a36Sopenharmony_ci name_len *= 2; 501162306a36Sopenharmony_ci } else { 501262306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, file_name); 501362306a36Sopenharmony_ci } 501462306a36Sopenharmony_ci params = 6 + name_len; 501562306a36Sopenharmony_ci data_count = sizeof(struct file_end_of_file_info); 501662306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 501762306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(4100); 501862306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 501962306a36Sopenharmony_ci pSMB->Reserved = 0; 502062306a36Sopenharmony_ci pSMB->Flags = 0; 502162306a36Sopenharmony_ci pSMB->Timeout = 0; 502262306a36Sopenharmony_ci pSMB->Reserved2 = 0; 502362306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_spi_req, 502462306a36Sopenharmony_ci InformationLevel) - 4; 502562306a36Sopenharmony_ci offset = param_offset + params; 502662306a36Sopenharmony_ci if (set_allocation) { 502762306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) 502862306a36Sopenharmony_ci pSMB->InformationLevel = 502962306a36Sopenharmony_ci cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); 503062306a36Sopenharmony_ci else 503162306a36Sopenharmony_ci pSMB->InformationLevel = 503262306a36Sopenharmony_ci cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); 503362306a36Sopenharmony_ci } else /* Set File Size */ { 503462306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) 503562306a36Sopenharmony_ci pSMB->InformationLevel = 503662306a36Sopenharmony_ci cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); 503762306a36Sopenharmony_ci else 503862306a36Sopenharmony_ci pSMB->InformationLevel = 503962306a36Sopenharmony_ci cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); 504062306a36Sopenharmony_ci } 504162306a36Sopenharmony_ci 504262306a36Sopenharmony_ci parm_data = 504362306a36Sopenharmony_ci (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + 504462306a36Sopenharmony_ci offset); 504562306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 504662306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 504762306a36Sopenharmony_ci pSMB->SetupCount = 1; 504862306a36Sopenharmony_ci pSMB->Reserved3 = 0; 504962306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); 505062306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + data_count; 505162306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(data_count); 505262306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 505362306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 505462306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 505562306a36Sopenharmony_ci pSMB->Reserved4 = 0; 505662306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 505762306a36Sopenharmony_ci parm_data->FileSize = cpu_to_le64(size); 505862306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 505962306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 506062306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 506162306a36Sopenharmony_ci if (rc) 506262306a36Sopenharmony_ci cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc); 506362306a36Sopenharmony_ci 506462306a36Sopenharmony_ci cifs_buf_release(pSMB); 506562306a36Sopenharmony_ci 506662306a36Sopenharmony_ci if (rc == -EAGAIN) 506762306a36Sopenharmony_ci goto SetEOFRetry; 506862306a36Sopenharmony_ci 506962306a36Sopenharmony_ci return rc; 507062306a36Sopenharmony_ci} 507162306a36Sopenharmony_ci 507262306a36Sopenharmony_ciint 507362306a36Sopenharmony_ciCIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, 507462306a36Sopenharmony_ci struct cifsFileInfo *cfile, __u64 size, bool set_allocation) 507562306a36Sopenharmony_ci{ 507662306a36Sopenharmony_ci struct smb_com_transaction2_sfi_req *pSMB = NULL; 507762306a36Sopenharmony_ci struct file_end_of_file_info *parm_data; 507862306a36Sopenharmony_ci int rc = 0; 507962306a36Sopenharmony_ci __u16 params, param_offset, offset, byte_count, count; 508062306a36Sopenharmony_ci 508162306a36Sopenharmony_ci cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n", 508262306a36Sopenharmony_ci (long long)size); 508362306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); 508462306a36Sopenharmony_ci 508562306a36Sopenharmony_ci if (rc) 508662306a36Sopenharmony_ci return rc; 508762306a36Sopenharmony_ci 508862306a36Sopenharmony_ci pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid); 508962306a36Sopenharmony_ci pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16)); 509062306a36Sopenharmony_ci 509162306a36Sopenharmony_ci params = 6; 509262306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 509362306a36Sopenharmony_ci pSMB->Reserved = 0; 509462306a36Sopenharmony_ci pSMB->Flags = 0; 509562306a36Sopenharmony_ci pSMB->Timeout = 0; 509662306a36Sopenharmony_ci pSMB->Reserved2 = 0; 509762306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; 509862306a36Sopenharmony_ci offset = param_offset + params; 509962306a36Sopenharmony_ci 510062306a36Sopenharmony_ci count = sizeof(struct file_end_of_file_info); 510162306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 510262306a36Sopenharmony_ci /* BB find exact max SMB PDU from sess structure BB */ 510362306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 510462306a36Sopenharmony_ci pSMB->SetupCount = 1; 510562306a36Sopenharmony_ci pSMB->Reserved3 = 0; 510662306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); 510762306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + count; 510862306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(count); 510962306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 511062306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 511162306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 511262306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 511362306a36Sopenharmony_ci /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ 511462306a36Sopenharmony_ci parm_data = 511562306a36Sopenharmony_ci (struct file_end_of_file_info *)(((char *)pSMB) + offset + 4); 511662306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 511762306a36Sopenharmony_ci parm_data->FileSize = cpu_to_le64(size); 511862306a36Sopenharmony_ci pSMB->Fid = cfile->fid.netfid; 511962306a36Sopenharmony_ci if (set_allocation) { 512062306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) 512162306a36Sopenharmony_ci pSMB->InformationLevel = 512262306a36Sopenharmony_ci cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); 512362306a36Sopenharmony_ci else 512462306a36Sopenharmony_ci pSMB->InformationLevel = 512562306a36Sopenharmony_ci cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); 512662306a36Sopenharmony_ci } else /* Set File Size */ { 512762306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) 512862306a36Sopenharmony_ci pSMB->InformationLevel = 512962306a36Sopenharmony_ci cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); 513062306a36Sopenharmony_ci else 513162306a36Sopenharmony_ci pSMB->InformationLevel = 513262306a36Sopenharmony_ci cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); 513362306a36Sopenharmony_ci } 513462306a36Sopenharmony_ci pSMB->Reserved4 = 0; 513562306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 513662306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 513762306a36Sopenharmony_ci rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); 513862306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 513962306a36Sopenharmony_ci if (rc) { 514062306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n", 514162306a36Sopenharmony_ci rc); 514262306a36Sopenharmony_ci } 514362306a36Sopenharmony_ci 514462306a36Sopenharmony_ci /* Note: On -EAGAIN error only caller can retry on handle based calls 514562306a36Sopenharmony_ci since file handle passed in no longer valid */ 514662306a36Sopenharmony_ci 514762306a36Sopenharmony_ci return rc; 514862306a36Sopenharmony_ci} 514962306a36Sopenharmony_ci 515062306a36Sopenharmony_ci/* Some legacy servers such as NT4 require that the file times be set on 515162306a36Sopenharmony_ci an open handle, rather than by pathname - this is awkward due to 515262306a36Sopenharmony_ci potential access conflicts on the open, but it is unavoidable for these 515362306a36Sopenharmony_ci old servers since the only other choice is to go from 100 nanosecond DCE 515462306a36Sopenharmony_ci time and resort to the original setpathinfo level which takes the ancient 515562306a36Sopenharmony_ci DOS time format with 2 second granularity */ 515662306a36Sopenharmony_ciint 515762306a36Sopenharmony_ciCIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, 515862306a36Sopenharmony_ci const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener) 515962306a36Sopenharmony_ci{ 516062306a36Sopenharmony_ci struct smb_com_transaction2_sfi_req *pSMB = NULL; 516162306a36Sopenharmony_ci char *data_offset; 516262306a36Sopenharmony_ci int rc = 0; 516362306a36Sopenharmony_ci __u16 params, param_offset, offset, byte_count, count; 516462306a36Sopenharmony_ci 516562306a36Sopenharmony_ci cifs_dbg(FYI, "Set Times (via SetFileInfo)\n"); 516662306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); 516762306a36Sopenharmony_ci 516862306a36Sopenharmony_ci if (rc) 516962306a36Sopenharmony_ci return rc; 517062306a36Sopenharmony_ci 517162306a36Sopenharmony_ci pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); 517262306a36Sopenharmony_ci pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); 517362306a36Sopenharmony_ci 517462306a36Sopenharmony_ci params = 6; 517562306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 517662306a36Sopenharmony_ci pSMB->Reserved = 0; 517762306a36Sopenharmony_ci pSMB->Flags = 0; 517862306a36Sopenharmony_ci pSMB->Timeout = 0; 517962306a36Sopenharmony_ci pSMB->Reserved2 = 0; 518062306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; 518162306a36Sopenharmony_ci offset = param_offset + params; 518262306a36Sopenharmony_ci 518362306a36Sopenharmony_ci data_offset = (char *)pSMB + 518462306a36Sopenharmony_ci offsetof(struct smb_hdr, Protocol) + offset; 518562306a36Sopenharmony_ci 518662306a36Sopenharmony_ci count = sizeof(FILE_BASIC_INFO); 518762306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 518862306a36Sopenharmony_ci /* BB find max SMB PDU from sess */ 518962306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 519062306a36Sopenharmony_ci pSMB->SetupCount = 1; 519162306a36Sopenharmony_ci pSMB->Reserved3 = 0; 519262306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); 519362306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + count; 519462306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(count); 519562306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 519662306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 519762306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 519862306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 519962306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 520062306a36Sopenharmony_ci pSMB->Fid = fid; 520162306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) 520262306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2); 520362306a36Sopenharmony_ci else 520462306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); 520562306a36Sopenharmony_ci pSMB->Reserved4 = 0; 520662306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 520762306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 520862306a36Sopenharmony_ci memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); 520962306a36Sopenharmony_ci rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); 521062306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 521162306a36Sopenharmony_ci if (rc) 521262306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n", 521362306a36Sopenharmony_ci rc); 521462306a36Sopenharmony_ci 521562306a36Sopenharmony_ci /* Note: On -EAGAIN error only caller can retry on handle based calls 521662306a36Sopenharmony_ci since file handle passed in no longer valid */ 521762306a36Sopenharmony_ci 521862306a36Sopenharmony_ci return rc; 521962306a36Sopenharmony_ci} 522062306a36Sopenharmony_ci 522162306a36Sopenharmony_ciint 522262306a36Sopenharmony_ciCIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, 522362306a36Sopenharmony_ci bool delete_file, __u16 fid, __u32 pid_of_opener) 522462306a36Sopenharmony_ci{ 522562306a36Sopenharmony_ci struct smb_com_transaction2_sfi_req *pSMB = NULL; 522662306a36Sopenharmony_ci char *data_offset; 522762306a36Sopenharmony_ci int rc = 0; 522862306a36Sopenharmony_ci __u16 params, param_offset, offset, byte_count, count; 522962306a36Sopenharmony_ci 523062306a36Sopenharmony_ci cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n"); 523162306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); 523262306a36Sopenharmony_ci 523362306a36Sopenharmony_ci if (rc) 523462306a36Sopenharmony_ci return rc; 523562306a36Sopenharmony_ci 523662306a36Sopenharmony_ci pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); 523762306a36Sopenharmony_ci pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); 523862306a36Sopenharmony_ci 523962306a36Sopenharmony_ci params = 6; 524062306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 524162306a36Sopenharmony_ci pSMB->Reserved = 0; 524262306a36Sopenharmony_ci pSMB->Flags = 0; 524362306a36Sopenharmony_ci pSMB->Timeout = 0; 524462306a36Sopenharmony_ci pSMB->Reserved2 = 0; 524562306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; 524662306a36Sopenharmony_ci offset = param_offset + params; 524762306a36Sopenharmony_ci 524862306a36Sopenharmony_ci /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ 524962306a36Sopenharmony_ci data_offset = (char *)(pSMB) + offset + 4; 525062306a36Sopenharmony_ci 525162306a36Sopenharmony_ci count = 1; 525262306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 525362306a36Sopenharmony_ci /* BB find max SMB PDU from sess */ 525462306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 525562306a36Sopenharmony_ci pSMB->SetupCount = 1; 525662306a36Sopenharmony_ci pSMB->Reserved3 = 0; 525762306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); 525862306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + count; 525962306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(count); 526062306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 526162306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 526262306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 526362306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 526462306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 526562306a36Sopenharmony_ci pSMB->Fid = fid; 526662306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO); 526762306a36Sopenharmony_ci pSMB->Reserved4 = 0; 526862306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 526962306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 527062306a36Sopenharmony_ci *data_offset = delete_file ? 1 : 0; 527162306a36Sopenharmony_ci rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); 527262306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 527362306a36Sopenharmony_ci if (rc) 527462306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc); 527562306a36Sopenharmony_ci 527662306a36Sopenharmony_ci return rc; 527762306a36Sopenharmony_ci} 527862306a36Sopenharmony_ci 527962306a36Sopenharmony_cistatic int 528062306a36Sopenharmony_ciCIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon, 528162306a36Sopenharmony_ci const char *fileName, const FILE_BASIC_INFO *data, 528262306a36Sopenharmony_ci const struct nls_table *nls_codepage, 528362306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 528462306a36Sopenharmony_ci{ 528562306a36Sopenharmony_ci int oplock = 0; 528662306a36Sopenharmony_ci struct cifs_open_parms oparms; 528762306a36Sopenharmony_ci struct cifs_fid fid; 528862306a36Sopenharmony_ci int rc; 528962306a36Sopenharmony_ci 529062306a36Sopenharmony_ci oparms = (struct cifs_open_parms) { 529162306a36Sopenharmony_ci .tcon = tcon, 529262306a36Sopenharmony_ci .cifs_sb = cifs_sb, 529362306a36Sopenharmony_ci .desired_access = GENERIC_WRITE, 529462306a36Sopenharmony_ci .create_options = cifs_create_options(cifs_sb, 0), 529562306a36Sopenharmony_ci .disposition = FILE_OPEN, 529662306a36Sopenharmony_ci .path = fileName, 529762306a36Sopenharmony_ci .fid = &fid, 529862306a36Sopenharmony_ci }; 529962306a36Sopenharmony_ci 530062306a36Sopenharmony_ci rc = CIFS_open(xid, &oparms, &oplock, NULL); 530162306a36Sopenharmony_ci if (rc) 530262306a36Sopenharmony_ci goto out; 530362306a36Sopenharmony_ci 530462306a36Sopenharmony_ci rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid); 530562306a36Sopenharmony_ci CIFSSMBClose(xid, tcon, fid.netfid); 530662306a36Sopenharmony_ciout: 530762306a36Sopenharmony_ci 530862306a36Sopenharmony_ci return rc; 530962306a36Sopenharmony_ci} 531062306a36Sopenharmony_ci 531162306a36Sopenharmony_ciint 531262306a36Sopenharmony_ciCIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, 531362306a36Sopenharmony_ci const char *fileName, const FILE_BASIC_INFO *data, 531462306a36Sopenharmony_ci const struct nls_table *nls_codepage, 531562306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 531662306a36Sopenharmony_ci{ 531762306a36Sopenharmony_ci TRANSACTION2_SPI_REQ *pSMB = NULL; 531862306a36Sopenharmony_ci TRANSACTION2_SPI_RSP *pSMBr = NULL; 531962306a36Sopenharmony_ci int name_len; 532062306a36Sopenharmony_ci int rc = 0; 532162306a36Sopenharmony_ci int bytes_returned = 0; 532262306a36Sopenharmony_ci char *data_offset; 532362306a36Sopenharmony_ci __u16 params, param_offset, offset, byte_count, count; 532462306a36Sopenharmony_ci int remap = cifs_remap(cifs_sb); 532562306a36Sopenharmony_ci 532662306a36Sopenharmony_ci cifs_dbg(FYI, "In SetTimes\n"); 532762306a36Sopenharmony_ci 532862306a36Sopenharmony_ciSetTimesRetry: 532962306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 533062306a36Sopenharmony_ci (void **) &pSMBr); 533162306a36Sopenharmony_ci if (rc) 533262306a36Sopenharmony_ci return rc; 533362306a36Sopenharmony_ci 533462306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 533562306a36Sopenharmony_ci name_len = 533662306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, 533762306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 533862306a36Sopenharmony_ci name_len++; /* trailing null */ 533962306a36Sopenharmony_ci name_len *= 2; 534062306a36Sopenharmony_ci } else { 534162306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, fileName); 534262306a36Sopenharmony_ci } 534362306a36Sopenharmony_ci 534462306a36Sopenharmony_ci params = 6 + name_len; 534562306a36Sopenharmony_ci count = sizeof(FILE_BASIC_INFO); 534662306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 534762306a36Sopenharmony_ci /* BB find max SMB PDU from sess structure BB */ 534862306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 534962306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 535062306a36Sopenharmony_ci pSMB->Reserved = 0; 535162306a36Sopenharmony_ci pSMB->Flags = 0; 535262306a36Sopenharmony_ci pSMB->Timeout = 0; 535362306a36Sopenharmony_ci pSMB->Reserved2 = 0; 535462306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_spi_req, 535562306a36Sopenharmony_ci InformationLevel) - 4; 535662306a36Sopenharmony_ci offset = param_offset + params; 535762306a36Sopenharmony_ci data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 535862306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 535962306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 536062306a36Sopenharmony_ci pSMB->SetupCount = 1; 536162306a36Sopenharmony_ci pSMB->Reserved3 = 0; 536262306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); 536362306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + count; 536462306a36Sopenharmony_ci 536562306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(count); 536662306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 536762306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 536862306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 536962306a36Sopenharmony_ci if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) 537062306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2); 537162306a36Sopenharmony_ci else 537262306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); 537362306a36Sopenharmony_ci pSMB->Reserved4 = 0; 537462306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 537562306a36Sopenharmony_ci memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); 537662306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 537762306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 537862306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 537962306a36Sopenharmony_ci if (rc) 538062306a36Sopenharmony_ci cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc); 538162306a36Sopenharmony_ci 538262306a36Sopenharmony_ci cifs_buf_release(pSMB); 538362306a36Sopenharmony_ci 538462306a36Sopenharmony_ci if (rc == -EAGAIN) 538562306a36Sopenharmony_ci goto SetTimesRetry; 538662306a36Sopenharmony_ci 538762306a36Sopenharmony_ci if (rc == -EOPNOTSUPP) 538862306a36Sopenharmony_ci return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data, 538962306a36Sopenharmony_ci nls_codepage, cifs_sb); 539062306a36Sopenharmony_ci 539162306a36Sopenharmony_ci return rc; 539262306a36Sopenharmony_ci} 539362306a36Sopenharmony_ci 539462306a36Sopenharmony_cistatic void 539562306a36Sopenharmony_cicifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, 539662306a36Sopenharmony_ci const struct cifs_unix_set_info_args *args) 539762306a36Sopenharmony_ci{ 539862306a36Sopenharmony_ci u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64; 539962306a36Sopenharmony_ci u64 mode = args->mode; 540062306a36Sopenharmony_ci 540162306a36Sopenharmony_ci if (uid_valid(args->uid)) 540262306a36Sopenharmony_ci uid = from_kuid(&init_user_ns, args->uid); 540362306a36Sopenharmony_ci if (gid_valid(args->gid)) 540462306a36Sopenharmony_ci gid = from_kgid(&init_user_ns, args->gid); 540562306a36Sopenharmony_ci 540662306a36Sopenharmony_ci /* 540762306a36Sopenharmony_ci * Samba server ignores set of file size to zero due to bugs in some 540862306a36Sopenharmony_ci * older clients, but we should be precise - we use SetFileSize to 540962306a36Sopenharmony_ci * set file size and do not want to truncate file size to zero 541062306a36Sopenharmony_ci * accidentally as happened on one Samba server beta by putting 541162306a36Sopenharmony_ci * zero instead of -1 here 541262306a36Sopenharmony_ci */ 541362306a36Sopenharmony_ci data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); 541462306a36Sopenharmony_ci data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64); 541562306a36Sopenharmony_ci data_offset->LastStatusChange = cpu_to_le64(args->ctime); 541662306a36Sopenharmony_ci data_offset->LastAccessTime = cpu_to_le64(args->atime); 541762306a36Sopenharmony_ci data_offset->LastModificationTime = cpu_to_le64(args->mtime); 541862306a36Sopenharmony_ci data_offset->Uid = cpu_to_le64(uid); 541962306a36Sopenharmony_ci data_offset->Gid = cpu_to_le64(gid); 542062306a36Sopenharmony_ci /* better to leave device as zero when it is */ 542162306a36Sopenharmony_ci data_offset->DevMajor = cpu_to_le64(MAJOR(args->device)); 542262306a36Sopenharmony_ci data_offset->DevMinor = cpu_to_le64(MINOR(args->device)); 542362306a36Sopenharmony_ci data_offset->Permissions = cpu_to_le64(mode); 542462306a36Sopenharmony_ci 542562306a36Sopenharmony_ci if (S_ISREG(mode)) 542662306a36Sopenharmony_ci data_offset->Type = cpu_to_le32(UNIX_FILE); 542762306a36Sopenharmony_ci else if (S_ISDIR(mode)) 542862306a36Sopenharmony_ci data_offset->Type = cpu_to_le32(UNIX_DIR); 542962306a36Sopenharmony_ci else if (S_ISLNK(mode)) 543062306a36Sopenharmony_ci data_offset->Type = cpu_to_le32(UNIX_SYMLINK); 543162306a36Sopenharmony_ci else if (S_ISCHR(mode)) 543262306a36Sopenharmony_ci data_offset->Type = cpu_to_le32(UNIX_CHARDEV); 543362306a36Sopenharmony_ci else if (S_ISBLK(mode)) 543462306a36Sopenharmony_ci data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV); 543562306a36Sopenharmony_ci else if (S_ISFIFO(mode)) 543662306a36Sopenharmony_ci data_offset->Type = cpu_to_le32(UNIX_FIFO); 543762306a36Sopenharmony_ci else if (S_ISSOCK(mode)) 543862306a36Sopenharmony_ci data_offset->Type = cpu_to_le32(UNIX_SOCKET); 543962306a36Sopenharmony_ci} 544062306a36Sopenharmony_ci 544162306a36Sopenharmony_ciint 544262306a36Sopenharmony_ciCIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, 544362306a36Sopenharmony_ci const struct cifs_unix_set_info_args *args, 544462306a36Sopenharmony_ci u16 fid, u32 pid_of_opener) 544562306a36Sopenharmony_ci{ 544662306a36Sopenharmony_ci struct smb_com_transaction2_sfi_req *pSMB = NULL; 544762306a36Sopenharmony_ci char *data_offset; 544862306a36Sopenharmony_ci int rc = 0; 544962306a36Sopenharmony_ci u16 params, param_offset, offset, byte_count, count; 545062306a36Sopenharmony_ci 545162306a36Sopenharmony_ci cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n"); 545262306a36Sopenharmony_ci rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); 545362306a36Sopenharmony_ci 545462306a36Sopenharmony_ci if (rc) 545562306a36Sopenharmony_ci return rc; 545662306a36Sopenharmony_ci 545762306a36Sopenharmony_ci pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); 545862306a36Sopenharmony_ci pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); 545962306a36Sopenharmony_ci 546062306a36Sopenharmony_ci params = 6; 546162306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 546262306a36Sopenharmony_ci pSMB->Reserved = 0; 546362306a36Sopenharmony_ci pSMB->Flags = 0; 546462306a36Sopenharmony_ci pSMB->Timeout = 0; 546562306a36Sopenharmony_ci pSMB->Reserved2 = 0; 546662306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; 546762306a36Sopenharmony_ci offset = param_offset + params; 546862306a36Sopenharmony_ci 546962306a36Sopenharmony_ci data_offset = (char *)pSMB + 547062306a36Sopenharmony_ci offsetof(struct smb_hdr, Protocol) + offset; 547162306a36Sopenharmony_ci 547262306a36Sopenharmony_ci count = sizeof(FILE_UNIX_BASIC_INFO); 547362306a36Sopenharmony_ci 547462306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 547562306a36Sopenharmony_ci /* BB find max SMB PDU from sess */ 547662306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 547762306a36Sopenharmony_ci pSMB->SetupCount = 1; 547862306a36Sopenharmony_ci pSMB->Reserved3 = 0; 547962306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); 548062306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + count; 548162306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(count); 548262306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 548362306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 548462306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 548562306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 548662306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 548762306a36Sopenharmony_ci pSMB->Fid = fid; 548862306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); 548962306a36Sopenharmony_ci pSMB->Reserved4 = 0; 549062306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 549162306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 549262306a36Sopenharmony_ci 549362306a36Sopenharmony_ci cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args); 549462306a36Sopenharmony_ci 549562306a36Sopenharmony_ci rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); 549662306a36Sopenharmony_ci cifs_small_buf_release(pSMB); 549762306a36Sopenharmony_ci if (rc) 549862306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n", 549962306a36Sopenharmony_ci rc); 550062306a36Sopenharmony_ci 550162306a36Sopenharmony_ci /* Note: On -EAGAIN error only caller can retry on handle based calls 550262306a36Sopenharmony_ci since file handle passed in no longer valid */ 550362306a36Sopenharmony_ci 550462306a36Sopenharmony_ci return rc; 550562306a36Sopenharmony_ci} 550662306a36Sopenharmony_ci 550762306a36Sopenharmony_ciint 550862306a36Sopenharmony_ciCIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, 550962306a36Sopenharmony_ci const char *file_name, 551062306a36Sopenharmony_ci const struct cifs_unix_set_info_args *args, 551162306a36Sopenharmony_ci const struct nls_table *nls_codepage, int remap) 551262306a36Sopenharmony_ci{ 551362306a36Sopenharmony_ci TRANSACTION2_SPI_REQ *pSMB = NULL; 551462306a36Sopenharmony_ci TRANSACTION2_SPI_RSP *pSMBr = NULL; 551562306a36Sopenharmony_ci int name_len; 551662306a36Sopenharmony_ci int rc = 0; 551762306a36Sopenharmony_ci int bytes_returned = 0; 551862306a36Sopenharmony_ci FILE_UNIX_BASIC_INFO *data_offset; 551962306a36Sopenharmony_ci __u16 params, param_offset, offset, count, byte_count; 552062306a36Sopenharmony_ci 552162306a36Sopenharmony_ci cifs_dbg(FYI, "In SetUID/GID/Mode\n"); 552262306a36Sopenharmony_cisetPermsRetry: 552362306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 552462306a36Sopenharmony_ci (void **) &pSMBr); 552562306a36Sopenharmony_ci if (rc) 552662306a36Sopenharmony_ci return rc; 552762306a36Sopenharmony_ci 552862306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 552962306a36Sopenharmony_ci name_len = 553062306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name, 553162306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 553262306a36Sopenharmony_ci name_len++; /* trailing null */ 553362306a36Sopenharmony_ci name_len *= 2; 553462306a36Sopenharmony_ci } else { 553562306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, file_name); 553662306a36Sopenharmony_ci } 553762306a36Sopenharmony_ci 553862306a36Sopenharmony_ci params = 6 + name_len; 553962306a36Sopenharmony_ci count = sizeof(FILE_UNIX_BASIC_INFO); 554062306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 554162306a36Sopenharmony_ci /* BB find max SMB PDU from sess structure BB */ 554262306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 554362306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 554462306a36Sopenharmony_ci pSMB->Reserved = 0; 554562306a36Sopenharmony_ci pSMB->Flags = 0; 554662306a36Sopenharmony_ci pSMB->Timeout = 0; 554762306a36Sopenharmony_ci pSMB->Reserved2 = 0; 554862306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_spi_req, 554962306a36Sopenharmony_ci InformationLevel) - 4; 555062306a36Sopenharmony_ci offset = param_offset + params; 555162306a36Sopenharmony_ci /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ 555262306a36Sopenharmony_ci data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4); 555362306a36Sopenharmony_ci memset(data_offset, 0, count); 555462306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 555562306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 555662306a36Sopenharmony_ci pSMB->SetupCount = 1; 555762306a36Sopenharmony_ci pSMB->Reserved3 = 0; 555862306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); 555962306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + count; 556062306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 556162306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(count); 556262306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 556362306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 556462306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); 556562306a36Sopenharmony_ci pSMB->Reserved4 = 0; 556662306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 556762306a36Sopenharmony_ci 556862306a36Sopenharmony_ci cifs_fill_unix_set_info(data_offset, args); 556962306a36Sopenharmony_ci 557062306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 557162306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 557262306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 557362306a36Sopenharmony_ci if (rc) 557462306a36Sopenharmony_ci cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc); 557562306a36Sopenharmony_ci 557662306a36Sopenharmony_ci cifs_buf_release(pSMB); 557762306a36Sopenharmony_ci if (rc == -EAGAIN) 557862306a36Sopenharmony_ci goto setPermsRetry; 557962306a36Sopenharmony_ci return rc; 558062306a36Sopenharmony_ci} 558162306a36Sopenharmony_ci 558262306a36Sopenharmony_ci#ifdef CONFIG_CIFS_XATTR 558362306a36Sopenharmony_ci/* 558462306a36Sopenharmony_ci * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common 558562306a36Sopenharmony_ci * function used by listxattr and getxattr type calls. When ea_name is set, 558662306a36Sopenharmony_ci * it looks for that attribute name and stuffs that value into the EAData 558762306a36Sopenharmony_ci * buffer. When ea_name is NULL, it stuffs a list of attribute names into the 558862306a36Sopenharmony_ci * buffer. In both cases, the return value is either the length of the 558962306a36Sopenharmony_ci * resulting data or a negative error code. If EAData is a NULL pointer then 559062306a36Sopenharmony_ci * the data isn't copied to it, but the length is returned. 559162306a36Sopenharmony_ci */ 559262306a36Sopenharmony_cissize_t 559362306a36Sopenharmony_ciCIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, 559462306a36Sopenharmony_ci const unsigned char *searchName, const unsigned char *ea_name, 559562306a36Sopenharmony_ci char *EAData, size_t buf_size, 559662306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 559762306a36Sopenharmony_ci{ 559862306a36Sopenharmony_ci /* BB assumes one setup word */ 559962306a36Sopenharmony_ci TRANSACTION2_QPI_REQ *pSMB = NULL; 560062306a36Sopenharmony_ci TRANSACTION2_QPI_RSP *pSMBr = NULL; 560162306a36Sopenharmony_ci int remap = cifs_remap(cifs_sb); 560262306a36Sopenharmony_ci struct nls_table *nls_codepage = cifs_sb->local_nls; 560362306a36Sopenharmony_ci int rc = 0; 560462306a36Sopenharmony_ci int bytes_returned; 560562306a36Sopenharmony_ci int list_len; 560662306a36Sopenharmony_ci struct fealist *ea_response_data; 560762306a36Sopenharmony_ci struct fea *temp_fea; 560862306a36Sopenharmony_ci char *temp_ptr; 560962306a36Sopenharmony_ci char *end_of_smb; 561062306a36Sopenharmony_ci __u16 params, byte_count, data_offset; 561162306a36Sopenharmony_ci unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0; 561262306a36Sopenharmony_ci 561362306a36Sopenharmony_ci cifs_dbg(FYI, "In Query All EAs path %s\n", searchName); 561462306a36Sopenharmony_ciQAllEAsRetry: 561562306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 561662306a36Sopenharmony_ci (void **) &pSMBr); 561762306a36Sopenharmony_ci if (rc) 561862306a36Sopenharmony_ci return rc; 561962306a36Sopenharmony_ci 562062306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 562162306a36Sopenharmony_ci list_len = 562262306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, 562362306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 562462306a36Sopenharmony_ci list_len++; /* trailing null */ 562562306a36Sopenharmony_ci list_len *= 2; 562662306a36Sopenharmony_ci } else { 562762306a36Sopenharmony_ci list_len = copy_path_name(pSMB->FileName, searchName); 562862306a36Sopenharmony_ci } 562962306a36Sopenharmony_ci 563062306a36Sopenharmony_ci params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */; 563162306a36Sopenharmony_ci pSMB->TotalDataCount = 0; 563262306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 563362306a36Sopenharmony_ci /* BB find exact max SMB PDU from sess structure BB */ 563462306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize); 563562306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 563662306a36Sopenharmony_ci pSMB->Reserved = 0; 563762306a36Sopenharmony_ci pSMB->Flags = 0; 563862306a36Sopenharmony_ci pSMB->Timeout = 0; 563962306a36Sopenharmony_ci pSMB->Reserved2 = 0; 564062306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(offsetof( 564162306a36Sopenharmony_ci struct smb_com_transaction2_qpi_req, InformationLevel) - 4); 564262306a36Sopenharmony_ci pSMB->DataCount = 0; 564362306a36Sopenharmony_ci pSMB->DataOffset = 0; 564462306a36Sopenharmony_ci pSMB->SetupCount = 1; 564562306a36Sopenharmony_ci pSMB->Reserved3 = 0; 564662306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); 564762306a36Sopenharmony_ci byte_count = params + 1 /* pad */ ; 564862306a36Sopenharmony_ci pSMB->TotalParameterCount = cpu_to_le16(params); 564962306a36Sopenharmony_ci pSMB->ParameterCount = pSMB->TotalParameterCount; 565062306a36Sopenharmony_ci pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); 565162306a36Sopenharmony_ci pSMB->Reserved4 = 0; 565262306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 565362306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 565462306a36Sopenharmony_ci 565562306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 565662306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 565762306a36Sopenharmony_ci if (rc) { 565862306a36Sopenharmony_ci cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc); 565962306a36Sopenharmony_ci goto QAllEAsOut; 566062306a36Sopenharmony_ci } 566162306a36Sopenharmony_ci 566262306a36Sopenharmony_ci 566362306a36Sopenharmony_ci /* BB also check enough total bytes returned */ 566462306a36Sopenharmony_ci /* BB we need to improve the validity checking 566562306a36Sopenharmony_ci of these trans2 responses */ 566662306a36Sopenharmony_ci 566762306a36Sopenharmony_ci rc = validate_t2((struct smb_t2_rsp *)pSMBr); 566862306a36Sopenharmony_ci if (rc || get_bcc(&pSMBr->hdr) < 4) { 566962306a36Sopenharmony_ci rc = -EIO; /* bad smb */ 567062306a36Sopenharmony_ci goto QAllEAsOut; 567162306a36Sopenharmony_ci } 567262306a36Sopenharmony_ci 567362306a36Sopenharmony_ci /* check that length of list is not more than bcc */ 567462306a36Sopenharmony_ci /* check that each entry does not go beyond length 567562306a36Sopenharmony_ci of list */ 567662306a36Sopenharmony_ci /* check that each element of each entry does not 567762306a36Sopenharmony_ci go beyond end of list */ 567862306a36Sopenharmony_ci /* validate_trans2_offsets() */ 567962306a36Sopenharmony_ci /* BB check if start of smb + data_offset > &bcc+ bcc */ 568062306a36Sopenharmony_ci 568162306a36Sopenharmony_ci data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 568262306a36Sopenharmony_ci ea_response_data = (struct fealist *) 568362306a36Sopenharmony_ci (((char *) &pSMBr->hdr.Protocol) + data_offset); 568462306a36Sopenharmony_ci 568562306a36Sopenharmony_ci list_len = le32_to_cpu(ea_response_data->list_len); 568662306a36Sopenharmony_ci cifs_dbg(FYI, "ea length %d\n", list_len); 568762306a36Sopenharmony_ci if (list_len <= 8) { 568862306a36Sopenharmony_ci cifs_dbg(FYI, "empty EA list returned from server\n"); 568962306a36Sopenharmony_ci /* didn't find the named attribute */ 569062306a36Sopenharmony_ci if (ea_name) 569162306a36Sopenharmony_ci rc = -ENODATA; 569262306a36Sopenharmony_ci goto QAllEAsOut; 569362306a36Sopenharmony_ci } 569462306a36Sopenharmony_ci 569562306a36Sopenharmony_ci /* make sure list_len doesn't go past end of SMB */ 569662306a36Sopenharmony_ci end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr); 569762306a36Sopenharmony_ci if ((char *)ea_response_data + list_len > end_of_smb) { 569862306a36Sopenharmony_ci cifs_dbg(FYI, "EA list appears to go beyond SMB\n"); 569962306a36Sopenharmony_ci rc = -EIO; 570062306a36Sopenharmony_ci goto QAllEAsOut; 570162306a36Sopenharmony_ci } 570262306a36Sopenharmony_ci 570362306a36Sopenharmony_ci /* account for ea list len */ 570462306a36Sopenharmony_ci list_len -= 4; 570562306a36Sopenharmony_ci temp_fea = &ea_response_data->list; 570662306a36Sopenharmony_ci temp_ptr = (char *)temp_fea; 570762306a36Sopenharmony_ci while (list_len > 0) { 570862306a36Sopenharmony_ci unsigned int name_len; 570962306a36Sopenharmony_ci __u16 value_len; 571062306a36Sopenharmony_ci 571162306a36Sopenharmony_ci list_len -= 4; 571262306a36Sopenharmony_ci temp_ptr += 4; 571362306a36Sopenharmony_ci /* make sure we can read name_len and value_len */ 571462306a36Sopenharmony_ci if (list_len < 0) { 571562306a36Sopenharmony_ci cifs_dbg(FYI, "EA entry goes beyond length of list\n"); 571662306a36Sopenharmony_ci rc = -EIO; 571762306a36Sopenharmony_ci goto QAllEAsOut; 571862306a36Sopenharmony_ci } 571962306a36Sopenharmony_ci 572062306a36Sopenharmony_ci name_len = temp_fea->name_len; 572162306a36Sopenharmony_ci value_len = le16_to_cpu(temp_fea->value_len); 572262306a36Sopenharmony_ci list_len -= name_len + 1 + value_len; 572362306a36Sopenharmony_ci if (list_len < 0) { 572462306a36Sopenharmony_ci cifs_dbg(FYI, "EA entry goes beyond length of list\n"); 572562306a36Sopenharmony_ci rc = -EIO; 572662306a36Sopenharmony_ci goto QAllEAsOut; 572762306a36Sopenharmony_ci } 572862306a36Sopenharmony_ci 572962306a36Sopenharmony_ci if (ea_name) { 573062306a36Sopenharmony_ci if (ea_name_len == name_len && 573162306a36Sopenharmony_ci memcmp(ea_name, temp_ptr, name_len) == 0) { 573262306a36Sopenharmony_ci temp_ptr += name_len + 1; 573362306a36Sopenharmony_ci rc = value_len; 573462306a36Sopenharmony_ci if (buf_size == 0) 573562306a36Sopenharmony_ci goto QAllEAsOut; 573662306a36Sopenharmony_ci if ((size_t)value_len > buf_size) { 573762306a36Sopenharmony_ci rc = -ERANGE; 573862306a36Sopenharmony_ci goto QAllEAsOut; 573962306a36Sopenharmony_ci } 574062306a36Sopenharmony_ci memcpy(EAData, temp_ptr, value_len); 574162306a36Sopenharmony_ci goto QAllEAsOut; 574262306a36Sopenharmony_ci } 574362306a36Sopenharmony_ci } else { 574462306a36Sopenharmony_ci /* account for prefix user. and trailing null */ 574562306a36Sopenharmony_ci rc += (5 + 1 + name_len); 574662306a36Sopenharmony_ci if (rc < (int) buf_size) { 574762306a36Sopenharmony_ci memcpy(EAData, "user.", 5); 574862306a36Sopenharmony_ci EAData += 5; 574962306a36Sopenharmony_ci memcpy(EAData, temp_ptr, name_len); 575062306a36Sopenharmony_ci EAData += name_len; 575162306a36Sopenharmony_ci /* null terminate name */ 575262306a36Sopenharmony_ci *EAData = 0; 575362306a36Sopenharmony_ci ++EAData; 575462306a36Sopenharmony_ci } else if (buf_size == 0) { 575562306a36Sopenharmony_ci /* skip copy - calc size only */ 575662306a36Sopenharmony_ci } else { 575762306a36Sopenharmony_ci /* stop before overrun buffer */ 575862306a36Sopenharmony_ci rc = -ERANGE; 575962306a36Sopenharmony_ci break; 576062306a36Sopenharmony_ci } 576162306a36Sopenharmony_ci } 576262306a36Sopenharmony_ci temp_ptr += name_len + 1 + value_len; 576362306a36Sopenharmony_ci temp_fea = (struct fea *)temp_ptr; 576462306a36Sopenharmony_ci } 576562306a36Sopenharmony_ci 576662306a36Sopenharmony_ci /* didn't find the named attribute */ 576762306a36Sopenharmony_ci if (ea_name) 576862306a36Sopenharmony_ci rc = -ENODATA; 576962306a36Sopenharmony_ci 577062306a36Sopenharmony_ciQAllEAsOut: 577162306a36Sopenharmony_ci cifs_buf_release(pSMB); 577262306a36Sopenharmony_ci if (rc == -EAGAIN) 577362306a36Sopenharmony_ci goto QAllEAsRetry; 577462306a36Sopenharmony_ci 577562306a36Sopenharmony_ci return (ssize_t)rc; 577662306a36Sopenharmony_ci} 577762306a36Sopenharmony_ci 577862306a36Sopenharmony_ciint 577962306a36Sopenharmony_ciCIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, 578062306a36Sopenharmony_ci const char *fileName, const char *ea_name, const void *ea_value, 578162306a36Sopenharmony_ci const __u16 ea_value_len, const struct nls_table *nls_codepage, 578262306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 578362306a36Sopenharmony_ci{ 578462306a36Sopenharmony_ci struct smb_com_transaction2_spi_req *pSMB = NULL; 578562306a36Sopenharmony_ci struct smb_com_transaction2_spi_rsp *pSMBr = NULL; 578662306a36Sopenharmony_ci struct fealist *parm_data; 578762306a36Sopenharmony_ci int name_len; 578862306a36Sopenharmony_ci int rc = 0; 578962306a36Sopenharmony_ci int bytes_returned = 0; 579062306a36Sopenharmony_ci __u16 params, param_offset, byte_count, offset, count; 579162306a36Sopenharmony_ci int remap = cifs_remap(cifs_sb); 579262306a36Sopenharmony_ci 579362306a36Sopenharmony_ci cifs_dbg(FYI, "In SetEA\n"); 579462306a36Sopenharmony_ciSetEARetry: 579562306a36Sopenharmony_ci rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 579662306a36Sopenharmony_ci (void **) &pSMBr); 579762306a36Sopenharmony_ci if (rc) 579862306a36Sopenharmony_ci return rc; 579962306a36Sopenharmony_ci 580062306a36Sopenharmony_ci if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 580162306a36Sopenharmony_ci name_len = 580262306a36Sopenharmony_ci cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, 580362306a36Sopenharmony_ci PATH_MAX, nls_codepage, remap); 580462306a36Sopenharmony_ci name_len++; /* trailing null */ 580562306a36Sopenharmony_ci name_len *= 2; 580662306a36Sopenharmony_ci } else { 580762306a36Sopenharmony_ci name_len = copy_path_name(pSMB->FileName, fileName); 580862306a36Sopenharmony_ci } 580962306a36Sopenharmony_ci 581062306a36Sopenharmony_ci params = 6 + name_len; 581162306a36Sopenharmony_ci 581262306a36Sopenharmony_ci /* done calculating parms using name_len of file name, 581362306a36Sopenharmony_ci now use name_len to calculate length of ea name 581462306a36Sopenharmony_ci we are going to create in the inode xattrs */ 581562306a36Sopenharmony_ci if (ea_name == NULL) 581662306a36Sopenharmony_ci name_len = 0; 581762306a36Sopenharmony_ci else 581862306a36Sopenharmony_ci name_len = strnlen(ea_name, 255); 581962306a36Sopenharmony_ci 582062306a36Sopenharmony_ci count = sizeof(*parm_data) + 1 + ea_value_len + name_len; 582162306a36Sopenharmony_ci pSMB->MaxParameterCount = cpu_to_le16(2); 582262306a36Sopenharmony_ci /* BB find max SMB PDU from sess */ 582362306a36Sopenharmony_ci pSMB->MaxDataCount = cpu_to_le16(1000); 582462306a36Sopenharmony_ci pSMB->MaxSetupCount = 0; 582562306a36Sopenharmony_ci pSMB->Reserved = 0; 582662306a36Sopenharmony_ci pSMB->Flags = 0; 582762306a36Sopenharmony_ci pSMB->Timeout = 0; 582862306a36Sopenharmony_ci pSMB->Reserved2 = 0; 582962306a36Sopenharmony_ci param_offset = offsetof(struct smb_com_transaction2_spi_req, 583062306a36Sopenharmony_ci InformationLevel) - 4; 583162306a36Sopenharmony_ci offset = param_offset + params; 583262306a36Sopenharmony_ci pSMB->InformationLevel = 583362306a36Sopenharmony_ci cpu_to_le16(SMB_SET_FILE_EA); 583462306a36Sopenharmony_ci 583562306a36Sopenharmony_ci parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset; 583662306a36Sopenharmony_ci pSMB->ParameterOffset = cpu_to_le16(param_offset); 583762306a36Sopenharmony_ci pSMB->DataOffset = cpu_to_le16(offset); 583862306a36Sopenharmony_ci pSMB->SetupCount = 1; 583962306a36Sopenharmony_ci pSMB->Reserved3 = 0; 584062306a36Sopenharmony_ci pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); 584162306a36Sopenharmony_ci byte_count = 3 /* pad */ + params + count; 584262306a36Sopenharmony_ci pSMB->DataCount = cpu_to_le16(count); 584362306a36Sopenharmony_ci parm_data->list_len = cpu_to_le32(count); 584462306a36Sopenharmony_ci parm_data->list.EA_flags = 0; 584562306a36Sopenharmony_ci /* we checked above that name len is less than 255 */ 584662306a36Sopenharmony_ci parm_data->list.name_len = (__u8)name_len; 584762306a36Sopenharmony_ci /* EA names are always ASCII */ 584862306a36Sopenharmony_ci if (ea_name) 584962306a36Sopenharmony_ci strncpy(parm_data->list.name, ea_name, name_len); 585062306a36Sopenharmony_ci parm_data->list.name[name_len] = '\0'; 585162306a36Sopenharmony_ci parm_data->list.value_len = cpu_to_le16(ea_value_len); 585262306a36Sopenharmony_ci /* caller ensures that ea_value_len is less than 64K but 585362306a36Sopenharmony_ci we need to ensure that it fits within the smb */ 585462306a36Sopenharmony_ci 585562306a36Sopenharmony_ci /*BB add length check to see if it would fit in 585662306a36Sopenharmony_ci negotiated SMB buffer size BB */ 585762306a36Sopenharmony_ci /* if (ea_value_len > buffer_size - 512 (enough for header)) */ 585862306a36Sopenharmony_ci if (ea_value_len) 585962306a36Sopenharmony_ci memcpy(parm_data->list.name + name_len + 1, 586062306a36Sopenharmony_ci ea_value, ea_value_len); 586162306a36Sopenharmony_ci 586262306a36Sopenharmony_ci pSMB->TotalDataCount = pSMB->DataCount; 586362306a36Sopenharmony_ci pSMB->ParameterCount = cpu_to_le16(params); 586462306a36Sopenharmony_ci pSMB->TotalParameterCount = pSMB->ParameterCount; 586562306a36Sopenharmony_ci pSMB->Reserved4 = 0; 586662306a36Sopenharmony_ci inc_rfc1001_len(pSMB, byte_count); 586762306a36Sopenharmony_ci pSMB->ByteCount = cpu_to_le16(byte_count); 586862306a36Sopenharmony_ci rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 586962306a36Sopenharmony_ci (struct smb_hdr *) pSMBr, &bytes_returned, 0); 587062306a36Sopenharmony_ci if (rc) 587162306a36Sopenharmony_ci cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc); 587262306a36Sopenharmony_ci 587362306a36Sopenharmony_ci cifs_buf_release(pSMB); 587462306a36Sopenharmony_ci 587562306a36Sopenharmony_ci if (rc == -EAGAIN) 587662306a36Sopenharmony_ci goto SetEARetry; 587762306a36Sopenharmony_ci 587862306a36Sopenharmony_ci return rc; 587962306a36Sopenharmony_ci} 588062306a36Sopenharmony_ci#endif 5881