| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | *   fs/cifs/cifssmb.c | 
|  | 3 | * | 
|  | 4 | *   Copyright (C) International Business Machines  Corp., 2002,2010 | 
|  | 5 | *   Author(s): Steve French (sfrench@us.ibm.com) | 
|  | 6 | * | 
|  | 7 | *   Contains the routines for constructing the SMB PDUs themselves | 
|  | 8 | * | 
|  | 9 | *   This library is free software; you can redistribute it and/or modify | 
|  | 10 | *   it under the terms of the GNU Lesser General Public License as published | 
|  | 11 | *   by the Free Software Foundation; either version 2.1 of the License, or | 
|  | 12 | *   (at your option) any later version. | 
|  | 13 | * | 
|  | 14 | *   This library is distributed in the hope that it will be useful, | 
|  | 15 | *   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 16 | *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See | 
|  | 17 | *   the GNU Lesser General Public License for more details. | 
|  | 18 | * | 
|  | 19 | *   You should have received a copy of the GNU Lesser General Public License | 
|  | 20 | *   along with this library; if not, write to the Free Software | 
|  | 21 | *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 
|  | 22 | */ | 
|  | 23 |  | 
|  | 24 | /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */ | 
|  | 25 | /* These are mostly routines that operate on a pathname, or on a tree id     */ | 
|  | 26 | /* (mounted volume), but there are eight handle based routines which must be */ | 
|  | 27 | /* treated slightly differently for reconnection purposes since we never     */ | 
|  | 28 | /* want to reuse a stale file handle and only the caller knows the file info */ | 
|  | 29 |  | 
|  | 30 | #include <linux/fs.h> | 
|  | 31 | #include <linux/kernel.h> | 
|  | 32 | #include <linux/vfs.h> | 
|  | 33 | #include <linux/slab.h> | 
|  | 34 | #include <linux/posix_acl_xattr.h> | 
|  | 35 | #include <linux/pagemap.h> | 
|  | 36 | #include <linux/swap.h> | 
|  | 37 | #include <linux/task_io_accounting_ops.h> | 
|  | 38 | #include <linux/uaccess.h> | 
|  | 39 | #include "cifspdu.h" | 
|  | 40 | #include "cifsglob.h" | 
|  | 41 | #include "cifsacl.h" | 
|  | 42 | #include "cifsproto.h" | 
|  | 43 | #include "cifs_unicode.h" | 
|  | 44 | #include "cifs_debug.h" | 
|  | 45 | #include "fscache.h" | 
|  | 46 | #include "smbdirect.h" | 
|  | 47 |  | 
|  | 48 | #ifdef CONFIG_CIFS_POSIX | 
|  | 49 | static struct { | 
|  | 50 | int index; | 
|  | 51 | char *name; | 
|  | 52 | } protocols[] = { | 
|  | 53 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 
|  | 54 | {LANMAN_PROT, "\2LM1.2X002"}, | 
|  | 55 | {LANMAN2_PROT, "\2LANMAN2.1"}, | 
|  | 56 | #endif /* weak password hashing for legacy clients */ | 
|  | 57 | {CIFS_PROT, "\2NT LM 0.12"}, | 
|  | 58 | {POSIX_PROT, "\2POSIX 2"}, | 
|  | 59 | {BAD_PROT, "\2"} | 
|  | 60 | }; | 
|  | 61 | #else | 
|  | 62 | static struct { | 
|  | 63 | int index; | 
|  | 64 | char *name; | 
|  | 65 | } protocols[] = { | 
|  | 66 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 
|  | 67 | {LANMAN_PROT, "\2LM1.2X002"}, | 
|  | 68 | {LANMAN2_PROT, "\2LANMAN2.1"}, | 
|  | 69 | #endif /* weak password hashing for legacy clients */ | 
|  | 70 | {CIFS_PROT, "\2NT LM 0.12"}, | 
|  | 71 | {BAD_PROT, "\2"} | 
|  | 72 | }; | 
|  | 73 | #endif | 
|  | 74 |  | 
|  | 75 | /* define the number of elements in the cifs dialect array */ | 
|  | 76 | #ifdef CONFIG_CIFS_POSIX | 
|  | 77 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 
|  | 78 | #define CIFS_NUM_PROT 4 | 
|  | 79 | #else | 
|  | 80 | #define CIFS_NUM_PROT 2 | 
|  | 81 | #endif /* CIFS_WEAK_PW_HASH */ | 
|  | 82 | #else /* not posix */ | 
|  | 83 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 
|  | 84 | #define CIFS_NUM_PROT 3 | 
|  | 85 | #else | 
|  | 86 | #define CIFS_NUM_PROT 1 | 
|  | 87 | #endif /* CONFIG_CIFS_WEAK_PW_HASH */ | 
|  | 88 | #endif /* CIFS_POSIX */ | 
|  | 89 |  | 
|  | 90 | /* | 
|  | 91 | * Mark as invalid, all open files on tree connections since they | 
|  | 92 | * were closed when session to server was lost. | 
|  | 93 | */ | 
|  | 94 | void | 
|  | 95 | cifs_mark_open_files_invalid(struct cifs_tcon *tcon) | 
|  | 96 | { | 
|  | 97 | struct cifsFileInfo *open_file = NULL; | 
|  | 98 | struct list_head *tmp; | 
|  | 99 | struct list_head *tmp1; | 
|  | 100 |  | 
|  | 101 | /* list all files open on tree connection and mark them invalid */ | 
|  | 102 | spin_lock(&tcon->open_file_lock); | 
|  | 103 | list_for_each_safe(tmp, tmp1, &tcon->openFileList) { | 
|  | 104 | open_file = list_entry(tmp, struct cifsFileInfo, tlist); | 
|  | 105 | open_file->invalidHandle = true; | 
|  | 106 | open_file->oplock_break_cancelled = true; | 
|  | 107 | } | 
|  | 108 | spin_unlock(&tcon->open_file_lock); | 
|  | 109 |  | 
|  | 110 | mutex_lock(&tcon->crfid.fid_mutex); | 
|  | 111 | tcon->crfid.is_valid = false; | 
|  | 112 | memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid)); | 
|  | 113 | mutex_unlock(&tcon->crfid.fid_mutex); | 
|  | 114 |  | 
|  | 115 | /* | 
|  | 116 | * BB Add call to invalidate_inodes(sb) for all superblocks mounted | 
|  | 117 | * to this tcon. | 
|  | 118 | */ | 
|  | 119 | } | 
|  | 120 |  | 
|  | 121 | /* reconnect the socket, tcon, and smb session if needed */ | 
|  | 122 | static int | 
|  | 123 | cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) | 
|  | 124 | { | 
|  | 125 | int rc; | 
|  | 126 | struct cifs_ses *ses; | 
|  | 127 | struct TCP_Server_Info *server; | 
|  | 128 | struct nls_table *nls_codepage; | 
|  | 129 |  | 
|  | 130 | /* | 
|  | 131 | * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for | 
|  | 132 | * tcp and smb session status done differently for those three - in the | 
|  | 133 | * calling routine | 
|  | 134 | */ | 
|  | 135 | if (!tcon) | 
|  | 136 | return 0; | 
|  | 137 |  | 
|  | 138 | ses = tcon->ses; | 
|  | 139 | server = ses->server; | 
|  | 140 |  | 
|  | 141 | /* | 
|  | 142 | * only tree disconnect, open, and write, (and ulogoff which does not | 
|  | 143 | * have tcon) are allowed as we start force umount | 
|  | 144 | */ | 
|  | 145 | if (tcon->tidStatus == CifsExiting) { | 
|  | 146 | if (smb_command != SMB_COM_WRITE_ANDX && | 
|  | 147 | smb_command != SMB_COM_OPEN_ANDX && | 
|  | 148 | smb_command != SMB_COM_TREE_DISCONNECT) { | 
|  | 149 | cifs_dbg(FYI, "can not send cmd %d while umounting\n", | 
|  | 150 | smb_command); | 
|  | 151 | return -ENODEV; | 
|  | 152 | } | 
|  | 153 | } | 
|  | 154 |  | 
|  | 155 | /* | 
|  | 156 | * Give demultiplex thread up to 10 seconds to reconnect, should be | 
|  | 157 | * greater than cifs socket timeout which is 7 seconds | 
|  | 158 | */ | 
|  | 159 | while (server->tcpStatus == CifsNeedReconnect) { | 
|  | 160 | rc = wait_event_interruptible_timeout(server->response_q, | 
|  | 161 | (server->tcpStatus != CifsNeedReconnect), | 
|  | 162 | 10 * HZ); | 
|  | 163 | if (rc < 0) { | 
|  | 164 | cifs_dbg(FYI, "%s: aborting reconnect due to a received" | 
|  | 165 | " signal by the process\n", __func__); | 
|  | 166 | return -ERESTARTSYS; | 
|  | 167 | } | 
|  | 168 |  | 
|  | 169 | /* are we still trying to reconnect? */ | 
|  | 170 | if (server->tcpStatus != CifsNeedReconnect) | 
|  | 171 | break; | 
|  | 172 |  | 
|  | 173 | /* | 
|  | 174 | * on "soft" mounts we wait once. Hard mounts keep | 
|  | 175 | * retrying until process is killed or server comes | 
|  | 176 | * back on-line | 
|  | 177 | */ | 
|  | 178 | if (!tcon->retry) { | 
|  | 179 | cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n"); | 
|  | 180 | return -EHOSTDOWN; | 
|  | 181 | } | 
|  | 182 | } | 
|  | 183 |  | 
|  | 184 | if (!ses->need_reconnect && !tcon->need_reconnect) | 
|  | 185 | return 0; | 
|  | 186 |  | 
|  | 187 | nls_codepage = load_nls_default(); | 
|  | 188 |  | 
|  | 189 | /* | 
|  | 190 | * need to prevent multiple threads trying to simultaneously | 
|  | 191 | * reconnect the same SMB session | 
|  | 192 | */ | 
|  | 193 | mutex_lock(&ses->session_mutex); | 
|  | 194 |  | 
|  | 195 | /* | 
|  | 196 | * Recheck after acquire mutex. If another thread is negotiating | 
|  | 197 | * and the server never sends an answer the socket will be closed | 
|  | 198 | * and tcpStatus set to reconnect. | 
|  | 199 | */ | 
|  | 200 | if (server->tcpStatus == CifsNeedReconnect) { | 
|  | 201 | rc = -EHOSTDOWN; | 
|  | 202 | mutex_unlock(&ses->session_mutex); | 
|  | 203 | goto out; | 
|  | 204 | } | 
|  | 205 |  | 
|  | 206 | rc = cifs_negotiate_protocol(0, ses); | 
|  | 207 | if (rc == 0 && ses->need_reconnect) | 
|  | 208 | rc = cifs_setup_session(0, ses, nls_codepage); | 
|  | 209 |  | 
|  | 210 | /* do we need to reconnect tcon? */ | 
|  | 211 | if (rc || !tcon->need_reconnect) { | 
|  | 212 | mutex_unlock(&ses->session_mutex); | 
|  | 213 | goto out; | 
|  | 214 | } | 
|  | 215 |  | 
|  | 216 | cifs_mark_open_files_invalid(tcon); | 
|  | 217 | rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage); | 
|  | 218 | mutex_unlock(&ses->session_mutex); | 
|  | 219 | cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); | 
|  | 220 |  | 
|  | 221 | if (rc) { | 
|  | 222 | printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc); | 
|  | 223 | goto out; | 
|  | 224 | } | 
|  | 225 |  | 
|  | 226 | atomic_inc(&tconInfoReconnectCount); | 
|  | 227 |  | 
|  | 228 | /* tell server Unix caps we support */ | 
|  | 229 | if (ses->capabilities & CAP_UNIX) | 
|  | 230 | reset_cifs_unix_caps(0, tcon, NULL, NULL); | 
|  | 231 |  | 
|  | 232 | /* | 
|  | 233 | * Removed call to reopen open files here. It is safer (and faster) to | 
|  | 234 | * reopen files one at a time as needed in read and write. | 
|  | 235 | * | 
|  | 236 | * FIXME: what about file locks? don't we need to reclaim them ASAP? | 
|  | 237 | */ | 
|  | 238 |  | 
|  | 239 | out: | 
|  | 240 | /* | 
|  | 241 | * Check if handle based operation so we know whether we can continue | 
|  | 242 | * or not without returning to caller to reset file handle | 
|  | 243 | */ | 
|  | 244 | switch (smb_command) { | 
|  | 245 | case SMB_COM_READ_ANDX: | 
|  | 246 | case SMB_COM_WRITE_ANDX: | 
|  | 247 | case SMB_COM_CLOSE: | 
|  | 248 | case SMB_COM_FIND_CLOSE2: | 
|  | 249 | case SMB_COM_LOCKING_ANDX: | 
|  | 250 | rc = -EAGAIN; | 
|  | 251 | } | 
|  | 252 |  | 
|  | 253 | unload_nls(nls_codepage); | 
|  | 254 | return rc; | 
|  | 255 | } | 
|  | 256 |  | 
|  | 257 | /* Allocate and return pointer to an SMB request buffer, and set basic | 
|  | 258 | SMB information in the SMB header.  If the return code is zero, this | 
|  | 259 | function must have filled in request_buf pointer */ | 
|  | 260 | static int | 
|  | 261 | small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon, | 
|  | 262 | void **request_buf) | 
|  | 263 | { | 
|  | 264 | int rc; | 
|  | 265 |  | 
|  | 266 | rc = cifs_reconnect_tcon(tcon, smb_command); | 
|  | 267 | if (rc) | 
|  | 268 | return rc; | 
|  | 269 |  | 
|  | 270 | *request_buf = cifs_small_buf_get(); | 
|  | 271 | if (*request_buf == NULL) { | 
|  | 272 | /* BB should we add a retry in here if not a writepage? */ | 
|  | 273 | return -ENOMEM; | 
|  | 274 | } | 
|  | 275 |  | 
|  | 276 | header_assemble((struct smb_hdr *) *request_buf, smb_command, | 
|  | 277 | tcon, wct); | 
|  | 278 |  | 
|  | 279 | if (tcon != NULL) | 
|  | 280 | cifs_stats_inc(&tcon->num_smbs_sent); | 
|  | 281 |  | 
|  | 282 | return 0; | 
|  | 283 | } | 
|  | 284 |  | 
|  | 285 | int | 
|  | 286 | small_smb_init_no_tc(const int smb_command, const int wct, | 
|  | 287 | struct cifs_ses *ses, void **request_buf) | 
|  | 288 | { | 
|  | 289 | int rc; | 
|  | 290 | struct smb_hdr *buffer; | 
|  | 291 |  | 
|  | 292 | rc = small_smb_init(smb_command, wct, NULL, request_buf); | 
|  | 293 | if (rc) | 
|  | 294 | return rc; | 
|  | 295 |  | 
|  | 296 | buffer = (struct smb_hdr *)*request_buf; | 
|  | 297 | buffer->Mid = get_next_mid(ses->server); | 
|  | 298 | if (ses->capabilities & CAP_UNICODE) | 
|  | 299 | buffer->Flags2 |= SMBFLG2_UNICODE; | 
|  | 300 | if (ses->capabilities & CAP_STATUS32) | 
|  | 301 | buffer->Flags2 |= SMBFLG2_ERR_STATUS; | 
|  | 302 |  | 
|  | 303 | /* uid, tid can stay at zero as set in header assemble */ | 
|  | 304 |  | 
|  | 305 | /* BB add support for turning on the signing when | 
|  | 306 | this function is used after 1st of session setup requests */ | 
|  | 307 |  | 
|  | 308 | return rc; | 
|  | 309 | } | 
|  | 310 |  | 
|  | 311 | /* If the return code is zero, this function must fill in request_buf pointer */ | 
|  | 312 | static int | 
|  | 313 | __smb_init(int smb_command, int wct, struct cifs_tcon *tcon, | 
|  | 314 | void **request_buf, void **response_buf) | 
|  | 315 | { | 
|  | 316 | *request_buf = cifs_buf_get(); | 
|  | 317 | if (*request_buf == NULL) { | 
|  | 318 | /* BB should we add a retry in here if not a writepage? */ | 
|  | 319 | return -ENOMEM; | 
|  | 320 | } | 
|  | 321 | /* Although the original thought was we needed the response buf for  */ | 
|  | 322 | /* potential retries of smb operations it turns out we can determine */ | 
|  | 323 | /* from the mid flags when the request buffer can be resent without  */ | 
|  | 324 | /* having to use a second distinct buffer for the response */ | 
|  | 325 | if (response_buf) | 
|  | 326 | *response_buf = *request_buf; | 
|  | 327 |  | 
|  | 328 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, | 
|  | 329 | wct); | 
|  | 330 |  | 
|  | 331 | if (tcon != NULL) | 
|  | 332 | cifs_stats_inc(&tcon->num_smbs_sent); | 
|  | 333 |  | 
|  | 334 | return 0; | 
|  | 335 | } | 
|  | 336 |  | 
|  | 337 | /* If the return code is zero, this function must fill in request_buf pointer */ | 
|  | 338 | static int | 
|  | 339 | smb_init(int smb_command, int wct, struct cifs_tcon *tcon, | 
|  | 340 | void **request_buf, void **response_buf) | 
|  | 341 | { | 
|  | 342 | int rc; | 
|  | 343 |  | 
|  | 344 | rc = cifs_reconnect_tcon(tcon, smb_command); | 
|  | 345 | if (rc) | 
|  | 346 | return rc; | 
|  | 347 |  | 
|  | 348 | return __smb_init(smb_command, wct, tcon, request_buf, response_buf); | 
|  | 349 | } | 
|  | 350 |  | 
|  | 351 | static int | 
|  | 352 | smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon, | 
|  | 353 | void **request_buf, void **response_buf) | 
|  | 354 | { | 
|  | 355 | if (tcon->ses->need_reconnect || tcon->need_reconnect) | 
|  | 356 | return -EHOSTDOWN; | 
|  | 357 |  | 
|  | 358 | return __smb_init(smb_command, wct, tcon, request_buf, response_buf); | 
|  | 359 | } | 
|  | 360 |  | 
|  | 361 | static int validate_t2(struct smb_t2_rsp *pSMB) | 
|  | 362 | { | 
|  | 363 | unsigned int total_size; | 
|  | 364 |  | 
|  | 365 | /* check for plausible wct */ | 
|  | 366 | if (pSMB->hdr.WordCount < 10) | 
|  | 367 | goto vt2_err; | 
|  | 368 |  | 
|  | 369 | /* check for parm and data offset going beyond end of smb */ | 
|  | 370 | if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 || | 
|  | 371 | get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024) | 
|  | 372 | goto vt2_err; | 
|  | 373 |  | 
|  | 374 | total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount); | 
|  | 375 | if (total_size >= 512) | 
|  | 376 | goto vt2_err; | 
|  | 377 |  | 
|  | 378 | /* check that bcc is at least as big as parms + data, and that it is | 
|  | 379 | * less than negotiated smb buffer | 
|  | 380 | */ | 
|  | 381 | total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount); | 
|  | 382 | if (total_size > get_bcc(&pSMB->hdr) || | 
|  | 383 | total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) | 
|  | 384 | goto vt2_err; | 
|  | 385 |  | 
|  | 386 | return 0; | 
|  | 387 | vt2_err: | 
|  | 388 | cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, | 
|  | 389 | sizeof(struct smb_t2_rsp) + 16); | 
|  | 390 | return -EINVAL; | 
|  | 391 | } | 
|  | 392 |  | 
|  | 393 | static int | 
|  | 394 | decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr) | 
|  | 395 | { | 
|  | 396 | int	rc = 0; | 
|  | 397 | u16	count; | 
|  | 398 | char	*guid = pSMBr->u.extended_response.GUID; | 
|  | 399 | struct TCP_Server_Info *server = ses->server; | 
|  | 400 |  | 
|  | 401 | count = get_bcc(&pSMBr->hdr); | 
|  | 402 | if (count < SMB1_CLIENT_GUID_SIZE) | 
|  | 403 | return -EIO; | 
|  | 404 |  | 
|  | 405 | spin_lock(&cifs_tcp_ses_lock); | 
|  | 406 | if (server->srv_count > 1) { | 
|  | 407 | spin_unlock(&cifs_tcp_ses_lock); | 
|  | 408 | if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) { | 
|  | 409 | cifs_dbg(FYI, "server UID changed\n"); | 
|  | 410 | memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE); | 
|  | 411 | } | 
|  | 412 | } else { | 
|  | 413 | spin_unlock(&cifs_tcp_ses_lock); | 
|  | 414 | memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE); | 
|  | 415 | } | 
|  | 416 |  | 
|  | 417 | if (count == SMB1_CLIENT_GUID_SIZE) { | 
|  | 418 | server->sec_ntlmssp = true; | 
|  | 419 | } else { | 
|  | 420 | count -= SMB1_CLIENT_GUID_SIZE; | 
|  | 421 | rc = decode_negTokenInit( | 
|  | 422 | pSMBr->u.extended_response.SecurityBlob, count, server); | 
|  | 423 | if (rc != 1) | 
|  | 424 | return -EINVAL; | 
|  | 425 | } | 
|  | 426 |  | 
|  | 427 | return 0; | 
|  | 428 | } | 
|  | 429 |  | 
|  | 430 | int | 
|  | 431 | cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required) | 
|  | 432 | { | 
|  | 433 | bool srv_sign_required = server->sec_mode & server->vals->signing_required; | 
|  | 434 | bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled; | 
|  | 435 | bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN; | 
|  | 436 |  | 
|  | 437 | /* | 
|  | 438 | * Is signing required by mnt options? If not then check | 
|  | 439 | * global_secflags to see if it is there. | 
|  | 440 | */ | 
|  | 441 | if (!mnt_sign_required) | 
|  | 442 | mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) == | 
|  | 443 | CIFSSEC_MUST_SIGN); | 
|  | 444 |  | 
|  | 445 | /* | 
|  | 446 | * If signing is required then it's automatically enabled too, | 
|  | 447 | * otherwise, check to see if the secflags allow it. | 
|  | 448 | */ | 
|  | 449 | mnt_sign_enabled = mnt_sign_required ? mnt_sign_required : | 
|  | 450 | (global_secflags & CIFSSEC_MAY_SIGN); | 
|  | 451 |  | 
|  | 452 | /* If server requires signing, does client allow it? */ | 
|  | 453 | if (srv_sign_required) { | 
|  | 454 | if (!mnt_sign_enabled) { | 
|  | 455 | cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!"); | 
|  | 456 | return -ENOTSUPP; | 
|  | 457 | } | 
|  | 458 | server->sign = true; | 
|  | 459 | } | 
|  | 460 |  | 
|  | 461 | /* If client requires signing, does server allow it? */ | 
|  | 462 | if (mnt_sign_required) { | 
|  | 463 | if (!srv_sign_enabled) { | 
|  | 464 | cifs_dbg(VFS, "Server does not support signing!"); | 
|  | 465 | return -ENOTSUPP; | 
|  | 466 | } | 
|  | 467 | server->sign = true; | 
|  | 468 | } | 
|  | 469 |  | 
|  | 470 | if (cifs_rdma_enabled(server) && server->sign) | 
|  | 471 | cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled"); | 
|  | 472 |  | 
|  | 473 | return 0; | 
|  | 474 | } | 
|  | 475 |  | 
|  | 476 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 
|  | 477 | static int | 
|  | 478 | decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) | 
|  | 479 | { | 
|  | 480 | __s16 tmp; | 
|  | 481 | struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr; | 
|  | 482 |  | 
|  | 483 | if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT) | 
|  | 484 | return -EOPNOTSUPP; | 
|  | 485 |  | 
|  | 486 | server->sec_mode = le16_to_cpu(rsp->SecurityMode); | 
|  | 487 | server->maxReq = min_t(unsigned int, | 
|  | 488 | le16_to_cpu(rsp->MaxMpxCount), | 
|  | 489 | cifs_max_pending); | 
|  | 490 | set_credits(server, server->maxReq); | 
|  | 491 | server->maxBuf = le16_to_cpu(rsp->MaxBufSize); | 
|  | 492 | /* even though we do not use raw we might as well set this | 
|  | 493 | accurately, in case we ever find a need for it */ | 
|  | 494 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | 
|  | 495 | server->max_rw = 0xFF00; | 
|  | 496 | server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; | 
|  | 497 | } else { | 
|  | 498 | server->max_rw = 0;/* do not need to use raw anyway */ | 
|  | 499 | server->capabilities = CAP_MPX_MODE; | 
|  | 500 | } | 
|  | 501 | tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); | 
|  | 502 | if (tmp == -1) { | 
|  | 503 | /* OS/2 often does not set timezone therefore | 
|  | 504 | * we must use server time to calc time zone. | 
|  | 505 | * Could deviate slightly from the right zone. | 
|  | 506 | * Smallest defined timezone difference is 15 minutes | 
|  | 507 | * (i.e. Nepal).  Rounding up/down is done to match | 
|  | 508 | * this requirement. | 
|  | 509 | */ | 
|  | 510 | int val, seconds, remain, result; | 
|  | 511 | struct timespec64 ts; | 
|  | 512 | time64_t utc = ktime_get_real_seconds(); | 
|  | 513 | ts = cnvrtDosUnixTm(rsp->SrvTime.Date, | 
|  | 514 | rsp->SrvTime.Time, 0); | 
|  | 515 | cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n", | 
|  | 516 | ts.tv_sec, utc, | 
|  | 517 | utc - ts.tv_sec); | 
|  | 518 | val = (int)(utc - ts.tv_sec); | 
|  | 519 | seconds = abs(val); | 
|  | 520 | result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; | 
|  | 521 | remain = seconds % MIN_TZ_ADJ; | 
|  | 522 | if (remain >= (MIN_TZ_ADJ / 2)) | 
|  | 523 | result += MIN_TZ_ADJ; | 
|  | 524 | if (val < 0) | 
|  | 525 | result = -result; | 
|  | 526 | server->timeAdj = result; | 
|  | 527 | } else { | 
|  | 528 | server->timeAdj = (int)tmp; | 
|  | 529 | server->timeAdj *= 60; /* also in seconds */ | 
|  | 530 | } | 
|  | 531 | cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj); | 
|  | 532 |  | 
|  | 533 |  | 
|  | 534 | /* BB get server time for time conversions and add | 
|  | 535 | code to use it and timezone since this is not UTC */ | 
|  | 536 |  | 
|  | 537 | if (rsp->EncryptionKeyLength == | 
|  | 538 | cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { | 
|  | 539 | memcpy(server->cryptkey, rsp->EncryptionKey, | 
|  | 540 | CIFS_CRYPTO_KEY_SIZE); | 
|  | 541 | } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { | 
|  | 542 | return -EIO; /* need cryptkey unless plain text */ | 
|  | 543 | } | 
|  | 544 |  | 
|  | 545 | cifs_dbg(FYI, "LANMAN negotiated\n"); | 
|  | 546 | return 0; | 
|  | 547 | } | 
|  | 548 | #else | 
|  | 549 | static inline int | 
|  | 550 | decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) | 
|  | 551 | { | 
|  | 552 | cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n"); | 
|  | 553 | return -EOPNOTSUPP; | 
|  | 554 | } | 
|  | 555 | #endif | 
|  | 556 |  | 
|  | 557 | static bool | 
|  | 558 | should_set_ext_sec_flag(enum securityEnum sectype) | 
|  | 559 | { | 
|  | 560 | switch (sectype) { | 
|  | 561 | case RawNTLMSSP: | 
|  | 562 | case Kerberos: | 
|  | 563 | return true; | 
|  | 564 | case Unspecified: | 
|  | 565 | if (global_secflags & | 
|  | 566 | (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)) | 
|  | 567 | return true; | 
|  | 568 | /* Fallthrough */ | 
|  | 569 | default: | 
|  | 570 | return false; | 
|  | 571 | } | 
|  | 572 | } | 
|  | 573 |  | 
|  | 574 | int | 
|  | 575 | CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) | 
|  | 576 | { | 
|  | 577 | NEGOTIATE_REQ *pSMB; | 
|  | 578 | NEGOTIATE_RSP *pSMBr; | 
|  | 579 | int rc = 0; | 
|  | 580 | int bytes_returned; | 
|  | 581 | int i; | 
|  | 582 | struct TCP_Server_Info *server = ses->server; | 
|  | 583 | u16 count; | 
|  | 584 |  | 
|  | 585 | if (!server) { | 
|  | 586 | WARN(1, "%s: server is NULL!\n", __func__); | 
|  | 587 | return -EIO; | 
|  | 588 | } | 
|  | 589 |  | 
|  | 590 | rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , | 
|  | 591 | (void **) &pSMB, (void **) &pSMBr); | 
|  | 592 | if (rc) | 
|  | 593 | return rc; | 
|  | 594 |  | 
|  | 595 | pSMB->hdr.Mid = get_next_mid(server); | 
|  | 596 | pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); | 
|  | 597 |  | 
|  | 598 | if (should_set_ext_sec_flag(ses->sectype)) { | 
|  | 599 | cifs_dbg(FYI, "Requesting extended security."); | 
|  | 600 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 
|  | 601 | } | 
|  | 602 |  | 
|  | 603 | count = 0; | 
|  | 604 | /* | 
|  | 605 | * We know that all the name entries in the protocols array | 
|  | 606 | * are short (< 16 bytes anyway) and are NUL terminated. | 
|  | 607 | */ | 
|  | 608 | for (i = 0; i < CIFS_NUM_PROT; i++) { | 
|  | 609 | size_t len = strlen(protocols[i].name) + 1; | 
|  | 610 |  | 
|  | 611 | memcpy(pSMB->DialectsArray+count, protocols[i].name, len); | 
|  | 612 | count += len; | 
|  | 613 | } | 
|  | 614 | inc_rfc1001_len(pSMB, count); | 
|  | 615 | pSMB->ByteCount = cpu_to_le16(count); | 
|  | 616 |  | 
|  | 617 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | 
|  | 618 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 619 | if (rc != 0) | 
|  | 620 | goto neg_err_exit; | 
|  | 621 |  | 
|  | 622 | server->dialect = le16_to_cpu(pSMBr->DialectIndex); | 
|  | 623 | cifs_dbg(FYI, "Dialect: %d\n", server->dialect); | 
|  | 624 | /* Check wct = 1 error case */ | 
|  | 625 | if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) { | 
|  | 626 | /* core returns wct = 1, but we do not ask for core - otherwise | 
|  | 627 | small wct just comes when dialect index is -1 indicating we | 
|  | 628 | could not negotiate a common dialect */ | 
|  | 629 | rc = -EOPNOTSUPP; | 
|  | 630 | goto neg_err_exit; | 
|  | 631 | } else if (pSMBr->hdr.WordCount == 13) { | 
|  | 632 | server->negflavor = CIFS_NEGFLAVOR_LANMAN; | 
|  | 633 | rc = decode_lanman_negprot_rsp(server, pSMBr); | 
|  | 634 | goto signing_check; | 
|  | 635 | } else if (pSMBr->hdr.WordCount != 17) { | 
|  | 636 | /* unknown wct */ | 
|  | 637 | rc = -EOPNOTSUPP; | 
|  | 638 | goto neg_err_exit; | 
|  | 639 | } | 
|  | 640 | /* else wct == 17, NTLM or better */ | 
|  | 641 |  | 
|  | 642 | server->sec_mode = pSMBr->SecurityMode; | 
|  | 643 | if ((server->sec_mode & SECMODE_USER) == 0) | 
|  | 644 | cifs_dbg(FYI, "share mode security\n"); | 
|  | 645 |  | 
|  | 646 | /* one byte, so no need to convert this or EncryptionKeyLen from | 
|  | 647 | little endian */ | 
|  | 648 | server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), | 
|  | 649 | cifs_max_pending); | 
|  | 650 | set_credits(server, server->maxReq); | 
|  | 651 | /* probably no need to store and check maxvcs */ | 
|  | 652 | server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); | 
|  | 653 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); | 
|  | 654 | cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf); | 
|  | 655 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 
|  | 656 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); | 
|  | 657 | server->timeAdj *= 60; | 
|  | 658 |  | 
|  | 659 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | 
|  | 660 | server->negflavor = CIFS_NEGFLAVOR_UNENCAP; | 
|  | 661 | memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey, | 
|  | 662 | CIFS_CRYPTO_KEY_SIZE); | 
|  | 663 | } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC || | 
|  | 664 | server->capabilities & CAP_EXTENDED_SECURITY) { | 
|  | 665 | server->negflavor = CIFS_NEGFLAVOR_EXTENDED; | 
|  | 666 | rc = decode_ext_sec_blob(ses, pSMBr); | 
|  | 667 | } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { | 
|  | 668 | rc = -EIO; /* no crypt key only if plain text pwd */ | 
|  | 669 | } else { | 
|  | 670 | server->negflavor = CIFS_NEGFLAVOR_UNENCAP; | 
|  | 671 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | 
|  | 672 | } | 
|  | 673 |  | 
|  | 674 | signing_check: | 
|  | 675 | if (!rc) | 
|  | 676 | rc = cifs_enable_signing(server, ses->sign); | 
|  | 677 | neg_err_exit: | 
|  | 678 | cifs_buf_release(pSMB); | 
|  | 679 |  | 
|  | 680 | cifs_dbg(FYI, "negprot rc %d\n", rc); | 
|  | 681 | return rc; | 
|  | 682 | } | 
|  | 683 |  | 
|  | 684 | int | 
|  | 685 | CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon) | 
|  | 686 | { | 
|  | 687 | struct smb_hdr *smb_buffer; | 
|  | 688 | int rc = 0; | 
|  | 689 |  | 
|  | 690 | cifs_dbg(FYI, "In tree disconnect\n"); | 
|  | 691 |  | 
|  | 692 | /* BB: do we need to check this? These should never be NULL. */ | 
|  | 693 | if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) | 
|  | 694 | return -EIO; | 
|  | 695 |  | 
|  | 696 | /* | 
|  | 697 | * No need to return error on this operation if tid invalidated and | 
|  | 698 | * closed on server already e.g. due to tcp session crashing. Also, | 
|  | 699 | * the tcon is no longer on the list, so no need to take lock before | 
|  | 700 | * checking this. | 
|  | 701 | */ | 
|  | 702 | if ((tcon->need_reconnect) || (tcon->ses->need_reconnect)) | 
|  | 703 | return 0; | 
|  | 704 |  | 
|  | 705 | rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, | 
|  | 706 | (void **)&smb_buffer); | 
|  | 707 | if (rc) | 
|  | 708 | return rc; | 
|  | 709 |  | 
|  | 710 | rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0); | 
|  | 711 | cifs_small_buf_release(smb_buffer); | 
|  | 712 | if (rc) | 
|  | 713 | cifs_dbg(FYI, "Tree disconnect failed %d\n", rc); | 
|  | 714 |  | 
|  | 715 | /* No need to return error on this operation if tid invalidated and | 
|  | 716 | closed on server already e.g. due to tcp session crashing */ | 
|  | 717 | if (rc == -EAGAIN) | 
|  | 718 | rc = 0; | 
|  | 719 |  | 
|  | 720 | return rc; | 
|  | 721 | } | 
|  | 722 |  | 
|  | 723 | /* | 
|  | 724 | * This is a no-op for now. We're not really interested in the reply, but | 
|  | 725 | * rather in the fact that the server sent one and that server->lstrp | 
|  | 726 | * gets updated. | 
|  | 727 | * | 
|  | 728 | * FIXME: maybe we should consider checking that the reply matches request? | 
|  | 729 | */ | 
|  | 730 | static void | 
|  | 731 | cifs_echo_callback(struct mid_q_entry *mid) | 
|  | 732 | { | 
|  | 733 | struct TCP_Server_Info *server = mid->callback_data; | 
|  | 734 |  | 
|  | 735 | DeleteMidQEntry(mid); | 
|  | 736 | add_credits(server, 1, CIFS_ECHO_OP); | 
|  | 737 | } | 
|  | 738 |  | 
|  | 739 | int | 
|  | 740 | CIFSSMBEcho(struct TCP_Server_Info *server) | 
|  | 741 | { | 
|  | 742 | ECHO_REQ *smb; | 
|  | 743 | int rc = 0; | 
|  | 744 | struct kvec iov[2]; | 
|  | 745 | struct smb_rqst rqst = { .rq_iov = iov, | 
|  | 746 | .rq_nvec = 2 }; | 
|  | 747 |  | 
|  | 748 | cifs_dbg(FYI, "In echo request\n"); | 
|  | 749 |  | 
|  | 750 | rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb); | 
|  | 751 | if (rc) | 
|  | 752 | return rc; | 
|  | 753 |  | 
|  | 754 | if (server->capabilities & CAP_UNICODE) | 
|  | 755 | smb->hdr.Flags2 |= SMBFLG2_UNICODE; | 
|  | 756 |  | 
|  | 757 | /* set up echo request */ | 
|  | 758 | smb->hdr.Tid = 0xffff; | 
|  | 759 | smb->hdr.WordCount = 1; | 
|  | 760 | put_unaligned_le16(1, &smb->EchoCount); | 
|  | 761 | put_bcc(1, &smb->hdr); | 
|  | 762 | smb->Data[0] = 'a'; | 
|  | 763 | inc_rfc1001_len(smb, 3); | 
|  | 764 |  | 
|  | 765 | iov[0].iov_len = 4; | 
|  | 766 | iov[0].iov_base = smb; | 
|  | 767 | iov[1].iov_len = get_rfc1002_length(smb); | 
|  | 768 | iov[1].iov_base = (char *)smb + 4; | 
|  | 769 |  | 
|  | 770 | rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL, | 
|  | 771 | server, CIFS_ASYNC_OP | CIFS_ECHO_OP); | 
|  | 772 | if (rc) | 
|  | 773 | cifs_dbg(FYI, "Echo request failed: %d\n", rc); | 
|  | 774 |  | 
|  | 775 | cifs_small_buf_release(smb); | 
|  | 776 |  | 
|  | 777 | return rc; | 
|  | 778 | } | 
|  | 779 |  | 
|  | 780 | int | 
|  | 781 | CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses) | 
|  | 782 | { | 
|  | 783 | LOGOFF_ANDX_REQ *pSMB; | 
|  | 784 | int rc = 0; | 
|  | 785 |  | 
|  | 786 | cifs_dbg(FYI, "In SMBLogoff for session disconnect\n"); | 
|  | 787 |  | 
|  | 788 | /* | 
|  | 789 | * BB: do we need to check validity of ses and server? They should | 
|  | 790 | * always be valid since we have an active reference. If not, that | 
|  | 791 | * should probably be a BUG() | 
|  | 792 | */ | 
|  | 793 | if (!ses || !ses->server) | 
|  | 794 | return -EIO; | 
|  | 795 |  | 
|  | 796 | mutex_lock(&ses->session_mutex); | 
|  | 797 | if (ses->need_reconnect) | 
|  | 798 | goto session_already_dead; /* no need to send SMBlogoff if uid | 
|  | 799 | already closed due to reconnect */ | 
|  | 800 | rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); | 
|  | 801 | if (rc) { | 
|  | 802 | mutex_unlock(&ses->session_mutex); | 
|  | 803 | return rc; | 
|  | 804 | } | 
|  | 805 |  | 
|  | 806 | pSMB->hdr.Mid = get_next_mid(ses->server); | 
|  | 807 |  | 
|  | 808 | if (ses->server->sign) | 
|  | 809 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 
|  | 810 |  | 
|  | 811 | pSMB->hdr.Uid = ses->Suid; | 
|  | 812 |  | 
|  | 813 | pSMB->AndXCommand = 0xFF; | 
|  | 814 | rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0); | 
|  | 815 | cifs_small_buf_release(pSMB); | 
|  | 816 | session_already_dead: | 
|  | 817 | mutex_unlock(&ses->session_mutex); | 
|  | 818 |  | 
|  | 819 | /* if session dead then we do not need to do ulogoff, | 
|  | 820 | since server closed smb session, no sense reporting | 
|  | 821 | error */ | 
|  | 822 | if (rc == -EAGAIN) | 
|  | 823 | rc = 0; | 
|  | 824 | return rc; | 
|  | 825 | } | 
|  | 826 |  | 
|  | 827 | int | 
|  | 828 | CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 829 | const char *fileName, __u16 type, | 
|  | 830 | const struct nls_table *nls_codepage, int remap) | 
|  | 831 | { | 
|  | 832 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 
|  | 833 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 
|  | 834 | struct unlink_psx_rq *pRqD; | 
|  | 835 | int name_len; | 
|  | 836 | int rc = 0; | 
|  | 837 | int bytes_returned = 0; | 
|  | 838 | __u16 params, param_offset, offset, byte_count; | 
|  | 839 |  | 
|  | 840 | cifs_dbg(FYI, "In POSIX delete\n"); | 
|  | 841 | PsxDelete: | 
|  | 842 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 843 | (void **) &pSMBr); | 
|  | 844 | if (rc) | 
|  | 845 | return rc; | 
|  | 846 |  | 
|  | 847 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 848 | name_len = | 
|  | 849 | cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, | 
|  | 850 | PATH_MAX, nls_codepage, remap); | 
|  | 851 | name_len++;	/* trailing null */ | 
|  | 852 | name_len *= 2; | 
|  | 853 | } else { /* BB add path length overrun check */ | 
|  | 854 | name_len = strnlen(fileName, PATH_MAX); | 
|  | 855 | name_len++;	/* trailing null */ | 
|  | 856 | strncpy(pSMB->FileName, fileName, name_len); | 
|  | 857 | } | 
|  | 858 |  | 
|  | 859 | params = 6 + name_len; | 
|  | 860 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 861 | pSMB->MaxDataCount = 0; /* BB double check this with jra */ | 
|  | 862 | pSMB->MaxSetupCount = 0; | 
|  | 863 | pSMB->Reserved = 0; | 
|  | 864 | pSMB->Flags = 0; | 
|  | 865 | pSMB->Timeout = 0; | 
|  | 866 | pSMB->Reserved2 = 0; | 
|  | 867 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | 
|  | 868 | InformationLevel) - 4; | 
|  | 869 | offset = param_offset + params; | 
|  | 870 |  | 
|  | 871 | /* Setup pointer to Request Data (inode type) */ | 
|  | 872 | pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset); | 
|  | 873 | pRqD->type = cpu_to_le16(type); | 
|  | 874 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 875 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 876 | pSMB->SetupCount = 1; | 
|  | 877 | pSMB->Reserved3 = 0; | 
|  | 878 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | 
|  | 879 | byte_count = 3 /* pad */  + params + sizeof(struct unlink_psx_rq); | 
|  | 880 |  | 
|  | 881 | pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq)); | 
|  | 882 | pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq)); | 
|  | 883 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 884 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 885 | pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK); | 
|  | 886 | pSMB->Reserved4 = 0; | 
|  | 887 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 888 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 889 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 890 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 891 | if (rc) | 
|  | 892 | cifs_dbg(FYI, "Posix delete returned %d\n", rc); | 
|  | 893 | cifs_buf_release(pSMB); | 
|  | 894 |  | 
|  | 895 | cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes); | 
|  | 896 |  | 
|  | 897 | if (rc == -EAGAIN) | 
|  | 898 | goto PsxDelete; | 
|  | 899 |  | 
|  | 900 | return rc; | 
|  | 901 | } | 
|  | 902 |  | 
|  | 903 | int | 
|  | 904 | CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name, | 
|  | 905 | struct cifs_sb_info *cifs_sb) | 
|  | 906 | { | 
|  | 907 | DELETE_FILE_REQ *pSMB = NULL; | 
|  | 908 | DELETE_FILE_RSP *pSMBr = NULL; | 
|  | 909 | int rc = 0; | 
|  | 910 | int bytes_returned; | 
|  | 911 | int name_len; | 
|  | 912 | int remap = cifs_remap(cifs_sb); | 
|  | 913 |  | 
|  | 914 | DelFileRetry: | 
|  | 915 | rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, | 
|  | 916 | (void **) &pSMBr); | 
|  | 917 | if (rc) | 
|  | 918 | return rc; | 
|  | 919 |  | 
|  | 920 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 921 | name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name, | 
|  | 922 | PATH_MAX, cifs_sb->local_nls, | 
|  | 923 | remap); | 
|  | 924 | name_len++;	/* trailing null */ | 
|  | 925 | name_len *= 2; | 
|  | 926 | } else {		/* BB improve check for buffer overruns BB */ | 
|  | 927 | name_len = strnlen(name, PATH_MAX); | 
|  | 928 | name_len++;	/* trailing null */ | 
|  | 929 | strncpy(pSMB->fileName, name, name_len); | 
|  | 930 | } | 
|  | 931 | pSMB->SearchAttributes = | 
|  | 932 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); | 
|  | 933 | pSMB->BufferFormat = 0x04; | 
|  | 934 | inc_rfc1001_len(pSMB, name_len + 1); | 
|  | 935 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 
|  | 936 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 937 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 938 | cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes); | 
|  | 939 | if (rc) | 
|  | 940 | cifs_dbg(FYI, "Error in RMFile = %d\n", rc); | 
|  | 941 |  | 
|  | 942 | cifs_buf_release(pSMB); | 
|  | 943 | if (rc == -EAGAIN) | 
|  | 944 | goto DelFileRetry; | 
|  | 945 |  | 
|  | 946 | return rc; | 
|  | 947 | } | 
|  | 948 |  | 
|  | 949 | int | 
|  | 950 | CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, | 
|  | 951 | struct cifs_sb_info *cifs_sb) | 
|  | 952 | { | 
|  | 953 | DELETE_DIRECTORY_REQ *pSMB = NULL; | 
|  | 954 | DELETE_DIRECTORY_RSP *pSMBr = NULL; | 
|  | 955 | int rc = 0; | 
|  | 956 | int bytes_returned; | 
|  | 957 | int name_len; | 
|  | 958 | int remap = cifs_remap(cifs_sb); | 
|  | 959 |  | 
|  | 960 | cifs_dbg(FYI, "In CIFSSMBRmDir\n"); | 
|  | 961 | RmDirRetry: | 
|  | 962 | rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB, | 
|  | 963 | (void **) &pSMBr); | 
|  | 964 | if (rc) | 
|  | 965 | return rc; | 
|  | 966 |  | 
|  | 967 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 968 | name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, | 
|  | 969 | PATH_MAX, cifs_sb->local_nls, | 
|  | 970 | remap); | 
|  | 971 | name_len++;	/* trailing null */ | 
|  | 972 | name_len *= 2; | 
|  | 973 | } else {		/* BB improve check for buffer overruns BB */ | 
|  | 974 | name_len = strnlen(name, PATH_MAX); | 
|  | 975 | name_len++;	/* trailing null */ | 
|  | 976 | strncpy(pSMB->DirName, name, name_len); | 
|  | 977 | } | 
|  | 978 |  | 
|  | 979 | pSMB->BufferFormat = 0x04; | 
|  | 980 | inc_rfc1001_len(pSMB, name_len + 1); | 
|  | 981 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 
|  | 982 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 983 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 984 | cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs); | 
|  | 985 | if (rc) | 
|  | 986 | cifs_dbg(FYI, "Error in RMDir = %d\n", rc); | 
|  | 987 |  | 
|  | 988 | cifs_buf_release(pSMB); | 
|  | 989 | if (rc == -EAGAIN) | 
|  | 990 | goto RmDirRetry; | 
|  | 991 | return rc; | 
|  | 992 | } | 
|  | 993 |  | 
|  | 994 | int | 
|  | 995 | CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, | 
|  | 996 | struct cifs_sb_info *cifs_sb) | 
|  | 997 | { | 
|  | 998 | int rc = 0; | 
|  | 999 | CREATE_DIRECTORY_REQ *pSMB = NULL; | 
|  | 1000 | CREATE_DIRECTORY_RSP *pSMBr = NULL; | 
|  | 1001 | int bytes_returned; | 
|  | 1002 | int name_len; | 
|  | 1003 | int remap = cifs_remap(cifs_sb); | 
|  | 1004 |  | 
|  | 1005 | cifs_dbg(FYI, "In CIFSSMBMkDir\n"); | 
|  | 1006 | MkDirRetry: | 
|  | 1007 | rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB, | 
|  | 1008 | (void **) &pSMBr); | 
|  | 1009 | if (rc) | 
|  | 1010 | return rc; | 
|  | 1011 |  | 
|  | 1012 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 1013 | name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, | 
|  | 1014 | PATH_MAX, cifs_sb->local_nls, | 
|  | 1015 | remap); | 
|  | 1016 | name_len++;	/* trailing null */ | 
|  | 1017 | name_len *= 2; | 
|  | 1018 | } else {		/* BB improve check for buffer overruns BB */ | 
|  | 1019 | name_len = strnlen(name, PATH_MAX); | 
|  | 1020 | name_len++;	/* trailing null */ | 
|  | 1021 | strncpy(pSMB->DirName, name, name_len); | 
|  | 1022 | } | 
|  | 1023 |  | 
|  | 1024 | pSMB->BufferFormat = 0x04; | 
|  | 1025 | inc_rfc1001_len(pSMB, name_len + 1); | 
|  | 1026 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 
|  | 1027 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 1028 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 1029 | cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs); | 
|  | 1030 | if (rc) | 
|  | 1031 | cifs_dbg(FYI, "Error in Mkdir = %d\n", rc); | 
|  | 1032 |  | 
|  | 1033 | cifs_buf_release(pSMB); | 
|  | 1034 | if (rc == -EAGAIN) | 
|  | 1035 | goto MkDirRetry; | 
|  | 1036 | return rc; | 
|  | 1037 | } | 
|  | 1038 |  | 
|  | 1039 | int | 
|  | 1040 | CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 1041 | __u32 posix_flags, __u64 mode, __u16 *netfid, | 
|  | 1042 | FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock, | 
|  | 1043 | const char *name, const struct nls_table *nls_codepage, | 
|  | 1044 | int remap) | 
|  | 1045 | { | 
|  | 1046 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 
|  | 1047 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 
|  | 1048 | int name_len; | 
|  | 1049 | int rc = 0; | 
|  | 1050 | int bytes_returned = 0; | 
|  | 1051 | __u16 params, param_offset, offset, byte_count, count; | 
|  | 1052 | OPEN_PSX_REQ *pdata; | 
|  | 1053 | OPEN_PSX_RSP *psx_rsp; | 
|  | 1054 |  | 
|  | 1055 | cifs_dbg(FYI, "In POSIX Create\n"); | 
|  | 1056 | PsxCreat: | 
|  | 1057 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 1058 | (void **) &pSMBr); | 
|  | 1059 | if (rc) | 
|  | 1060 | return rc; | 
|  | 1061 |  | 
|  | 1062 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 1063 | name_len = | 
|  | 1064 | cifsConvertToUTF16((__le16 *) pSMB->FileName, name, | 
|  | 1065 | PATH_MAX, nls_codepage, remap); | 
|  | 1066 | name_len++;	/* trailing null */ | 
|  | 1067 | name_len *= 2; | 
|  | 1068 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 1069 | name_len = strnlen(name, PATH_MAX); | 
|  | 1070 | name_len++;	/* trailing null */ | 
|  | 1071 | strncpy(pSMB->FileName, name, name_len); | 
|  | 1072 | } | 
|  | 1073 |  | 
|  | 1074 | params = 6 + name_len; | 
|  | 1075 | count = sizeof(OPEN_PSX_REQ); | 
|  | 1076 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 1077 | pSMB->MaxDataCount = cpu_to_le16(1000);	/* large enough */ | 
|  | 1078 | pSMB->MaxSetupCount = 0; | 
|  | 1079 | pSMB->Reserved = 0; | 
|  | 1080 | pSMB->Flags = 0; | 
|  | 1081 | pSMB->Timeout = 0; | 
|  | 1082 | pSMB->Reserved2 = 0; | 
|  | 1083 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | 
|  | 1084 | InformationLevel) - 4; | 
|  | 1085 | offset = param_offset + params; | 
|  | 1086 | pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset); | 
|  | 1087 | pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); | 
|  | 1088 | pdata->Permissions = cpu_to_le64(mode); | 
|  | 1089 | pdata->PosixOpenFlags = cpu_to_le32(posix_flags); | 
|  | 1090 | pdata->OpenFlags =  cpu_to_le32(*pOplock); | 
|  | 1091 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 1092 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 1093 | pSMB->SetupCount = 1; | 
|  | 1094 | pSMB->Reserved3 = 0; | 
|  | 1095 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | 
|  | 1096 | byte_count = 3 /* pad */  + params + count; | 
|  | 1097 |  | 
|  | 1098 | pSMB->DataCount = cpu_to_le16(count); | 
|  | 1099 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 1100 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 1101 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 1102 | pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN); | 
|  | 1103 | pSMB->Reserved4 = 0; | 
|  | 1104 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 1105 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 1106 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 1107 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 1108 | if (rc) { | 
|  | 1109 | cifs_dbg(FYI, "Posix create returned %d\n", rc); | 
|  | 1110 | goto psx_create_err; | 
|  | 1111 | } | 
|  | 1112 |  | 
|  | 1113 | cifs_dbg(FYI, "copying inode info\n"); | 
|  | 1114 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 1115 |  | 
|  | 1116 | if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) { | 
|  | 1117 | rc = -EIO;	/* bad smb */ | 
|  | 1118 | goto psx_create_err; | 
|  | 1119 | } | 
|  | 1120 |  | 
|  | 1121 | /* copy return information to pRetData */ | 
|  | 1122 | psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol | 
|  | 1123 | + le16_to_cpu(pSMBr->t2.DataOffset)); | 
|  | 1124 |  | 
|  | 1125 | *pOplock = le16_to_cpu(psx_rsp->OplockFlags); | 
|  | 1126 | if (netfid) | 
|  | 1127 | *netfid = psx_rsp->Fid;   /* cifs fid stays in le */ | 
|  | 1128 | /* Let caller know file was created so we can set the mode. */ | 
|  | 1129 | /* Do we care about the CreateAction in any other cases? */ | 
|  | 1130 | if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction) | 
|  | 1131 | *pOplock |= CIFS_CREATE_ACTION; | 
|  | 1132 | /* check to make sure response data is there */ | 
|  | 1133 | if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) { | 
|  | 1134 | pRetData->Type = cpu_to_le32(-1); /* unknown */ | 
|  | 1135 | cifs_dbg(NOISY, "unknown type\n"); | 
|  | 1136 | } else { | 
|  | 1137 | if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP) | 
|  | 1138 | + sizeof(FILE_UNIX_BASIC_INFO)) { | 
|  | 1139 | cifs_dbg(VFS, "Open response data too small\n"); | 
|  | 1140 | pRetData->Type = cpu_to_le32(-1); | 
|  | 1141 | goto psx_create_err; | 
|  | 1142 | } | 
|  | 1143 | memcpy((char *) pRetData, | 
|  | 1144 | (char *)psx_rsp + sizeof(OPEN_PSX_RSP), | 
|  | 1145 | sizeof(FILE_UNIX_BASIC_INFO)); | 
|  | 1146 | } | 
|  | 1147 |  | 
|  | 1148 | psx_create_err: | 
|  | 1149 | cifs_buf_release(pSMB); | 
|  | 1150 |  | 
|  | 1151 | if (posix_flags & SMB_O_DIRECTORY) | 
|  | 1152 | cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs); | 
|  | 1153 | else | 
|  | 1154 | cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens); | 
|  | 1155 |  | 
|  | 1156 | if (rc == -EAGAIN) | 
|  | 1157 | goto PsxCreat; | 
|  | 1158 |  | 
|  | 1159 | return rc; | 
|  | 1160 | } | 
|  | 1161 |  | 
|  | 1162 | static __u16 convert_disposition(int disposition) | 
|  | 1163 | { | 
|  | 1164 | __u16 ofun = 0; | 
|  | 1165 |  | 
|  | 1166 | switch (disposition) { | 
|  | 1167 | case FILE_SUPERSEDE: | 
|  | 1168 | ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; | 
|  | 1169 | break; | 
|  | 1170 | case FILE_OPEN: | 
|  | 1171 | ofun = SMBOPEN_OAPPEND; | 
|  | 1172 | break; | 
|  | 1173 | case FILE_CREATE: | 
|  | 1174 | ofun = SMBOPEN_OCREATE; | 
|  | 1175 | break; | 
|  | 1176 | case FILE_OPEN_IF: | 
|  | 1177 | ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND; | 
|  | 1178 | break; | 
|  | 1179 | case FILE_OVERWRITE: | 
|  | 1180 | ofun = SMBOPEN_OTRUNC; | 
|  | 1181 | break; | 
|  | 1182 | case FILE_OVERWRITE_IF: | 
|  | 1183 | ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; | 
|  | 1184 | break; | 
|  | 1185 | default: | 
|  | 1186 | cifs_dbg(FYI, "unknown disposition %d\n", disposition); | 
|  | 1187 | ofun =  SMBOPEN_OAPPEND; /* regular open */ | 
|  | 1188 | } | 
|  | 1189 | return ofun; | 
|  | 1190 | } | 
|  | 1191 |  | 
|  | 1192 | static int | 
|  | 1193 | access_flags_to_smbopen_mode(const int access_flags) | 
|  | 1194 | { | 
|  | 1195 | int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE); | 
|  | 1196 |  | 
|  | 1197 | if (masked_flags == GENERIC_READ) | 
|  | 1198 | return SMBOPEN_READ; | 
|  | 1199 | else if (masked_flags == GENERIC_WRITE) | 
|  | 1200 | return SMBOPEN_WRITE; | 
|  | 1201 |  | 
|  | 1202 | /* just go for read/write */ | 
|  | 1203 | return SMBOPEN_READWRITE; | 
|  | 1204 | } | 
|  | 1205 |  | 
|  | 1206 | int | 
|  | 1207 | SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 1208 | const char *fileName, const int openDisposition, | 
|  | 1209 | const int access_flags, const int create_options, __u16 *netfid, | 
|  | 1210 | int *pOplock, FILE_ALL_INFO *pfile_info, | 
|  | 1211 | const struct nls_table *nls_codepage, int remap) | 
|  | 1212 | { | 
|  | 1213 | int rc = -EACCES; | 
|  | 1214 | OPENX_REQ *pSMB = NULL; | 
|  | 1215 | OPENX_RSP *pSMBr = NULL; | 
|  | 1216 | int bytes_returned; | 
|  | 1217 | int name_len; | 
|  | 1218 | __u16 count; | 
|  | 1219 |  | 
|  | 1220 | OldOpenRetry: | 
|  | 1221 | rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB, | 
|  | 1222 | (void **) &pSMBr); | 
|  | 1223 | if (rc) | 
|  | 1224 | return rc; | 
|  | 1225 |  | 
|  | 1226 | pSMB->AndXCommand = 0xFF;       /* none */ | 
|  | 1227 |  | 
|  | 1228 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 1229 | count = 1;      /* account for one byte pad to word boundary */ | 
|  | 1230 | name_len = | 
|  | 1231 | cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1), | 
|  | 1232 | fileName, PATH_MAX, nls_codepage, remap); | 
|  | 1233 | name_len++;     /* trailing null */ | 
|  | 1234 | name_len *= 2; | 
|  | 1235 | } else {                /* BB improve check for buffer overruns BB */ | 
|  | 1236 | count = 0;      /* no pad */ | 
|  | 1237 | name_len = strnlen(fileName, PATH_MAX); | 
|  | 1238 | name_len++;     /* trailing null */ | 
|  | 1239 | strncpy(pSMB->fileName, fileName, name_len); | 
|  | 1240 | } | 
|  | 1241 | if (*pOplock & REQ_OPLOCK) | 
|  | 1242 | pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK); | 
|  | 1243 | else if (*pOplock & REQ_BATCHOPLOCK) | 
|  | 1244 | pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); | 
|  | 1245 |  | 
|  | 1246 | pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); | 
|  | 1247 | pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags)); | 
|  | 1248 | pSMB->Mode |= cpu_to_le16(0x40); /* deny none */ | 
|  | 1249 | /* set file as system file if special file such | 
|  | 1250 | as fifo and server expecting SFU style and | 
|  | 1251 | no Unix extensions */ | 
|  | 1252 |  | 
|  | 1253 | if (create_options & CREATE_OPTION_SPECIAL) | 
|  | 1254 | pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM); | 
|  | 1255 | else /* BB FIXME BB */ | 
|  | 1256 | pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); | 
|  | 1257 |  | 
|  | 1258 | if (create_options & CREATE_OPTION_READONLY) | 
|  | 1259 | pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY); | 
|  | 1260 |  | 
|  | 1261 | /* BB FIXME BB */ | 
|  | 1262 | /*	pSMB->CreateOptions = cpu_to_le32(create_options & | 
|  | 1263 | CREATE_OPTIONS_MASK); */ | 
|  | 1264 | /* BB FIXME END BB */ | 
|  | 1265 |  | 
|  | 1266 | pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); | 
|  | 1267 | pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); | 
|  | 1268 | count += name_len; | 
|  | 1269 | inc_rfc1001_len(pSMB, count); | 
|  | 1270 |  | 
|  | 1271 | pSMB->ByteCount = cpu_to_le16(count); | 
|  | 1272 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 1273 | (struct smb_hdr *)pSMBr, &bytes_returned, 0); | 
|  | 1274 | cifs_stats_inc(&tcon->stats.cifs_stats.num_opens); | 
|  | 1275 | if (rc) { | 
|  | 1276 | cifs_dbg(FYI, "Error in Open = %d\n", rc); | 
|  | 1277 | } else { | 
|  | 1278 | /* BB verify if wct == 15 */ | 
|  | 1279 |  | 
|  | 1280 | /*		*pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/ | 
|  | 1281 |  | 
|  | 1282 | *netfid = pSMBr->Fid;   /* cifs fid stays in le */ | 
|  | 1283 | /* Let caller know file was created so we can set the mode. */ | 
|  | 1284 | /* Do we care about the CreateAction in any other cases? */ | 
|  | 1285 | /* BB FIXME BB */ | 
|  | 1286 | /*		if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) | 
|  | 1287 | *pOplock |= CIFS_CREATE_ACTION; */ | 
|  | 1288 | /* BB FIXME END */ | 
|  | 1289 |  | 
|  | 1290 | if (pfile_info) { | 
|  | 1291 | pfile_info->CreationTime = 0; /* BB convert CreateTime*/ | 
|  | 1292 | pfile_info->LastAccessTime = 0; /* BB fixme */ | 
|  | 1293 | pfile_info->LastWriteTime = 0; /* BB fixme */ | 
|  | 1294 | pfile_info->ChangeTime = 0;  /* BB fixme */ | 
|  | 1295 | pfile_info->Attributes = | 
|  | 1296 | cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); | 
|  | 1297 | /* the file_info buf is endian converted by caller */ | 
|  | 1298 | pfile_info->AllocationSize = | 
|  | 1299 | cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile)); | 
|  | 1300 | pfile_info->EndOfFile = pfile_info->AllocationSize; | 
|  | 1301 | pfile_info->NumberOfLinks = cpu_to_le32(1); | 
|  | 1302 | pfile_info->DeletePending = 0; | 
|  | 1303 | } | 
|  | 1304 | } | 
|  | 1305 |  | 
|  | 1306 | cifs_buf_release(pSMB); | 
|  | 1307 | if (rc == -EAGAIN) | 
|  | 1308 | goto OldOpenRetry; | 
|  | 1309 | return rc; | 
|  | 1310 | } | 
|  | 1311 |  | 
|  | 1312 | int | 
|  | 1313 | CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock, | 
|  | 1314 | FILE_ALL_INFO *buf) | 
|  | 1315 | { | 
|  | 1316 | int rc = -EACCES; | 
|  | 1317 | OPEN_REQ *req = NULL; | 
|  | 1318 | OPEN_RSP *rsp = NULL; | 
|  | 1319 | int bytes_returned; | 
|  | 1320 | int name_len; | 
|  | 1321 | __u16 count; | 
|  | 1322 | struct cifs_sb_info *cifs_sb = oparms->cifs_sb; | 
|  | 1323 | struct cifs_tcon *tcon = oparms->tcon; | 
|  | 1324 | int remap = cifs_remap(cifs_sb); | 
|  | 1325 | const struct nls_table *nls = cifs_sb->local_nls; | 
|  | 1326 | int create_options = oparms->create_options; | 
|  | 1327 | int desired_access = oparms->desired_access; | 
|  | 1328 | int disposition = oparms->disposition; | 
|  | 1329 | const char *path = oparms->path; | 
|  | 1330 |  | 
|  | 1331 | openRetry: | 
|  | 1332 | rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req, | 
|  | 1333 | (void **)&rsp); | 
|  | 1334 | if (rc) | 
|  | 1335 | return rc; | 
|  | 1336 |  | 
|  | 1337 | /* no commands go after this */ | 
|  | 1338 | req->AndXCommand = 0xFF; | 
|  | 1339 |  | 
|  | 1340 | if (req->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 1341 | /* account for one byte pad to word boundary */ | 
|  | 1342 | count = 1; | 
|  | 1343 | name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1), | 
|  | 1344 | path, PATH_MAX, nls, remap); | 
|  | 1345 | /* trailing null */ | 
|  | 1346 | name_len++; | 
|  | 1347 | name_len *= 2; | 
|  | 1348 | req->NameLength = cpu_to_le16(name_len); | 
|  | 1349 | } else { | 
|  | 1350 | /* BB improve check for buffer overruns BB */ | 
|  | 1351 | /* no pad */ | 
|  | 1352 | count = 0; | 
|  | 1353 | name_len = strnlen(path, PATH_MAX); | 
|  | 1354 | /* trailing null */ | 
|  | 1355 | name_len++; | 
|  | 1356 | req->NameLength = cpu_to_le16(name_len); | 
|  | 1357 | strncpy(req->fileName, path, name_len); | 
|  | 1358 | } | 
|  | 1359 |  | 
|  | 1360 | if (*oplock & REQ_OPLOCK) | 
|  | 1361 | req->OpenFlags = cpu_to_le32(REQ_OPLOCK); | 
|  | 1362 | else if (*oplock & REQ_BATCHOPLOCK) | 
|  | 1363 | req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); | 
|  | 1364 |  | 
|  | 1365 | req->DesiredAccess = cpu_to_le32(desired_access); | 
|  | 1366 | req->AllocationSize = 0; | 
|  | 1367 |  | 
|  | 1368 | /* | 
|  | 1369 | * Set file as system file if special file such as fifo and server | 
|  | 1370 | * expecting SFU style and no Unix extensions. | 
|  | 1371 | */ | 
|  | 1372 | if (create_options & CREATE_OPTION_SPECIAL) | 
|  | 1373 | req->FileAttributes = cpu_to_le32(ATTR_SYSTEM); | 
|  | 1374 | else | 
|  | 1375 | req->FileAttributes = cpu_to_le32(ATTR_NORMAL); | 
|  | 1376 |  | 
|  | 1377 | /* | 
|  | 1378 | * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case | 
|  | 1379 | * sensitive checks for other servers such as Samba. | 
|  | 1380 | */ | 
|  | 1381 | if (tcon->ses->capabilities & CAP_UNIX) | 
|  | 1382 | req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); | 
|  | 1383 |  | 
|  | 1384 | if (create_options & CREATE_OPTION_READONLY) | 
|  | 1385 | req->FileAttributes |= cpu_to_le32(ATTR_READONLY); | 
|  | 1386 |  | 
|  | 1387 | req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); | 
|  | 1388 | req->CreateDisposition = cpu_to_le32(disposition); | 
|  | 1389 | req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); | 
|  | 1390 |  | 
|  | 1391 | /* BB Expirement with various impersonation levels and verify */ | 
|  | 1392 | req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); | 
|  | 1393 | req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY; | 
|  | 1394 |  | 
|  | 1395 | count += name_len; | 
|  | 1396 | inc_rfc1001_len(req, count); | 
|  | 1397 |  | 
|  | 1398 | req->ByteCount = cpu_to_le16(count); | 
|  | 1399 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req, | 
|  | 1400 | (struct smb_hdr *)rsp, &bytes_returned, 0); | 
|  | 1401 | cifs_stats_inc(&tcon->stats.cifs_stats.num_opens); | 
|  | 1402 | if (rc) { | 
|  | 1403 | cifs_dbg(FYI, "Error in Open = %d\n", rc); | 
|  | 1404 | cifs_buf_release(req); | 
|  | 1405 | if (rc == -EAGAIN) | 
|  | 1406 | goto openRetry; | 
|  | 1407 | return rc; | 
|  | 1408 | } | 
|  | 1409 |  | 
|  | 1410 | /* 1 byte no need to le_to_cpu */ | 
|  | 1411 | *oplock = rsp->OplockLevel; | 
|  | 1412 | /* cifs fid stays in le */ | 
|  | 1413 | oparms->fid->netfid = rsp->Fid; | 
|  | 1414 |  | 
|  | 1415 | /* Let caller know file was created so we can set the mode. */ | 
|  | 1416 | /* Do we care about the CreateAction in any other cases? */ | 
|  | 1417 | if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction) | 
|  | 1418 | *oplock |= CIFS_CREATE_ACTION; | 
|  | 1419 |  | 
|  | 1420 | if (buf) { | 
|  | 1421 | /* copy from CreationTime to Attributes */ | 
|  | 1422 | memcpy((char *)buf, (char *)&rsp->CreationTime, 36); | 
|  | 1423 | /* the file_info buf is endian converted by caller */ | 
|  | 1424 | buf->AllocationSize = rsp->AllocationSize; | 
|  | 1425 | buf->EndOfFile = rsp->EndOfFile; | 
|  | 1426 | buf->NumberOfLinks = cpu_to_le32(1); | 
|  | 1427 | buf->DeletePending = 0; | 
|  | 1428 | } | 
|  | 1429 |  | 
|  | 1430 | cifs_buf_release(req); | 
|  | 1431 | return rc; | 
|  | 1432 | } | 
|  | 1433 |  | 
|  | 1434 | /* | 
|  | 1435 | * Discard any remaining data in the current SMB. To do this, we borrow the | 
|  | 1436 | * current bigbuf. | 
|  | 1437 | */ | 
|  | 1438 | int | 
|  | 1439 | cifs_discard_remaining_data(struct TCP_Server_Info *server) | 
|  | 1440 | { | 
|  | 1441 | unsigned int rfclen = server->pdu_size; | 
|  | 1442 | int remaining = rfclen + server->vals->header_preamble_size - | 
|  | 1443 | server->total_read; | 
|  | 1444 |  | 
|  | 1445 | while (remaining > 0) { | 
|  | 1446 | int length; | 
|  | 1447 |  | 
|  | 1448 | length = cifs_read_from_socket(server, server->bigbuf, | 
|  | 1449 | min_t(unsigned int, remaining, | 
|  | 1450 | CIFSMaxBufSize + MAX_HEADER_SIZE(server))); | 
|  | 1451 | if (length < 0) | 
|  | 1452 | return length; | 
|  | 1453 | server->total_read += length; | 
|  | 1454 | remaining -= length; | 
|  | 1455 | } | 
|  | 1456 |  | 
|  | 1457 | return 0; | 
|  | 1458 | } | 
|  | 1459 |  | 
|  | 1460 | static int | 
|  | 1461 | __cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid, | 
|  | 1462 | bool malformed) | 
|  | 1463 | { | 
|  | 1464 | int length; | 
|  | 1465 |  | 
|  | 1466 | length = cifs_discard_remaining_data(server); | 
|  | 1467 | dequeue_mid(mid, malformed); | 
|  | 1468 | mid->resp_buf = server->smallbuf; | 
|  | 1469 | server->smallbuf = NULL; | 
|  | 1470 | return length; | 
|  | 1471 | } | 
|  | 1472 |  | 
|  | 1473 | static int | 
|  | 1474 | cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | 
|  | 1475 | { | 
|  | 1476 | struct cifs_readdata *rdata = mid->callback_data; | 
|  | 1477 |  | 
|  | 1478 | return  __cifs_readv_discard(server, mid, rdata->result); | 
|  | 1479 | } | 
|  | 1480 |  | 
|  | 1481 | int | 
|  | 1482 | cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | 
|  | 1483 | { | 
|  | 1484 | int length, len; | 
|  | 1485 | unsigned int data_offset, data_len; | 
|  | 1486 | struct cifs_readdata *rdata = mid->callback_data; | 
|  | 1487 | char *buf = server->smallbuf; | 
|  | 1488 | unsigned int buflen = server->pdu_size + | 
|  | 1489 | server->vals->header_preamble_size; | 
|  | 1490 | bool use_rdma_mr = false; | 
|  | 1491 |  | 
|  | 1492 | cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n", | 
|  | 1493 | __func__, mid->mid, rdata->offset, rdata->bytes); | 
|  | 1494 |  | 
|  | 1495 | /* | 
|  | 1496 | * read the rest of READ_RSP header (sans Data array), or whatever we | 
|  | 1497 | * can if there's not enough data. At this point, we've read down to | 
|  | 1498 | * the Mid. | 
|  | 1499 | */ | 
|  | 1500 | len = min_t(unsigned int, buflen, server->vals->read_rsp_size) - | 
|  | 1501 | HEADER_SIZE(server) + 1; | 
|  | 1502 |  | 
|  | 1503 | length = cifs_read_from_socket(server, | 
|  | 1504 | buf + HEADER_SIZE(server) - 1, len); | 
|  | 1505 | if (length < 0) | 
|  | 1506 | return length; | 
|  | 1507 | server->total_read += length; | 
|  | 1508 |  | 
|  | 1509 | if (server->ops->is_session_expired && | 
|  | 1510 | server->ops->is_session_expired(buf)) { | 
|  | 1511 | cifs_reconnect(server); | 
|  | 1512 | wake_up(&server->response_q); | 
|  | 1513 | return -1; | 
|  | 1514 | } | 
|  | 1515 |  | 
|  | 1516 | if (server->ops->is_status_pending && | 
|  | 1517 | server->ops->is_status_pending(buf, server, 0)) { | 
|  | 1518 | cifs_discard_remaining_data(server); | 
|  | 1519 | return -1; | 
|  | 1520 | } | 
|  | 1521 |  | 
|  | 1522 | /* set up first two iov for signature check and to get credits */ | 
|  | 1523 | rdata->iov[0].iov_base = buf; | 
|  | 1524 | rdata->iov[0].iov_len = server->vals->header_preamble_size; | 
|  | 1525 | rdata->iov[1].iov_base = buf + server->vals->header_preamble_size; | 
|  | 1526 | rdata->iov[1].iov_len = | 
|  | 1527 | server->total_read - server->vals->header_preamble_size; | 
|  | 1528 | cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", | 
|  | 1529 | rdata->iov[0].iov_base, rdata->iov[0].iov_len); | 
|  | 1530 | cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n", | 
|  | 1531 | rdata->iov[1].iov_base, rdata->iov[1].iov_len); | 
|  | 1532 |  | 
|  | 1533 | /* Was the SMB read successful? */ | 
|  | 1534 | rdata->result = server->ops->map_error(buf, false); | 
|  | 1535 | if (rdata->result != 0) { | 
|  | 1536 | cifs_dbg(FYI, "%s: server returned error %d\n", | 
|  | 1537 | __func__, rdata->result); | 
|  | 1538 | /* normal error on read response */ | 
|  | 1539 | return __cifs_readv_discard(server, mid, false); | 
|  | 1540 | } | 
|  | 1541 |  | 
|  | 1542 | /* Is there enough to get to the rest of the READ_RSP header? */ | 
|  | 1543 | if (server->total_read < server->vals->read_rsp_size) { | 
|  | 1544 | cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n", | 
|  | 1545 | __func__, server->total_read, | 
|  | 1546 | server->vals->read_rsp_size); | 
|  | 1547 | rdata->result = -EIO; | 
|  | 1548 | return cifs_readv_discard(server, mid); | 
|  | 1549 | } | 
|  | 1550 |  | 
|  | 1551 | data_offset = server->ops->read_data_offset(buf) + | 
|  | 1552 | server->vals->header_preamble_size; | 
|  | 1553 | if (data_offset < server->total_read) { | 
|  | 1554 | /* | 
|  | 1555 | * win2k8 sometimes sends an offset of 0 when the read | 
|  | 1556 | * is beyond the EOF. Treat it as if the data starts just after | 
|  | 1557 | * the header. | 
|  | 1558 | */ | 
|  | 1559 | cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n", | 
|  | 1560 | __func__, data_offset); | 
|  | 1561 | data_offset = server->total_read; | 
|  | 1562 | } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) { | 
|  | 1563 | /* data_offset is beyond the end of smallbuf */ | 
|  | 1564 | cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n", | 
|  | 1565 | __func__, data_offset); | 
|  | 1566 | rdata->result = -EIO; | 
|  | 1567 | return cifs_readv_discard(server, mid); | 
|  | 1568 | } | 
|  | 1569 |  | 
|  | 1570 | cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n", | 
|  | 1571 | __func__, server->total_read, data_offset); | 
|  | 1572 |  | 
|  | 1573 | len = data_offset - server->total_read; | 
|  | 1574 | if (len > 0) { | 
|  | 1575 | /* read any junk before data into the rest of smallbuf */ | 
|  | 1576 | length = cifs_read_from_socket(server, | 
|  | 1577 | buf + server->total_read, len); | 
|  | 1578 | if (length < 0) | 
|  | 1579 | return length; | 
|  | 1580 | server->total_read += length; | 
|  | 1581 | } | 
|  | 1582 |  | 
|  | 1583 | /* how much data is in the response? */ | 
|  | 1584 | #ifdef CONFIG_CIFS_SMB_DIRECT | 
|  | 1585 | use_rdma_mr = rdata->mr; | 
|  | 1586 | #endif | 
|  | 1587 | data_len = server->ops->read_data_length(buf, use_rdma_mr); | 
|  | 1588 | if (!use_rdma_mr && (data_offset + data_len > buflen)) { | 
|  | 1589 | /* data_len is corrupt -- discard frame */ | 
|  | 1590 | rdata->result = -EIO; | 
|  | 1591 | return cifs_readv_discard(server, mid); | 
|  | 1592 | } | 
|  | 1593 |  | 
|  | 1594 | length = rdata->read_into_pages(server, rdata, data_len); | 
|  | 1595 | if (length < 0) | 
|  | 1596 | return length; | 
|  | 1597 |  | 
|  | 1598 | server->total_read += length; | 
|  | 1599 |  | 
|  | 1600 | cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n", | 
|  | 1601 | server->total_read, buflen, data_len); | 
|  | 1602 |  | 
|  | 1603 | /* discard anything left over */ | 
|  | 1604 | if (server->total_read < buflen) | 
|  | 1605 | return cifs_readv_discard(server, mid); | 
|  | 1606 |  | 
|  | 1607 | dequeue_mid(mid, false); | 
|  | 1608 | mid->resp_buf = server->smallbuf; | 
|  | 1609 | server->smallbuf = NULL; | 
|  | 1610 | return length; | 
|  | 1611 | } | 
|  | 1612 |  | 
|  | 1613 | static void | 
|  | 1614 | cifs_readv_callback(struct mid_q_entry *mid) | 
|  | 1615 | { | 
|  | 1616 | struct cifs_readdata *rdata = mid->callback_data; | 
|  | 1617 | struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); | 
|  | 1618 | struct TCP_Server_Info *server = tcon->ses->server; | 
|  | 1619 | struct smb_rqst rqst = { .rq_iov = rdata->iov, | 
|  | 1620 | .rq_nvec = 2, | 
|  | 1621 | .rq_pages = rdata->pages, | 
|  | 1622 | .rq_npages = rdata->nr_pages, | 
|  | 1623 | .rq_pagesz = rdata->pagesz, | 
|  | 1624 | .rq_tailsz = rdata->tailsz }; | 
|  | 1625 |  | 
|  | 1626 | cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n", | 
|  | 1627 | __func__, mid->mid, mid->mid_state, rdata->result, | 
|  | 1628 | rdata->bytes); | 
|  | 1629 |  | 
|  | 1630 | switch (mid->mid_state) { | 
|  | 1631 | case MID_RESPONSE_RECEIVED: | 
|  | 1632 | /* result already set, check signature */ | 
|  | 1633 | if (server->sign) { | 
|  | 1634 | int rc = 0; | 
|  | 1635 |  | 
|  | 1636 | rc = cifs_verify_signature(&rqst, server, | 
|  | 1637 | mid->sequence_number); | 
|  | 1638 | if (rc) | 
|  | 1639 | cifs_dbg(VFS, "SMB signature verification returned error = %d\n", | 
|  | 1640 | rc); | 
|  | 1641 | } | 
|  | 1642 | /* FIXME: should this be counted toward the initiating task? */ | 
|  | 1643 | task_io_account_read(rdata->got_bytes); | 
|  | 1644 | cifs_stats_bytes_read(tcon, rdata->got_bytes); | 
|  | 1645 | break; | 
|  | 1646 | case MID_REQUEST_SUBMITTED: | 
|  | 1647 | case MID_RETRY_NEEDED: | 
|  | 1648 | rdata->result = -EAGAIN; | 
|  | 1649 | if (server->sign && rdata->got_bytes) | 
|  | 1650 | /* reset bytes number since we can not check a sign */ | 
|  | 1651 | rdata->got_bytes = 0; | 
|  | 1652 | /* FIXME: should this be counted toward the initiating task? */ | 
|  | 1653 | task_io_account_read(rdata->got_bytes); | 
|  | 1654 | cifs_stats_bytes_read(tcon, rdata->got_bytes); | 
|  | 1655 | break; | 
|  | 1656 | default: | 
|  | 1657 | rdata->result = -EIO; | 
|  | 1658 | } | 
|  | 1659 |  | 
|  | 1660 | queue_work(cifsiod_wq, &rdata->work); | 
|  | 1661 | DeleteMidQEntry(mid); | 
|  | 1662 | add_credits(server, 1, 0); | 
|  | 1663 | } | 
|  | 1664 |  | 
|  | 1665 | /* cifs_async_readv - send an async write, and set up mid to handle result */ | 
|  | 1666 | int | 
|  | 1667 | cifs_async_readv(struct cifs_readdata *rdata) | 
|  | 1668 | { | 
|  | 1669 | int rc; | 
|  | 1670 | READ_REQ *smb = NULL; | 
|  | 1671 | int wct; | 
|  | 1672 | struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); | 
|  | 1673 | struct smb_rqst rqst = { .rq_iov = rdata->iov, | 
|  | 1674 | .rq_nvec = 2 }; | 
|  | 1675 |  | 
|  | 1676 | cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", | 
|  | 1677 | __func__, rdata->offset, rdata->bytes); | 
|  | 1678 |  | 
|  | 1679 | if (tcon->ses->capabilities & CAP_LARGE_FILES) | 
|  | 1680 | wct = 12; | 
|  | 1681 | else { | 
|  | 1682 | wct = 10; /* old style read */ | 
|  | 1683 | if ((rdata->offset >> 32) > 0)  { | 
|  | 1684 | /* can not handle this big offset for old */ | 
|  | 1685 | return -EIO; | 
|  | 1686 | } | 
|  | 1687 | } | 
|  | 1688 |  | 
|  | 1689 | rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb); | 
|  | 1690 | if (rc) | 
|  | 1691 | return rc; | 
|  | 1692 |  | 
|  | 1693 | smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid); | 
|  | 1694 | smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16)); | 
|  | 1695 |  | 
|  | 1696 | smb->AndXCommand = 0xFF;	/* none */ | 
|  | 1697 | smb->Fid = rdata->cfile->fid.netfid; | 
|  | 1698 | smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF); | 
|  | 1699 | if (wct == 12) | 
|  | 1700 | smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32); | 
|  | 1701 | smb->Remaining = 0; | 
|  | 1702 | smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF); | 
|  | 1703 | smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16); | 
|  | 1704 | if (wct == 12) | 
|  | 1705 | smb->ByteCount = 0; | 
|  | 1706 | else { | 
|  | 1707 | /* old style read */ | 
|  | 1708 | struct smb_com_readx_req *smbr = | 
|  | 1709 | (struct smb_com_readx_req *)smb; | 
|  | 1710 | smbr->ByteCount = 0; | 
|  | 1711 | } | 
|  | 1712 |  | 
|  | 1713 | /* 4 for RFC1001 length + 1 for BCC */ | 
|  | 1714 | rdata->iov[0].iov_base = smb; | 
|  | 1715 | rdata->iov[0].iov_len = 4; | 
|  | 1716 | rdata->iov[1].iov_base = (char *)smb + 4; | 
|  | 1717 | rdata->iov[1].iov_len = get_rfc1002_length(smb); | 
|  | 1718 |  | 
|  | 1719 | kref_get(&rdata->refcount); | 
|  | 1720 | rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive, | 
|  | 1721 | cifs_readv_callback, NULL, rdata, 0); | 
|  | 1722 |  | 
|  | 1723 | if (rc == 0) | 
|  | 1724 | cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); | 
|  | 1725 | else | 
|  | 1726 | kref_put(&rdata->refcount, cifs_readdata_release); | 
|  | 1727 |  | 
|  | 1728 | cifs_small_buf_release(smb); | 
|  | 1729 | return rc; | 
|  | 1730 | } | 
|  | 1731 |  | 
|  | 1732 | int | 
|  | 1733 | CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms, | 
|  | 1734 | unsigned int *nbytes, char **buf, int *pbuf_type) | 
|  | 1735 | { | 
|  | 1736 | int rc = -EACCES; | 
|  | 1737 | READ_REQ *pSMB = NULL; | 
|  | 1738 | READ_RSP *pSMBr = NULL; | 
|  | 1739 | char *pReadData = NULL; | 
|  | 1740 | int wct; | 
|  | 1741 | int resp_buf_type = 0; | 
|  | 1742 | struct kvec iov[1]; | 
|  | 1743 | struct kvec rsp_iov; | 
|  | 1744 | __u32 pid = io_parms->pid; | 
|  | 1745 | __u16 netfid = io_parms->netfid; | 
|  | 1746 | __u64 offset = io_parms->offset; | 
|  | 1747 | struct cifs_tcon *tcon = io_parms->tcon; | 
|  | 1748 | unsigned int count = io_parms->length; | 
|  | 1749 |  | 
|  | 1750 | cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid); | 
|  | 1751 | if (tcon->ses->capabilities & CAP_LARGE_FILES) | 
|  | 1752 | wct = 12; | 
|  | 1753 | else { | 
|  | 1754 | wct = 10; /* old style read */ | 
|  | 1755 | if ((offset >> 32) > 0)  { | 
|  | 1756 | /* can not handle this big offset for old */ | 
|  | 1757 | return -EIO; | 
|  | 1758 | } | 
|  | 1759 | } | 
|  | 1760 |  | 
|  | 1761 | *nbytes = 0; | 
|  | 1762 | rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB); | 
|  | 1763 | if (rc) | 
|  | 1764 | return rc; | 
|  | 1765 |  | 
|  | 1766 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid); | 
|  | 1767 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); | 
|  | 1768 |  | 
|  | 1769 | /* tcon and ses pointer are checked in smb_init */ | 
|  | 1770 | if (tcon->ses->server == NULL) | 
|  | 1771 | return -ECONNABORTED; | 
|  | 1772 |  | 
|  | 1773 | pSMB->AndXCommand = 0xFF;       /* none */ | 
|  | 1774 | pSMB->Fid = netfid; | 
|  | 1775 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | 
|  | 1776 | if (wct == 12) | 
|  | 1777 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | 
|  | 1778 |  | 
|  | 1779 | pSMB->Remaining = 0; | 
|  | 1780 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); | 
|  | 1781 | pSMB->MaxCountHigh = cpu_to_le32(count >> 16); | 
|  | 1782 | if (wct == 12) | 
|  | 1783 | pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */ | 
|  | 1784 | else { | 
|  | 1785 | /* old style read */ | 
|  | 1786 | struct smb_com_readx_req *pSMBW = | 
|  | 1787 | (struct smb_com_readx_req *)pSMB; | 
|  | 1788 | pSMBW->ByteCount = 0; | 
|  | 1789 | } | 
|  | 1790 |  | 
|  | 1791 | iov[0].iov_base = (char *)pSMB; | 
|  | 1792 | iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; | 
|  | 1793 | rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type, | 
|  | 1794 | CIFS_LOG_ERROR, &rsp_iov); | 
|  | 1795 | cifs_small_buf_release(pSMB); | 
|  | 1796 | cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); | 
|  | 1797 | pSMBr = (READ_RSP *)rsp_iov.iov_base; | 
|  | 1798 | if (rc) { | 
|  | 1799 | cifs_dbg(VFS, "Send error in read = %d\n", rc); | 
|  | 1800 | } else { | 
|  | 1801 | int data_length = le16_to_cpu(pSMBr->DataLengthHigh); | 
|  | 1802 | data_length = data_length << 16; | 
|  | 1803 | data_length += le16_to_cpu(pSMBr->DataLength); | 
|  | 1804 | *nbytes = data_length; | 
|  | 1805 |  | 
|  | 1806 | /*check that DataLength would not go beyond end of SMB */ | 
|  | 1807 | if ((data_length > CIFSMaxBufSize) | 
|  | 1808 | || (data_length > count)) { | 
|  | 1809 | cifs_dbg(FYI, "bad length %d for count %d\n", | 
|  | 1810 | data_length, count); | 
|  | 1811 | rc = -EIO; | 
|  | 1812 | *nbytes = 0; | 
|  | 1813 | } else { | 
|  | 1814 | pReadData = (char *) (&pSMBr->hdr.Protocol) + | 
|  | 1815 | le16_to_cpu(pSMBr->DataOffset); | 
|  | 1816 | /*			if (rc = copy_to_user(buf, pReadData, data_length)) { | 
|  | 1817 | cifs_dbg(VFS, "Faulting on read rc = %d\n",rc); | 
|  | 1818 | rc = -EFAULT; | 
|  | 1819 | }*/ /* can not use copy_to_user when using page cache*/ | 
|  | 1820 | if (*buf) | 
|  | 1821 | memcpy(*buf, pReadData, data_length); | 
|  | 1822 | } | 
|  | 1823 | } | 
|  | 1824 |  | 
|  | 1825 | if (*buf) { | 
|  | 1826 | free_rsp_buf(resp_buf_type, rsp_iov.iov_base); | 
|  | 1827 | } else if (resp_buf_type != CIFS_NO_BUFFER) { | 
|  | 1828 | /* return buffer to caller to free */ | 
|  | 1829 | *buf = rsp_iov.iov_base; | 
|  | 1830 | if (resp_buf_type == CIFS_SMALL_BUFFER) | 
|  | 1831 | *pbuf_type = CIFS_SMALL_BUFFER; | 
|  | 1832 | else if (resp_buf_type == CIFS_LARGE_BUFFER) | 
|  | 1833 | *pbuf_type = CIFS_LARGE_BUFFER; | 
|  | 1834 | } /* else no valid buffer on return - leave as null */ | 
|  | 1835 |  | 
|  | 1836 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 1837 | since file handle passed in no longer valid */ | 
|  | 1838 | return rc; | 
|  | 1839 | } | 
|  | 1840 |  | 
|  | 1841 |  | 
|  | 1842 | int | 
|  | 1843 | CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, | 
|  | 1844 | unsigned int *nbytes, const char *buf) | 
|  | 1845 | { | 
|  | 1846 | int rc = -EACCES; | 
|  | 1847 | WRITE_REQ *pSMB = NULL; | 
|  | 1848 | WRITE_RSP *pSMBr = NULL; | 
|  | 1849 | int bytes_returned, wct; | 
|  | 1850 | __u32 bytes_sent; | 
|  | 1851 | __u16 byte_count; | 
|  | 1852 | __u32 pid = io_parms->pid; | 
|  | 1853 | __u16 netfid = io_parms->netfid; | 
|  | 1854 | __u64 offset = io_parms->offset; | 
|  | 1855 | struct cifs_tcon *tcon = io_parms->tcon; | 
|  | 1856 | unsigned int count = io_parms->length; | 
|  | 1857 |  | 
|  | 1858 | *nbytes = 0; | 
|  | 1859 |  | 
|  | 1860 | /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/ | 
|  | 1861 | if (tcon->ses == NULL) | 
|  | 1862 | return -ECONNABORTED; | 
|  | 1863 |  | 
|  | 1864 | if (tcon->ses->capabilities & CAP_LARGE_FILES) | 
|  | 1865 | wct = 14; | 
|  | 1866 | else { | 
|  | 1867 | wct = 12; | 
|  | 1868 | if ((offset >> 32) > 0) { | 
|  | 1869 | /* can not handle big offset for old srv */ | 
|  | 1870 | return -EIO; | 
|  | 1871 | } | 
|  | 1872 | } | 
|  | 1873 |  | 
|  | 1874 | rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB, | 
|  | 1875 | (void **) &pSMBr); | 
|  | 1876 | if (rc) | 
|  | 1877 | return rc; | 
|  | 1878 |  | 
|  | 1879 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid); | 
|  | 1880 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); | 
|  | 1881 |  | 
|  | 1882 | /* tcon and ses pointer are checked in smb_init */ | 
|  | 1883 | if (tcon->ses->server == NULL) | 
|  | 1884 | return -ECONNABORTED; | 
|  | 1885 |  | 
|  | 1886 | pSMB->AndXCommand = 0xFF;	/* none */ | 
|  | 1887 | pSMB->Fid = netfid; | 
|  | 1888 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | 
|  | 1889 | if (wct == 14) | 
|  | 1890 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | 
|  | 1891 |  | 
|  | 1892 | pSMB->Reserved = 0xFFFFFFFF; | 
|  | 1893 | pSMB->WriteMode = 0; | 
|  | 1894 | pSMB->Remaining = 0; | 
|  | 1895 |  | 
|  | 1896 | /* Can increase buffer size if buffer is big enough in some cases ie we | 
|  | 1897 | can send more if LARGE_WRITE_X capability returned by the server and if | 
|  | 1898 | our buffer is big enough or if we convert to iovecs on socket writes | 
|  | 1899 | and eliminate the copy to the CIFS buffer */ | 
|  | 1900 | if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) { | 
|  | 1901 | bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count); | 
|  | 1902 | } else { | 
|  | 1903 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) | 
|  | 1904 | & ~0xFF; | 
|  | 1905 | } | 
|  | 1906 |  | 
|  | 1907 | if (bytes_sent > count) | 
|  | 1908 | bytes_sent = count; | 
|  | 1909 | pSMB->DataOffset = | 
|  | 1910 | cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); | 
|  | 1911 | if (buf) | 
|  | 1912 | memcpy(pSMB->Data, buf, bytes_sent); | 
|  | 1913 | else if (count != 0) { | 
|  | 1914 | /* No buffer */ | 
|  | 1915 | cifs_buf_release(pSMB); | 
|  | 1916 | return -EINVAL; | 
|  | 1917 | } /* else setting file size with write of zero bytes */ | 
|  | 1918 | if (wct == 14) | 
|  | 1919 | byte_count = bytes_sent + 1; /* pad */ | 
|  | 1920 | else /* wct == 12 */ | 
|  | 1921 | byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */ | 
|  | 1922 |  | 
|  | 1923 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); | 
|  | 1924 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); | 
|  | 1925 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 1926 |  | 
|  | 1927 | if (wct == 14) | 
|  | 1928 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 1929 | else { /* old style write has byte count 4 bytes earlier | 
|  | 1930 | so 4 bytes pad  */ | 
|  | 1931 | struct smb_com_writex_req *pSMBW = | 
|  | 1932 | (struct smb_com_writex_req *)pSMB; | 
|  | 1933 | pSMBW->ByteCount = cpu_to_le16(byte_count); | 
|  | 1934 | } | 
|  | 1935 |  | 
|  | 1936 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 1937 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 1938 | cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); | 
|  | 1939 | if (rc) { | 
|  | 1940 | cifs_dbg(FYI, "Send error in write = %d\n", rc); | 
|  | 1941 | } else { | 
|  | 1942 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | 
|  | 1943 | *nbytes = (*nbytes) << 16; | 
|  | 1944 | *nbytes += le16_to_cpu(pSMBr->Count); | 
|  | 1945 |  | 
|  | 1946 | /* | 
|  | 1947 | * Mask off high 16 bits when bytes written as returned by the | 
|  | 1948 | * server is greater than bytes requested by the client. Some | 
|  | 1949 | * OS/2 servers are known to set incorrect CountHigh values. | 
|  | 1950 | */ | 
|  | 1951 | if (*nbytes > count) | 
|  | 1952 | *nbytes &= 0xFFFF; | 
|  | 1953 | } | 
|  | 1954 |  | 
|  | 1955 | cifs_buf_release(pSMB); | 
|  | 1956 |  | 
|  | 1957 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 1958 | since file handle passed in no longer valid */ | 
|  | 1959 |  | 
|  | 1960 | return rc; | 
|  | 1961 | } | 
|  | 1962 |  | 
|  | 1963 | void | 
|  | 1964 | cifs_writedata_release(struct kref *refcount) | 
|  | 1965 | { | 
|  | 1966 | struct cifs_writedata *wdata = container_of(refcount, | 
|  | 1967 | struct cifs_writedata, refcount); | 
|  | 1968 | #ifdef CONFIG_CIFS_SMB_DIRECT | 
|  | 1969 | if (wdata->mr) { | 
|  | 1970 | smbd_deregister_mr(wdata->mr); | 
|  | 1971 | wdata->mr = NULL; | 
|  | 1972 | } | 
|  | 1973 | #endif | 
|  | 1974 |  | 
|  | 1975 | if (wdata->cfile) | 
|  | 1976 | cifsFileInfo_put(wdata->cfile); | 
|  | 1977 |  | 
|  | 1978 | kvfree(wdata->pages); | 
|  | 1979 | kfree(wdata); | 
|  | 1980 | } | 
|  | 1981 |  | 
|  | 1982 | /* | 
|  | 1983 | * Write failed with a retryable error. Resend the write request. It's also | 
|  | 1984 | * possible that the page was redirtied so re-clean the page. | 
|  | 1985 | */ | 
|  | 1986 | static void | 
|  | 1987 | cifs_writev_requeue(struct cifs_writedata *wdata) | 
|  | 1988 | { | 
|  | 1989 | int i, rc = 0; | 
|  | 1990 | struct inode *inode = d_inode(wdata->cfile->dentry); | 
|  | 1991 | struct TCP_Server_Info *server; | 
|  | 1992 | unsigned int rest_len; | 
|  | 1993 |  | 
|  | 1994 | server = tlink_tcon(wdata->cfile->tlink)->ses->server; | 
|  | 1995 | i = 0; | 
|  | 1996 | rest_len = wdata->bytes; | 
|  | 1997 | do { | 
|  | 1998 | struct cifs_writedata *wdata2; | 
|  | 1999 | unsigned int j, nr_pages, wsize, tailsz, cur_len; | 
|  | 2000 |  | 
|  | 2001 | wsize = server->ops->wp_retry_size(inode); | 
|  | 2002 | if (wsize < rest_len) { | 
|  | 2003 | nr_pages = wsize / PAGE_SIZE; | 
|  | 2004 | if (!nr_pages) { | 
|  | 2005 | rc = -ENOTSUPP; | 
|  | 2006 | break; | 
|  | 2007 | } | 
|  | 2008 | cur_len = nr_pages * PAGE_SIZE; | 
|  | 2009 | tailsz = PAGE_SIZE; | 
|  | 2010 | } else { | 
|  | 2011 | nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE); | 
|  | 2012 | cur_len = rest_len; | 
|  | 2013 | tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE; | 
|  | 2014 | } | 
|  | 2015 |  | 
|  | 2016 | wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete); | 
|  | 2017 | if (!wdata2) { | 
|  | 2018 | rc = -ENOMEM; | 
|  | 2019 | break; | 
|  | 2020 | } | 
|  | 2021 |  | 
|  | 2022 | for (j = 0; j < nr_pages; j++) { | 
|  | 2023 | wdata2->pages[j] = wdata->pages[i + j]; | 
|  | 2024 | lock_page(wdata2->pages[j]); | 
|  | 2025 | clear_page_dirty_for_io(wdata2->pages[j]); | 
|  | 2026 | } | 
|  | 2027 |  | 
|  | 2028 | wdata2->sync_mode = wdata->sync_mode; | 
|  | 2029 | wdata2->nr_pages = nr_pages; | 
|  | 2030 | wdata2->offset = page_offset(wdata2->pages[0]); | 
|  | 2031 | wdata2->pagesz = PAGE_SIZE; | 
|  | 2032 | wdata2->tailsz = tailsz; | 
|  | 2033 | wdata2->bytes = cur_len; | 
|  | 2034 |  | 
|  | 2035 | wdata2->cfile = find_writable_file(CIFS_I(inode), false); | 
|  | 2036 | if (!wdata2->cfile) { | 
|  | 2037 | cifs_dbg(VFS, "No writable handle to retry writepages\n"); | 
|  | 2038 | rc = -EBADF; | 
|  | 2039 | } else { | 
|  | 2040 | wdata2->pid = wdata2->cfile->pid; | 
|  | 2041 | rc = server->ops->async_writev(wdata2, | 
|  | 2042 | cifs_writedata_release); | 
|  | 2043 | } | 
|  | 2044 |  | 
|  | 2045 | for (j = 0; j < nr_pages; j++) { | 
|  | 2046 | unlock_page(wdata2->pages[j]); | 
|  | 2047 | if (rc != 0 && !is_retryable_error(rc)) { | 
|  | 2048 | SetPageError(wdata2->pages[j]); | 
|  | 2049 | end_page_writeback(wdata2->pages[j]); | 
|  | 2050 | put_page(wdata2->pages[j]); | 
|  | 2051 | } | 
|  | 2052 | } | 
|  | 2053 |  | 
|  | 2054 | if (rc) { | 
|  | 2055 | kref_put(&wdata2->refcount, cifs_writedata_release); | 
|  | 2056 | if (is_retryable_error(rc)) | 
|  | 2057 | continue; | 
|  | 2058 | i += nr_pages; | 
|  | 2059 | break; | 
|  | 2060 | } | 
|  | 2061 |  | 
|  | 2062 | rest_len -= cur_len; | 
|  | 2063 | i += nr_pages; | 
|  | 2064 | } while (i < wdata->nr_pages); | 
|  | 2065 |  | 
|  | 2066 | /* cleanup remaining pages from the original wdata */ | 
|  | 2067 | for (; i < wdata->nr_pages; i++) { | 
|  | 2068 | SetPageError(wdata->pages[i]); | 
|  | 2069 | end_page_writeback(wdata->pages[i]); | 
|  | 2070 | put_page(wdata->pages[i]); | 
|  | 2071 | } | 
|  | 2072 |  | 
|  | 2073 | if (rc != 0 && !is_retryable_error(rc)) | 
|  | 2074 | mapping_set_error(inode->i_mapping, rc); | 
|  | 2075 | kref_put(&wdata->refcount, cifs_writedata_release); | 
|  | 2076 | } | 
|  | 2077 |  | 
|  | 2078 | void | 
|  | 2079 | cifs_writev_complete(struct work_struct *work) | 
|  | 2080 | { | 
|  | 2081 | struct cifs_writedata *wdata = container_of(work, | 
|  | 2082 | struct cifs_writedata, work); | 
|  | 2083 | struct inode *inode = d_inode(wdata->cfile->dentry); | 
|  | 2084 | int i = 0; | 
|  | 2085 |  | 
|  | 2086 | if (wdata->result == 0) { | 
|  | 2087 | spin_lock(&inode->i_lock); | 
|  | 2088 | cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes); | 
|  | 2089 | spin_unlock(&inode->i_lock); | 
|  | 2090 | cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink), | 
|  | 2091 | wdata->bytes); | 
|  | 2092 | } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN) | 
|  | 2093 | return cifs_writev_requeue(wdata); | 
|  | 2094 |  | 
|  | 2095 | for (i = 0; i < wdata->nr_pages; i++) { | 
|  | 2096 | struct page *page = wdata->pages[i]; | 
|  | 2097 | if (wdata->result == -EAGAIN) | 
|  | 2098 | __set_page_dirty_nobuffers(page); | 
|  | 2099 | else if (wdata->result < 0) | 
|  | 2100 | SetPageError(page); | 
|  | 2101 | end_page_writeback(page); | 
|  | 2102 | put_page(page); | 
|  | 2103 | } | 
|  | 2104 | if (wdata->result != -EAGAIN) | 
|  | 2105 | mapping_set_error(inode->i_mapping, wdata->result); | 
|  | 2106 | kref_put(&wdata->refcount, cifs_writedata_release); | 
|  | 2107 | } | 
|  | 2108 |  | 
|  | 2109 | struct cifs_writedata * | 
|  | 2110 | cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete) | 
|  | 2111 | { | 
|  | 2112 | struct page **pages = | 
|  | 2113 | kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS); | 
|  | 2114 | if (pages) | 
|  | 2115 | return cifs_writedata_direct_alloc(pages, complete); | 
|  | 2116 |  | 
|  | 2117 | return NULL; | 
|  | 2118 | } | 
|  | 2119 |  | 
|  | 2120 | struct cifs_writedata * | 
|  | 2121 | cifs_writedata_direct_alloc(struct page **pages, work_func_t complete) | 
|  | 2122 | { | 
|  | 2123 | struct cifs_writedata *wdata; | 
|  | 2124 |  | 
|  | 2125 | wdata = kzalloc(sizeof(*wdata), GFP_NOFS); | 
|  | 2126 | if (wdata != NULL) { | 
|  | 2127 | wdata->pages = pages; | 
|  | 2128 | kref_init(&wdata->refcount); | 
|  | 2129 | INIT_LIST_HEAD(&wdata->list); | 
|  | 2130 | init_completion(&wdata->done); | 
|  | 2131 | INIT_WORK(&wdata->work, complete); | 
|  | 2132 | } | 
|  | 2133 | return wdata; | 
|  | 2134 | } | 
|  | 2135 |  | 
|  | 2136 | /* | 
|  | 2137 | * Check the mid_state and signature on received buffer (if any), and queue the | 
|  | 2138 | * workqueue completion task. | 
|  | 2139 | */ | 
|  | 2140 | static void | 
|  | 2141 | cifs_writev_callback(struct mid_q_entry *mid) | 
|  | 2142 | { | 
|  | 2143 | struct cifs_writedata *wdata = mid->callback_data; | 
|  | 2144 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); | 
|  | 2145 | unsigned int written; | 
|  | 2146 | WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf; | 
|  | 2147 |  | 
|  | 2148 | switch (mid->mid_state) { | 
|  | 2149 | case MID_RESPONSE_RECEIVED: | 
|  | 2150 | wdata->result = cifs_check_receive(mid, tcon->ses->server, 0); | 
|  | 2151 | if (wdata->result != 0) | 
|  | 2152 | break; | 
|  | 2153 |  | 
|  | 2154 | written = le16_to_cpu(smb->CountHigh); | 
|  | 2155 | written <<= 16; | 
|  | 2156 | written += le16_to_cpu(smb->Count); | 
|  | 2157 | /* | 
|  | 2158 | * Mask off high 16 bits when bytes written as returned | 
|  | 2159 | * by the server is greater than bytes requested by the | 
|  | 2160 | * client. OS/2 servers are known to set incorrect | 
|  | 2161 | * CountHigh values. | 
|  | 2162 | */ | 
|  | 2163 | if (written > wdata->bytes) | 
|  | 2164 | written &= 0xFFFF; | 
|  | 2165 |  | 
|  | 2166 | if (written < wdata->bytes) | 
|  | 2167 | wdata->result = -ENOSPC; | 
|  | 2168 | else | 
|  | 2169 | wdata->bytes = written; | 
|  | 2170 | break; | 
|  | 2171 | case MID_REQUEST_SUBMITTED: | 
|  | 2172 | case MID_RETRY_NEEDED: | 
|  | 2173 | wdata->result = -EAGAIN; | 
|  | 2174 | break; | 
|  | 2175 | default: | 
|  | 2176 | wdata->result = -EIO; | 
|  | 2177 | break; | 
|  | 2178 | } | 
|  | 2179 |  | 
|  | 2180 | queue_work(cifsiod_wq, &wdata->work); | 
|  | 2181 | DeleteMidQEntry(mid); | 
|  | 2182 | add_credits(tcon->ses->server, 1, 0); | 
|  | 2183 | } | 
|  | 2184 |  | 
|  | 2185 | /* cifs_async_writev - send an async write, and set up mid to handle result */ | 
|  | 2186 | int | 
|  | 2187 | cifs_async_writev(struct cifs_writedata *wdata, | 
|  | 2188 | void (*release)(struct kref *kref)) | 
|  | 2189 | { | 
|  | 2190 | int rc = -EACCES; | 
|  | 2191 | WRITE_REQ *smb = NULL; | 
|  | 2192 | int wct; | 
|  | 2193 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); | 
|  | 2194 | struct kvec iov[2]; | 
|  | 2195 | struct smb_rqst rqst = { }; | 
|  | 2196 |  | 
|  | 2197 | if (tcon->ses->capabilities & CAP_LARGE_FILES) { | 
|  | 2198 | wct = 14; | 
|  | 2199 | } else { | 
|  | 2200 | wct = 12; | 
|  | 2201 | if (wdata->offset >> 32 > 0) { | 
|  | 2202 | /* can not handle big offset for old srv */ | 
|  | 2203 | return -EIO; | 
|  | 2204 | } | 
|  | 2205 | } | 
|  | 2206 |  | 
|  | 2207 | rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb); | 
|  | 2208 | if (rc) | 
|  | 2209 | goto async_writev_out; | 
|  | 2210 |  | 
|  | 2211 | smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid); | 
|  | 2212 | smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16)); | 
|  | 2213 |  | 
|  | 2214 | smb->AndXCommand = 0xFF;	/* none */ | 
|  | 2215 | smb->Fid = wdata->cfile->fid.netfid; | 
|  | 2216 | smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF); | 
|  | 2217 | if (wct == 14) | 
|  | 2218 | smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32); | 
|  | 2219 | smb->Reserved = 0xFFFFFFFF; | 
|  | 2220 | smb->WriteMode = 0; | 
|  | 2221 | smb->Remaining = 0; | 
|  | 2222 |  | 
|  | 2223 | smb->DataOffset = | 
|  | 2224 | cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); | 
|  | 2225 |  | 
|  | 2226 | /* 4 for RFC1001 length + 1 for BCC */ | 
|  | 2227 | iov[0].iov_len = 4; | 
|  | 2228 | iov[0].iov_base = smb; | 
|  | 2229 | iov[1].iov_len = get_rfc1002_length(smb) + 1; | 
|  | 2230 | iov[1].iov_base = (char *)smb + 4; | 
|  | 2231 |  | 
|  | 2232 | rqst.rq_iov = iov; | 
|  | 2233 | rqst.rq_nvec = 2; | 
|  | 2234 | rqst.rq_pages = wdata->pages; | 
|  | 2235 | rqst.rq_npages = wdata->nr_pages; | 
|  | 2236 | rqst.rq_pagesz = wdata->pagesz; | 
|  | 2237 | rqst.rq_tailsz = wdata->tailsz; | 
|  | 2238 |  | 
|  | 2239 | cifs_dbg(FYI, "async write at %llu %u bytes\n", | 
|  | 2240 | wdata->offset, wdata->bytes); | 
|  | 2241 |  | 
|  | 2242 | smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF); | 
|  | 2243 | smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16); | 
|  | 2244 |  | 
|  | 2245 | if (wct == 14) { | 
|  | 2246 | inc_rfc1001_len(&smb->hdr, wdata->bytes + 1); | 
|  | 2247 | put_bcc(wdata->bytes + 1, &smb->hdr); | 
|  | 2248 | } else { | 
|  | 2249 | /* wct == 12 */ | 
|  | 2250 | struct smb_com_writex_req *smbw = | 
|  | 2251 | (struct smb_com_writex_req *)smb; | 
|  | 2252 | inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5); | 
|  | 2253 | put_bcc(wdata->bytes + 5, &smbw->hdr); | 
|  | 2254 | iov[1].iov_len += 4; /* pad bigger by four bytes */ | 
|  | 2255 | } | 
|  | 2256 |  | 
|  | 2257 | kref_get(&wdata->refcount); | 
|  | 2258 | rc = cifs_call_async(tcon->ses->server, &rqst, NULL, | 
|  | 2259 | cifs_writev_callback, NULL, wdata, 0); | 
|  | 2260 |  | 
|  | 2261 | if (rc == 0) | 
|  | 2262 | cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); | 
|  | 2263 | else | 
|  | 2264 | kref_put(&wdata->refcount, release); | 
|  | 2265 |  | 
|  | 2266 | async_writev_out: | 
|  | 2267 | cifs_small_buf_release(smb); | 
|  | 2268 | return rc; | 
|  | 2269 | } | 
|  | 2270 |  | 
|  | 2271 | int | 
|  | 2272 | CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms, | 
|  | 2273 | unsigned int *nbytes, struct kvec *iov, int n_vec) | 
|  | 2274 | { | 
|  | 2275 | int rc = -EACCES; | 
|  | 2276 | WRITE_REQ *pSMB = NULL; | 
|  | 2277 | int wct; | 
|  | 2278 | int smb_hdr_len; | 
|  | 2279 | int resp_buf_type = 0; | 
|  | 2280 | __u32 pid = io_parms->pid; | 
|  | 2281 | __u16 netfid = io_parms->netfid; | 
|  | 2282 | __u64 offset = io_parms->offset; | 
|  | 2283 | struct cifs_tcon *tcon = io_parms->tcon; | 
|  | 2284 | unsigned int count = io_parms->length; | 
|  | 2285 | struct kvec rsp_iov; | 
|  | 2286 |  | 
|  | 2287 | *nbytes = 0; | 
|  | 2288 |  | 
|  | 2289 | cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count); | 
|  | 2290 |  | 
|  | 2291 | if (tcon->ses->capabilities & CAP_LARGE_FILES) { | 
|  | 2292 | wct = 14; | 
|  | 2293 | } else { | 
|  | 2294 | wct = 12; | 
|  | 2295 | if ((offset >> 32) > 0) { | 
|  | 2296 | /* can not handle big offset for old srv */ | 
|  | 2297 | return -EIO; | 
|  | 2298 | } | 
|  | 2299 | } | 
|  | 2300 | rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB); | 
|  | 2301 | if (rc) | 
|  | 2302 | return rc; | 
|  | 2303 |  | 
|  | 2304 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid); | 
|  | 2305 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); | 
|  | 2306 |  | 
|  | 2307 | /* tcon and ses pointer are checked in smb_init */ | 
|  | 2308 | if (tcon->ses->server == NULL) | 
|  | 2309 | return -ECONNABORTED; | 
|  | 2310 |  | 
|  | 2311 | pSMB->AndXCommand = 0xFF;	/* none */ | 
|  | 2312 | pSMB->Fid = netfid; | 
|  | 2313 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | 
|  | 2314 | if (wct == 14) | 
|  | 2315 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | 
|  | 2316 | pSMB->Reserved = 0xFFFFFFFF; | 
|  | 2317 | pSMB->WriteMode = 0; | 
|  | 2318 | pSMB->Remaining = 0; | 
|  | 2319 |  | 
|  | 2320 | pSMB->DataOffset = | 
|  | 2321 | cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); | 
|  | 2322 |  | 
|  | 2323 | pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); | 
|  | 2324 | pSMB->DataLengthHigh = cpu_to_le16(count >> 16); | 
|  | 2325 | /* header + 1 byte pad */ | 
|  | 2326 | smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1; | 
|  | 2327 | if (wct == 14) | 
|  | 2328 | inc_rfc1001_len(pSMB, count + 1); | 
|  | 2329 | else /* wct == 12 */ | 
|  | 2330 | inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */ | 
|  | 2331 | if (wct == 14) | 
|  | 2332 | pSMB->ByteCount = cpu_to_le16(count + 1); | 
|  | 2333 | else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ { | 
|  | 2334 | struct smb_com_writex_req *pSMBW = | 
|  | 2335 | (struct smb_com_writex_req *)pSMB; | 
|  | 2336 | pSMBW->ByteCount = cpu_to_le16(count + 5); | 
|  | 2337 | } | 
|  | 2338 | iov[0].iov_base = pSMB; | 
|  | 2339 | if (wct == 14) | 
|  | 2340 | iov[0].iov_len = smb_hdr_len + 4; | 
|  | 2341 | else /* wct == 12 pad bigger by four bytes */ | 
|  | 2342 | iov[0].iov_len = smb_hdr_len + 8; | 
|  | 2343 |  | 
|  | 2344 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0, | 
|  | 2345 | &rsp_iov); | 
|  | 2346 | cifs_small_buf_release(pSMB); | 
|  | 2347 | cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); | 
|  | 2348 | if (rc) { | 
|  | 2349 | cifs_dbg(FYI, "Send error Write2 = %d\n", rc); | 
|  | 2350 | } else if (resp_buf_type == 0) { | 
|  | 2351 | /* presumably this can not happen, but best to be safe */ | 
|  | 2352 | rc = -EIO; | 
|  | 2353 | } else { | 
|  | 2354 | WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base; | 
|  | 2355 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | 
|  | 2356 | *nbytes = (*nbytes) << 16; | 
|  | 2357 | *nbytes += le16_to_cpu(pSMBr->Count); | 
|  | 2358 |  | 
|  | 2359 | /* | 
|  | 2360 | * Mask off high 16 bits when bytes written as returned by the | 
|  | 2361 | * server is greater than bytes requested by the client. OS/2 | 
|  | 2362 | * servers are known to set incorrect CountHigh values. | 
|  | 2363 | */ | 
|  | 2364 | if (*nbytes > count) | 
|  | 2365 | *nbytes &= 0xFFFF; | 
|  | 2366 | } | 
|  | 2367 |  | 
|  | 2368 | free_rsp_buf(resp_buf_type, rsp_iov.iov_base); | 
|  | 2369 |  | 
|  | 2370 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 2371 | since file handle passed in no longer valid */ | 
|  | 2372 |  | 
|  | 2373 | return rc; | 
|  | 2374 | } | 
|  | 2375 |  | 
|  | 2376 | int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 2377 | const __u16 netfid, const __u8 lock_type, const __u32 num_unlock, | 
|  | 2378 | const __u32 num_lock, LOCKING_ANDX_RANGE *buf) | 
|  | 2379 | { | 
|  | 2380 | int rc = 0; | 
|  | 2381 | LOCK_REQ *pSMB = NULL; | 
|  | 2382 | struct kvec iov[2]; | 
|  | 2383 | struct kvec rsp_iov; | 
|  | 2384 | int resp_buf_type; | 
|  | 2385 | __u16 count; | 
|  | 2386 |  | 
|  | 2387 | cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n", | 
|  | 2388 | num_lock, num_unlock); | 
|  | 2389 |  | 
|  | 2390 | rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); | 
|  | 2391 | if (rc) | 
|  | 2392 | return rc; | 
|  | 2393 |  | 
|  | 2394 | pSMB->Timeout = 0; | 
|  | 2395 | pSMB->NumberOfLocks = cpu_to_le16(num_lock); | 
|  | 2396 | pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock); | 
|  | 2397 | pSMB->LockType = lock_type; | 
|  | 2398 | pSMB->AndXCommand = 0xFF; /* none */ | 
|  | 2399 | pSMB->Fid = netfid; /* netfid stays le */ | 
|  | 2400 |  | 
|  | 2401 | count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); | 
|  | 2402 | inc_rfc1001_len(pSMB, count); | 
|  | 2403 | pSMB->ByteCount = cpu_to_le16(count); | 
|  | 2404 |  | 
|  | 2405 | iov[0].iov_base = (char *)pSMB; | 
|  | 2406 | iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 - | 
|  | 2407 | (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); | 
|  | 2408 | iov[1].iov_base = (char *)buf; | 
|  | 2409 | iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); | 
|  | 2410 |  | 
|  | 2411 | cifs_stats_inc(&tcon->stats.cifs_stats.num_locks); | 
|  | 2412 | rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP, | 
|  | 2413 | &rsp_iov); | 
|  | 2414 | cifs_small_buf_release(pSMB); | 
|  | 2415 | if (rc) | 
|  | 2416 | cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc); | 
|  | 2417 |  | 
|  | 2418 | return rc; | 
|  | 2419 | } | 
|  | 2420 |  | 
|  | 2421 | int | 
|  | 2422 | CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 2423 | const __u16 smb_file_id, const __u32 netpid, const __u64 len, | 
|  | 2424 | const __u64 offset, const __u32 numUnlock, | 
|  | 2425 | const __u32 numLock, const __u8 lockType, | 
|  | 2426 | const bool waitFlag, const __u8 oplock_level) | 
|  | 2427 | { | 
|  | 2428 | int rc = 0; | 
|  | 2429 | LOCK_REQ *pSMB = NULL; | 
|  | 2430 | /*	LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */ | 
|  | 2431 | int bytes_returned; | 
|  | 2432 | int flags = 0; | 
|  | 2433 | __u16 count; | 
|  | 2434 |  | 
|  | 2435 | cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n", | 
|  | 2436 | (int)waitFlag, numLock); | 
|  | 2437 | rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); | 
|  | 2438 |  | 
|  | 2439 | if (rc) | 
|  | 2440 | return rc; | 
|  | 2441 |  | 
|  | 2442 | if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) { | 
|  | 2443 | /* no response expected */ | 
|  | 2444 | flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP; | 
|  | 2445 | pSMB->Timeout = 0; | 
|  | 2446 | } else if (waitFlag) { | 
|  | 2447 | flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ | 
|  | 2448 | pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */ | 
|  | 2449 | } else { | 
|  | 2450 | pSMB->Timeout = 0; | 
|  | 2451 | } | 
|  | 2452 |  | 
|  | 2453 | pSMB->NumberOfLocks = cpu_to_le16(numLock); | 
|  | 2454 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); | 
|  | 2455 | pSMB->LockType = lockType; | 
|  | 2456 | pSMB->OplockLevel = oplock_level; | 
|  | 2457 | pSMB->AndXCommand = 0xFF;	/* none */ | 
|  | 2458 | pSMB->Fid = smb_file_id; /* netfid stays le */ | 
|  | 2459 |  | 
|  | 2460 | if ((numLock != 0) || (numUnlock != 0)) { | 
|  | 2461 | pSMB->Locks[0].Pid = cpu_to_le16(netpid); | 
|  | 2462 | /* BB where to store pid high? */ | 
|  | 2463 | pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len); | 
|  | 2464 | pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32)); | 
|  | 2465 | pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset); | 
|  | 2466 | pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32)); | 
|  | 2467 | count = sizeof(LOCKING_ANDX_RANGE); | 
|  | 2468 | } else { | 
|  | 2469 | /* oplock break */ | 
|  | 2470 | count = 0; | 
|  | 2471 | } | 
|  | 2472 | inc_rfc1001_len(pSMB, count); | 
|  | 2473 | pSMB->ByteCount = cpu_to_le16(count); | 
|  | 2474 |  | 
|  | 2475 | if (waitFlag) | 
|  | 2476 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, | 
|  | 2477 | (struct smb_hdr *) pSMB, &bytes_returned); | 
|  | 2478 | else | 
|  | 2479 | rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags); | 
|  | 2480 | cifs_small_buf_release(pSMB); | 
|  | 2481 | cifs_stats_inc(&tcon->stats.cifs_stats.num_locks); | 
|  | 2482 | if (rc) | 
|  | 2483 | cifs_dbg(FYI, "Send error in Lock = %d\n", rc); | 
|  | 2484 |  | 
|  | 2485 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 2486 | since file handle passed in no longer valid */ | 
|  | 2487 | return rc; | 
|  | 2488 | } | 
|  | 2489 |  | 
|  | 2490 | int | 
|  | 2491 | CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 2492 | const __u16 smb_file_id, const __u32 netpid, | 
|  | 2493 | const loff_t start_offset, const __u64 len, | 
|  | 2494 | struct file_lock *pLockData, const __u16 lock_type, | 
|  | 2495 | const bool waitFlag) | 
|  | 2496 | { | 
|  | 2497 | struct smb_com_transaction2_sfi_req *pSMB  = NULL; | 
|  | 2498 | struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; | 
|  | 2499 | struct cifs_posix_lock *parm_data; | 
|  | 2500 | int rc = 0; | 
|  | 2501 | int timeout = 0; | 
|  | 2502 | int bytes_returned = 0; | 
|  | 2503 | int resp_buf_type = 0; | 
|  | 2504 | __u16 params, param_offset, offset, byte_count, count; | 
|  | 2505 | struct kvec iov[1]; | 
|  | 2506 | struct kvec rsp_iov; | 
|  | 2507 |  | 
|  | 2508 | cifs_dbg(FYI, "Posix Lock\n"); | 
|  | 2509 |  | 
|  | 2510 | rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); | 
|  | 2511 |  | 
|  | 2512 | if (rc) | 
|  | 2513 | return rc; | 
|  | 2514 |  | 
|  | 2515 | pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; | 
|  | 2516 |  | 
|  | 2517 | params = 6; | 
|  | 2518 | pSMB->MaxSetupCount = 0; | 
|  | 2519 | pSMB->Reserved = 0; | 
|  | 2520 | pSMB->Flags = 0; | 
|  | 2521 | pSMB->Reserved2 = 0; | 
|  | 2522 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | 
|  | 2523 | offset = param_offset + params; | 
|  | 2524 |  | 
|  | 2525 | count = sizeof(struct cifs_posix_lock); | 
|  | 2526 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 2527 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */ | 
|  | 2528 | pSMB->SetupCount = 1; | 
|  | 2529 | pSMB->Reserved3 = 0; | 
|  | 2530 | if (pLockData) | 
|  | 2531 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); | 
|  | 2532 | else | 
|  | 2533 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | 
|  | 2534 | byte_count = 3 /* pad */  + params + count; | 
|  | 2535 | pSMB->DataCount = cpu_to_le16(count); | 
|  | 2536 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 2537 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 2538 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 2539 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 2540 | parm_data = (struct cifs_posix_lock *) | 
|  | 2541 | (((char *) &pSMB->hdr.Protocol) + offset); | 
|  | 2542 |  | 
|  | 2543 | parm_data->lock_type = cpu_to_le16(lock_type); | 
|  | 2544 | if (waitFlag) { | 
|  | 2545 | timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ | 
|  | 2546 | parm_data->lock_flags = cpu_to_le16(1); | 
|  | 2547 | pSMB->Timeout = cpu_to_le32(-1); | 
|  | 2548 | } else | 
|  | 2549 | pSMB->Timeout = 0; | 
|  | 2550 |  | 
|  | 2551 | parm_data->pid = cpu_to_le32(netpid); | 
|  | 2552 | parm_data->start = cpu_to_le64(start_offset); | 
|  | 2553 | parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */ | 
|  | 2554 |  | 
|  | 2555 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 2556 | pSMB->Fid = smb_file_id; | 
|  | 2557 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK); | 
|  | 2558 | pSMB->Reserved4 = 0; | 
|  | 2559 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 2560 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 2561 | if (waitFlag) { | 
|  | 2562 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, | 
|  | 2563 | (struct smb_hdr *) pSMBr, &bytes_returned); | 
|  | 2564 | } else { | 
|  | 2565 | iov[0].iov_base = (char *)pSMB; | 
|  | 2566 | iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; | 
|  | 2567 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, | 
|  | 2568 | &resp_buf_type, timeout, &rsp_iov); | 
|  | 2569 | pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base; | 
|  | 2570 | } | 
|  | 2571 | cifs_small_buf_release(pSMB); | 
|  | 2572 |  | 
|  | 2573 | if (rc) { | 
|  | 2574 | cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc); | 
|  | 2575 | } else if (pLockData) { | 
|  | 2576 | /* lock structure can be returned on get */ | 
|  | 2577 | __u16 data_offset; | 
|  | 2578 | __u16 data_count; | 
|  | 2579 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 2580 |  | 
|  | 2581 | if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) { | 
|  | 2582 | rc = -EIO;      /* bad smb */ | 
|  | 2583 | goto plk_err_exit; | 
|  | 2584 | } | 
|  | 2585 | data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 2586 | data_count  = le16_to_cpu(pSMBr->t2.DataCount); | 
|  | 2587 | if (data_count < sizeof(struct cifs_posix_lock)) { | 
|  | 2588 | rc = -EIO; | 
|  | 2589 | goto plk_err_exit; | 
|  | 2590 | } | 
|  | 2591 | parm_data = (struct cifs_posix_lock *) | 
|  | 2592 | ((char *)&pSMBr->hdr.Protocol + data_offset); | 
|  | 2593 | if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK)) | 
|  | 2594 | pLockData->fl_type = F_UNLCK; | 
|  | 2595 | else { | 
|  | 2596 | if (parm_data->lock_type == | 
|  | 2597 | cpu_to_le16(CIFS_RDLCK)) | 
|  | 2598 | pLockData->fl_type = F_RDLCK; | 
|  | 2599 | else if (parm_data->lock_type == | 
|  | 2600 | cpu_to_le16(CIFS_WRLCK)) | 
|  | 2601 | pLockData->fl_type = F_WRLCK; | 
|  | 2602 |  | 
|  | 2603 | pLockData->fl_start = le64_to_cpu(parm_data->start); | 
|  | 2604 | pLockData->fl_end = pLockData->fl_start + | 
|  | 2605 | le64_to_cpu(parm_data->length) - 1; | 
|  | 2606 | pLockData->fl_pid = -le32_to_cpu(parm_data->pid); | 
|  | 2607 | } | 
|  | 2608 | } | 
|  | 2609 |  | 
|  | 2610 | plk_err_exit: | 
|  | 2611 | free_rsp_buf(resp_buf_type, rsp_iov.iov_base); | 
|  | 2612 |  | 
|  | 2613 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 2614 | since file handle passed in no longer valid */ | 
|  | 2615 |  | 
|  | 2616 | return rc; | 
|  | 2617 | } | 
|  | 2618 |  | 
|  | 2619 |  | 
|  | 2620 | int | 
|  | 2621 | CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id) | 
|  | 2622 | { | 
|  | 2623 | int rc = 0; | 
|  | 2624 | CLOSE_REQ *pSMB = NULL; | 
|  | 2625 | cifs_dbg(FYI, "In CIFSSMBClose\n"); | 
|  | 2626 |  | 
|  | 2627 | /* do not retry on dead session on close */ | 
|  | 2628 | rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB); | 
|  | 2629 | if (rc == -EAGAIN) | 
|  | 2630 | return 0; | 
|  | 2631 | if (rc) | 
|  | 2632 | return rc; | 
|  | 2633 |  | 
|  | 2634 | pSMB->FileID = (__u16) smb_file_id; | 
|  | 2635 | pSMB->LastWriteTime = 0xFFFFFFFF; | 
|  | 2636 | pSMB->ByteCount = 0; | 
|  | 2637 | rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); | 
|  | 2638 | cifs_small_buf_release(pSMB); | 
|  | 2639 | cifs_stats_inc(&tcon->stats.cifs_stats.num_closes); | 
|  | 2640 | if (rc) { | 
|  | 2641 | if (rc != -EINTR) { | 
|  | 2642 | /* EINTR is expected when user ctl-c to kill app */ | 
|  | 2643 | cifs_dbg(VFS, "Send error in Close = %d\n", rc); | 
|  | 2644 | } | 
|  | 2645 | } | 
|  | 2646 |  | 
|  | 2647 | /* Since session is dead, file will be closed on server already */ | 
|  | 2648 | if (rc == -EAGAIN) | 
|  | 2649 | rc = 0; | 
|  | 2650 |  | 
|  | 2651 | return rc; | 
|  | 2652 | } | 
|  | 2653 |  | 
|  | 2654 | int | 
|  | 2655 | CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id) | 
|  | 2656 | { | 
|  | 2657 | int rc = 0; | 
|  | 2658 | FLUSH_REQ *pSMB = NULL; | 
|  | 2659 | cifs_dbg(FYI, "In CIFSSMBFlush\n"); | 
|  | 2660 |  | 
|  | 2661 | rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB); | 
|  | 2662 | if (rc) | 
|  | 2663 | return rc; | 
|  | 2664 |  | 
|  | 2665 | pSMB->FileID = (__u16) smb_file_id; | 
|  | 2666 | pSMB->ByteCount = 0; | 
|  | 2667 | rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); | 
|  | 2668 | cifs_small_buf_release(pSMB); | 
|  | 2669 | cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes); | 
|  | 2670 | if (rc) | 
|  | 2671 | cifs_dbg(VFS, "Send error in Flush = %d\n", rc); | 
|  | 2672 |  | 
|  | 2673 | return rc; | 
|  | 2674 | } | 
|  | 2675 |  | 
|  | 2676 | int | 
|  | 2677 | CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 2678 | const char *from_name, const char *to_name, | 
|  | 2679 | struct cifs_sb_info *cifs_sb) | 
|  | 2680 | { | 
|  | 2681 | int rc = 0; | 
|  | 2682 | RENAME_REQ *pSMB = NULL; | 
|  | 2683 | RENAME_RSP *pSMBr = NULL; | 
|  | 2684 | int bytes_returned; | 
|  | 2685 | int name_len, name_len2; | 
|  | 2686 | __u16 count; | 
|  | 2687 | int remap = cifs_remap(cifs_sb); | 
|  | 2688 |  | 
|  | 2689 | cifs_dbg(FYI, "In CIFSSMBRename\n"); | 
|  | 2690 | renameRetry: | 
|  | 2691 | rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB, | 
|  | 2692 | (void **) &pSMBr); | 
|  | 2693 | if (rc) | 
|  | 2694 | return rc; | 
|  | 2695 |  | 
|  | 2696 | pSMB->BufferFormat = 0x04; | 
|  | 2697 | pSMB->SearchAttributes = | 
|  | 2698 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | | 
|  | 2699 | ATTR_DIRECTORY); | 
|  | 2700 |  | 
|  | 2701 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 2702 | name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName, | 
|  | 2703 | from_name, PATH_MAX, | 
|  | 2704 | cifs_sb->local_nls, remap); | 
|  | 2705 | name_len++;	/* trailing null */ | 
|  | 2706 | name_len *= 2; | 
|  | 2707 | pSMB->OldFileName[name_len] = 0x04;	/* pad */ | 
|  | 2708 | /* protocol requires ASCII signature byte on Unicode string */ | 
|  | 2709 | pSMB->OldFileName[name_len + 1] = 0x00; | 
|  | 2710 | name_len2 = | 
|  | 2711 | cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], | 
|  | 2712 | to_name, PATH_MAX, cifs_sb->local_nls, | 
|  | 2713 | remap); | 
|  | 2714 | name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ; | 
|  | 2715 | name_len2 *= 2;	/* convert to bytes */ | 
|  | 2716 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 2717 | name_len = strnlen(from_name, PATH_MAX); | 
|  | 2718 | name_len++;	/* trailing null */ | 
|  | 2719 | strncpy(pSMB->OldFileName, from_name, name_len); | 
|  | 2720 | name_len2 = strnlen(to_name, PATH_MAX); | 
|  | 2721 | name_len2++;	/* trailing null */ | 
|  | 2722 | pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */ | 
|  | 2723 | strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2); | 
|  | 2724 | name_len2++;	/* trailing null */ | 
|  | 2725 | name_len2++;	/* signature byte */ | 
|  | 2726 | } | 
|  | 2727 |  | 
|  | 2728 | count = 1 /* 1st signature byte */  + name_len + name_len2; | 
|  | 2729 | inc_rfc1001_len(pSMB, count); | 
|  | 2730 | pSMB->ByteCount = cpu_to_le16(count); | 
|  | 2731 |  | 
|  | 2732 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 2733 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 2734 | cifs_stats_inc(&tcon->stats.cifs_stats.num_renames); | 
|  | 2735 | if (rc) | 
|  | 2736 | cifs_dbg(FYI, "Send error in rename = %d\n", rc); | 
|  | 2737 |  | 
|  | 2738 | cifs_buf_release(pSMB); | 
|  | 2739 |  | 
|  | 2740 | if (rc == -EAGAIN) | 
|  | 2741 | goto renameRetry; | 
|  | 2742 |  | 
|  | 2743 | return rc; | 
|  | 2744 | } | 
|  | 2745 |  | 
|  | 2746 | int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, | 
|  | 2747 | int netfid, const char *target_name, | 
|  | 2748 | const struct nls_table *nls_codepage, int remap) | 
|  | 2749 | { | 
|  | 2750 | struct smb_com_transaction2_sfi_req *pSMB  = NULL; | 
|  | 2751 | struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; | 
|  | 2752 | struct set_file_rename *rename_info; | 
|  | 2753 | char *data_offset; | 
|  | 2754 | char dummy_string[30]; | 
|  | 2755 | int rc = 0; | 
|  | 2756 | int bytes_returned = 0; | 
|  | 2757 | int len_of_str; | 
|  | 2758 | __u16 params, param_offset, offset, count, byte_count; | 
|  | 2759 |  | 
|  | 2760 | cifs_dbg(FYI, "Rename to File by handle\n"); | 
|  | 2761 | rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, | 
|  | 2762 | (void **) &pSMBr); | 
|  | 2763 | if (rc) | 
|  | 2764 | return rc; | 
|  | 2765 |  | 
|  | 2766 | params = 6; | 
|  | 2767 | pSMB->MaxSetupCount = 0; | 
|  | 2768 | pSMB->Reserved = 0; | 
|  | 2769 | pSMB->Flags = 0; | 
|  | 2770 | pSMB->Timeout = 0; | 
|  | 2771 | pSMB->Reserved2 = 0; | 
|  | 2772 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | 
|  | 2773 | offset = param_offset + params; | 
|  | 2774 |  | 
|  | 2775 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | 
|  | 2776 | rename_info = (struct set_file_rename *) data_offset; | 
|  | 2777 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 2778 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */ | 
|  | 2779 | pSMB->SetupCount = 1; | 
|  | 2780 | pSMB->Reserved3 = 0; | 
|  | 2781 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | 
|  | 2782 | byte_count = 3 /* pad */  + params; | 
|  | 2783 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 2784 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 2785 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 2786 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 2787 | /* construct random name ".cifs_tmp<inodenum><mid>" */ | 
|  | 2788 | rename_info->overwrite = cpu_to_le32(1); | 
|  | 2789 | rename_info->root_fid  = 0; | 
|  | 2790 | /* unicode only call */ | 
|  | 2791 | if (target_name == NULL) { | 
|  | 2792 | sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid); | 
|  | 2793 | len_of_str = | 
|  | 2794 | cifsConvertToUTF16((__le16 *)rename_info->target_name, | 
|  | 2795 | dummy_string, 24, nls_codepage, remap); | 
|  | 2796 | } else { | 
|  | 2797 | len_of_str = | 
|  | 2798 | cifsConvertToUTF16((__le16 *)rename_info->target_name, | 
|  | 2799 | target_name, PATH_MAX, nls_codepage, | 
|  | 2800 | remap); | 
|  | 2801 | } | 
|  | 2802 | rename_info->target_name_len = cpu_to_le32(2 * len_of_str); | 
|  | 2803 | count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str); | 
|  | 2804 | byte_count += count; | 
|  | 2805 | pSMB->DataCount = cpu_to_le16(count); | 
|  | 2806 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 2807 | pSMB->Fid = netfid; | 
|  | 2808 | pSMB->InformationLevel = | 
|  | 2809 | cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); | 
|  | 2810 | pSMB->Reserved4 = 0; | 
|  | 2811 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 2812 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 2813 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, | 
|  | 2814 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 2815 | cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames); | 
|  | 2816 | if (rc) | 
|  | 2817 | cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n", | 
|  | 2818 | rc); | 
|  | 2819 |  | 
|  | 2820 | cifs_buf_release(pSMB); | 
|  | 2821 |  | 
|  | 2822 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 2823 | since file handle passed in no longer valid */ | 
|  | 2824 |  | 
|  | 2825 | return rc; | 
|  | 2826 | } | 
|  | 2827 |  | 
|  | 2828 | int | 
|  | 2829 | CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 2830 | const char *fromName, const __u16 target_tid, const char *toName, | 
|  | 2831 | const int flags, const struct nls_table *nls_codepage, int remap) | 
|  | 2832 | { | 
|  | 2833 | int rc = 0; | 
|  | 2834 | COPY_REQ *pSMB = NULL; | 
|  | 2835 | COPY_RSP *pSMBr = NULL; | 
|  | 2836 | int bytes_returned; | 
|  | 2837 | int name_len, name_len2; | 
|  | 2838 | __u16 count; | 
|  | 2839 |  | 
|  | 2840 | cifs_dbg(FYI, "In CIFSSMBCopy\n"); | 
|  | 2841 | copyRetry: | 
|  | 2842 | rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB, | 
|  | 2843 | (void **) &pSMBr); | 
|  | 2844 | if (rc) | 
|  | 2845 | return rc; | 
|  | 2846 |  | 
|  | 2847 | pSMB->BufferFormat = 0x04; | 
|  | 2848 | pSMB->Tid2 = target_tid; | 
|  | 2849 |  | 
|  | 2850 | pSMB->Flags = cpu_to_le16(flags & COPY_TREE); | 
|  | 2851 |  | 
|  | 2852 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 2853 | name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName, | 
|  | 2854 | fromName, PATH_MAX, nls_codepage, | 
|  | 2855 | remap); | 
|  | 2856 | name_len++;     /* trailing null */ | 
|  | 2857 | name_len *= 2; | 
|  | 2858 | pSMB->OldFileName[name_len] = 0x04;     /* pad */ | 
|  | 2859 | /* protocol requires ASCII signature byte on Unicode string */ | 
|  | 2860 | pSMB->OldFileName[name_len + 1] = 0x00; | 
|  | 2861 | name_len2 = | 
|  | 2862 | cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], | 
|  | 2863 | toName, PATH_MAX, nls_codepage, remap); | 
|  | 2864 | name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ; | 
|  | 2865 | name_len2 *= 2; /* convert to bytes */ | 
|  | 2866 | } else { 	/* BB improve the check for buffer overruns BB */ | 
|  | 2867 | name_len = strnlen(fromName, PATH_MAX); | 
|  | 2868 | name_len++;     /* trailing null */ | 
|  | 2869 | strncpy(pSMB->OldFileName, fromName, name_len); | 
|  | 2870 | name_len2 = strnlen(toName, PATH_MAX); | 
|  | 2871 | name_len2++;    /* trailing null */ | 
|  | 2872 | pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */ | 
|  | 2873 | strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); | 
|  | 2874 | name_len2++;    /* trailing null */ | 
|  | 2875 | name_len2++;    /* signature byte */ | 
|  | 2876 | } | 
|  | 2877 |  | 
|  | 2878 | count = 1 /* 1st signature byte */  + name_len + name_len2; | 
|  | 2879 | inc_rfc1001_len(pSMB, count); | 
|  | 2880 | pSMB->ByteCount = cpu_to_le16(count); | 
|  | 2881 |  | 
|  | 2882 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 2883 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 2884 | if (rc) { | 
|  | 2885 | cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n", | 
|  | 2886 | rc, le16_to_cpu(pSMBr->CopyCount)); | 
|  | 2887 | } | 
|  | 2888 | cifs_buf_release(pSMB); | 
|  | 2889 |  | 
|  | 2890 | if (rc == -EAGAIN) | 
|  | 2891 | goto copyRetry; | 
|  | 2892 |  | 
|  | 2893 | return rc; | 
|  | 2894 | } | 
|  | 2895 |  | 
|  | 2896 | int | 
|  | 2897 | CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 2898 | const char *fromName, const char *toName, | 
|  | 2899 | const struct nls_table *nls_codepage, int remap) | 
|  | 2900 | { | 
|  | 2901 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 
|  | 2902 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 
|  | 2903 | char *data_offset; | 
|  | 2904 | int name_len; | 
|  | 2905 | int name_len_target; | 
|  | 2906 | int rc = 0; | 
|  | 2907 | int bytes_returned = 0; | 
|  | 2908 | __u16 params, param_offset, offset, byte_count; | 
|  | 2909 |  | 
|  | 2910 | cifs_dbg(FYI, "In Symlink Unix style\n"); | 
|  | 2911 | createSymLinkRetry: | 
|  | 2912 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 2913 | (void **) &pSMBr); | 
|  | 2914 | if (rc) | 
|  | 2915 | return rc; | 
|  | 2916 |  | 
|  | 2917 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 2918 | name_len = | 
|  | 2919 | cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName, | 
|  | 2920 | /* find define for this maxpathcomponent */ | 
|  | 2921 | PATH_MAX, nls_codepage, remap); | 
|  | 2922 | name_len++;	/* trailing null */ | 
|  | 2923 | name_len *= 2; | 
|  | 2924 |  | 
|  | 2925 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 2926 | name_len = strnlen(fromName, PATH_MAX); | 
|  | 2927 | name_len++;	/* trailing null */ | 
|  | 2928 | strncpy(pSMB->FileName, fromName, name_len); | 
|  | 2929 | } | 
|  | 2930 | params = 6 + name_len; | 
|  | 2931 | pSMB->MaxSetupCount = 0; | 
|  | 2932 | pSMB->Reserved = 0; | 
|  | 2933 | pSMB->Flags = 0; | 
|  | 2934 | pSMB->Timeout = 0; | 
|  | 2935 | pSMB->Reserved2 = 0; | 
|  | 2936 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | 
|  | 2937 | InformationLevel) - 4; | 
|  | 2938 | offset = param_offset + params; | 
|  | 2939 |  | 
|  | 2940 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | 
|  | 2941 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 2942 | name_len_target = | 
|  | 2943 | cifsConvertToUTF16((__le16 *) data_offset, toName, | 
|  | 2944 | /* find define for this maxpathcomponent */ | 
|  | 2945 | PATH_MAX, nls_codepage, remap); | 
|  | 2946 | name_len_target++;	/* trailing null */ | 
|  | 2947 | name_len_target *= 2; | 
|  | 2948 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 2949 | name_len_target = strnlen(toName, PATH_MAX); | 
|  | 2950 | name_len_target++;	/* trailing null */ | 
|  | 2951 | strncpy(data_offset, toName, name_len_target); | 
|  | 2952 | } | 
|  | 2953 |  | 
|  | 2954 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 2955 | /* BB find exact max on data count below from sess */ | 
|  | 2956 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 2957 | pSMB->SetupCount = 1; | 
|  | 2958 | pSMB->Reserved3 = 0; | 
|  | 2959 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | 
|  | 2960 | byte_count = 3 /* pad */  + params + name_len_target; | 
|  | 2961 | pSMB->DataCount = cpu_to_le16(name_len_target); | 
|  | 2962 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 2963 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 2964 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 2965 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 2966 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 2967 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); | 
|  | 2968 | pSMB->Reserved4 = 0; | 
|  | 2969 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 2970 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 2971 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 2972 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 2973 | cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks); | 
|  | 2974 | if (rc) | 
|  | 2975 | cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n", | 
|  | 2976 | rc); | 
|  | 2977 |  | 
|  | 2978 | cifs_buf_release(pSMB); | 
|  | 2979 |  | 
|  | 2980 | if (rc == -EAGAIN) | 
|  | 2981 | goto createSymLinkRetry; | 
|  | 2982 |  | 
|  | 2983 | return rc; | 
|  | 2984 | } | 
|  | 2985 |  | 
|  | 2986 | int | 
|  | 2987 | CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 2988 | const char *fromName, const char *toName, | 
|  | 2989 | const struct nls_table *nls_codepage, int remap) | 
|  | 2990 | { | 
|  | 2991 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 
|  | 2992 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 
|  | 2993 | char *data_offset; | 
|  | 2994 | int name_len; | 
|  | 2995 | int name_len_target; | 
|  | 2996 | int rc = 0; | 
|  | 2997 | int bytes_returned = 0; | 
|  | 2998 | __u16 params, param_offset, offset, byte_count; | 
|  | 2999 |  | 
|  | 3000 | cifs_dbg(FYI, "In Create Hard link Unix style\n"); | 
|  | 3001 | createHardLinkRetry: | 
|  | 3002 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 3003 | (void **) &pSMBr); | 
|  | 3004 | if (rc) | 
|  | 3005 | return rc; | 
|  | 3006 |  | 
|  | 3007 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 3008 | name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName, | 
|  | 3009 | PATH_MAX, nls_codepage, remap); | 
|  | 3010 | name_len++;	/* trailing null */ | 
|  | 3011 | name_len *= 2; | 
|  | 3012 |  | 
|  | 3013 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 3014 | name_len = strnlen(toName, PATH_MAX); | 
|  | 3015 | name_len++;	/* trailing null */ | 
|  | 3016 | strncpy(pSMB->FileName, toName, name_len); | 
|  | 3017 | } | 
|  | 3018 | params = 6 + name_len; | 
|  | 3019 | pSMB->MaxSetupCount = 0; | 
|  | 3020 | pSMB->Reserved = 0; | 
|  | 3021 | pSMB->Flags = 0; | 
|  | 3022 | pSMB->Timeout = 0; | 
|  | 3023 | pSMB->Reserved2 = 0; | 
|  | 3024 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | 
|  | 3025 | InformationLevel) - 4; | 
|  | 3026 | offset = param_offset + params; | 
|  | 3027 |  | 
|  | 3028 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | 
|  | 3029 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 3030 | name_len_target = | 
|  | 3031 | cifsConvertToUTF16((__le16 *) data_offset, fromName, | 
|  | 3032 | PATH_MAX, nls_codepage, remap); | 
|  | 3033 | name_len_target++;	/* trailing null */ | 
|  | 3034 | name_len_target *= 2; | 
|  | 3035 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 3036 | name_len_target = strnlen(fromName, PATH_MAX); | 
|  | 3037 | name_len_target++;	/* trailing null */ | 
|  | 3038 | strncpy(data_offset, fromName, name_len_target); | 
|  | 3039 | } | 
|  | 3040 |  | 
|  | 3041 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 3042 | /* BB find exact max on data count below from sess*/ | 
|  | 3043 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 3044 | pSMB->SetupCount = 1; | 
|  | 3045 | pSMB->Reserved3 = 0; | 
|  | 3046 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | 
|  | 3047 | byte_count = 3 /* pad */  + params + name_len_target; | 
|  | 3048 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 3049 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 3050 | pSMB->DataCount = cpu_to_le16(name_len_target); | 
|  | 3051 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 3052 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 3053 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 3054 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); | 
|  | 3055 | pSMB->Reserved4 = 0; | 
|  | 3056 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 3057 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 3058 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 3059 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 3060 | cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks); | 
|  | 3061 | if (rc) | 
|  | 3062 | cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n", | 
|  | 3063 | rc); | 
|  | 3064 |  | 
|  | 3065 | cifs_buf_release(pSMB); | 
|  | 3066 | if (rc == -EAGAIN) | 
|  | 3067 | goto createHardLinkRetry; | 
|  | 3068 |  | 
|  | 3069 | return rc; | 
|  | 3070 | } | 
|  | 3071 |  | 
|  | 3072 | int | 
|  | 3073 | CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 3074 | const char *from_name, const char *to_name, | 
|  | 3075 | struct cifs_sb_info *cifs_sb) | 
|  | 3076 | { | 
|  | 3077 | int rc = 0; | 
|  | 3078 | NT_RENAME_REQ *pSMB = NULL; | 
|  | 3079 | RENAME_RSP *pSMBr = NULL; | 
|  | 3080 | int bytes_returned; | 
|  | 3081 | int name_len, name_len2; | 
|  | 3082 | __u16 count; | 
|  | 3083 | int remap = cifs_remap(cifs_sb); | 
|  | 3084 |  | 
|  | 3085 | cifs_dbg(FYI, "In CIFSCreateHardLink\n"); | 
|  | 3086 | winCreateHardLinkRetry: | 
|  | 3087 |  | 
|  | 3088 | rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB, | 
|  | 3089 | (void **) &pSMBr); | 
|  | 3090 | if (rc) | 
|  | 3091 | return rc; | 
|  | 3092 |  | 
|  | 3093 | pSMB->SearchAttributes = | 
|  | 3094 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | | 
|  | 3095 | ATTR_DIRECTORY); | 
|  | 3096 | pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK); | 
|  | 3097 | pSMB->ClusterCount = 0; | 
|  | 3098 |  | 
|  | 3099 | pSMB->BufferFormat = 0x04; | 
|  | 3100 |  | 
|  | 3101 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 3102 | name_len = | 
|  | 3103 | cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name, | 
|  | 3104 | PATH_MAX, cifs_sb->local_nls, remap); | 
|  | 3105 | name_len++;	/* trailing null */ | 
|  | 3106 | name_len *= 2; | 
|  | 3107 |  | 
|  | 3108 | /* protocol specifies ASCII buffer format (0x04) for unicode */ | 
|  | 3109 | pSMB->OldFileName[name_len] = 0x04; | 
|  | 3110 | pSMB->OldFileName[name_len + 1] = 0x00; /* pad */ | 
|  | 3111 | name_len2 = | 
|  | 3112 | cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], | 
|  | 3113 | to_name, PATH_MAX, cifs_sb->local_nls, | 
|  | 3114 | remap); | 
|  | 3115 | name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ; | 
|  | 3116 | name_len2 *= 2;	/* convert to bytes */ | 
|  | 3117 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 3118 | name_len = strnlen(from_name, PATH_MAX); | 
|  | 3119 | name_len++;	/* trailing null */ | 
|  | 3120 | strncpy(pSMB->OldFileName, from_name, name_len); | 
|  | 3121 | name_len2 = strnlen(to_name, PATH_MAX); | 
|  | 3122 | name_len2++;	/* trailing null */ | 
|  | 3123 | pSMB->OldFileName[name_len] = 0x04;	/* 2nd buffer format */ | 
|  | 3124 | strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2); | 
|  | 3125 | name_len2++;	/* trailing null */ | 
|  | 3126 | name_len2++;	/* signature byte */ | 
|  | 3127 | } | 
|  | 3128 |  | 
|  | 3129 | count = 1 /* string type byte */  + name_len + name_len2; | 
|  | 3130 | inc_rfc1001_len(pSMB, count); | 
|  | 3131 | pSMB->ByteCount = cpu_to_le16(count); | 
|  | 3132 |  | 
|  | 3133 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 3134 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 3135 | cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks); | 
|  | 3136 | if (rc) | 
|  | 3137 | cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc); | 
|  | 3138 |  | 
|  | 3139 | cifs_buf_release(pSMB); | 
|  | 3140 | if (rc == -EAGAIN) | 
|  | 3141 | goto winCreateHardLinkRetry; | 
|  | 3142 |  | 
|  | 3143 | return rc; | 
|  | 3144 | } | 
|  | 3145 |  | 
|  | 3146 | int | 
|  | 3147 | CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 3148 | const unsigned char *searchName, char **symlinkinfo, | 
|  | 3149 | const struct nls_table *nls_codepage, int remap) | 
|  | 3150 | { | 
|  | 3151 | /* SMB_QUERY_FILE_UNIX_LINK */ | 
|  | 3152 | TRANSACTION2_QPI_REQ *pSMB = NULL; | 
|  | 3153 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | 
|  | 3154 | int rc = 0; | 
|  | 3155 | int bytes_returned; | 
|  | 3156 | int name_len; | 
|  | 3157 | __u16 params, byte_count; | 
|  | 3158 | char *data_start; | 
|  | 3159 |  | 
|  | 3160 | cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName); | 
|  | 3161 |  | 
|  | 3162 | querySymLinkRetry: | 
|  | 3163 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 3164 | (void **) &pSMBr); | 
|  | 3165 | if (rc) | 
|  | 3166 | return rc; | 
|  | 3167 |  | 
|  | 3168 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 3169 | name_len = | 
|  | 3170 | cifsConvertToUTF16((__le16 *) pSMB->FileName, | 
|  | 3171 | searchName, PATH_MAX, nls_codepage, | 
|  | 3172 | remap); | 
|  | 3173 | name_len++;	/* trailing null */ | 
|  | 3174 | name_len *= 2; | 
|  | 3175 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 3176 | name_len = strnlen(searchName, PATH_MAX); | 
|  | 3177 | name_len++;	/* trailing null */ | 
|  | 3178 | strncpy(pSMB->FileName, searchName, name_len); | 
|  | 3179 | } | 
|  | 3180 |  | 
|  | 3181 | params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ; | 
|  | 3182 | pSMB->TotalDataCount = 0; | 
|  | 3183 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 3184 | pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize); | 
|  | 3185 | pSMB->MaxSetupCount = 0; | 
|  | 3186 | pSMB->Reserved = 0; | 
|  | 3187 | pSMB->Flags = 0; | 
|  | 3188 | pSMB->Timeout = 0; | 
|  | 3189 | pSMB->Reserved2 = 0; | 
|  | 3190 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | 
|  | 3191 | struct smb_com_transaction2_qpi_req, InformationLevel) - 4); | 
|  | 3192 | pSMB->DataCount = 0; | 
|  | 3193 | pSMB->DataOffset = 0; | 
|  | 3194 | pSMB->SetupCount = 1; | 
|  | 3195 | pSMB->Reserved3 = 0; | 
|  | 3196 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | 
|  | 3197 | byte_count = params + 1 /* pad */ ; | 
|  | 3198 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 3199 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 3200 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); | 
|  | 3201 | pSMB->Reserved4 = 0; | 
|  | 3202 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 3203 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 3204 |  | 
|  | 3205 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 3206 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 3207 | if (rc) { | 
|  | 3208 | cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc); | 
|  | 3209 | } else { | 
|  | 3210 | /* decode response */ | 
|  | 3211 |  | 
|  | 3212 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 3213 | /* BB also check enough total bytes returned */ | 
|  | 3214 | if (rc || get_bcc(&pSMBr->hdr) < 2) | 
|  | 3215 | rc = -EIO; | 
|  | 3216 | else { | 
|  | 3217 | bool is_unicode; | 
|  | 3218 | u16 count = le16_to_cpu(pSMBr->t2.DataCount); | 
|  | 3219 |  | 
|  | 3220 | data_start = ((char *) &pSMBr->hdr.Protocol) + | 
|  | 3221 | le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 3222 |  | 
|  | 3223 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) | 
|  | 3224 | is_unicode = true; | 
|  | 3225 | else | 
|  | 3226 | is_unicode = false; | 
|  | 3227 |  | 
|  | 3228 | /* BB FIXME investigate remapping reserved chars here */ | 
|  | 3229 | *symlinkinfo = cifs_strndup_from_utf16(data_start, | 
|  | 3230 | count, is_unicode, nls_codepage); | 
|  | 3231 | if (!*symlinkinfo) | 
|  | 3232 | rc = -ENOMEM; | 
|  | 3233 | } | 
|  | 3234 | } | 
|  | 3235 | cifs_buf_release(pSMB); | 
|  | 3236 | if (rc == -EAGAIN) | 
|  | 3237 | goto querySymLinkRetry; | 
|  | 3238 | return rc; | 
|  | 3239 | } | 
|  | 3240 |  | 
|  | 3241 | /* | 
|  | 3242 | *	Recent Windows versions now create symlinks more frequently | 
|  | 3243 | *	and they use the "reparse point" mechanism below.  We can of course | 
|  | 3244 | *	do symlinks nicely to Samba and other servers which support the | 
|  | 3245 | *	CIFS Unix Extensions and we can also do SFU symlinks and "client only" | 
|  | 3246 | *	"MF" symlinks optionally, but for recent Windows we really need to | 
|  | 3247 | *	reenable the code below and fix the cifs_symlink callers to handle this. | 
|  | 3248 | *	In the interim this code has been moved to its own config option so | 
|  | 3249 | *	it is not compiled in by default until callers fixed up and more tested. | 
|  | 3250 | */ | 
|  | 3251 | int | 
|  | 3252 | CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 3253 | __u16 fid, char **symlinkinfo, | 
|  | 3254 | const struct nls_table *nls_codepage) | 
|  | 3255 | { | 
|  | 3256 | int rc = 0; | 
|  | 3257 | int bytes_returned; | 
|  | 3258 | struct smb_com_transaction_ioctl_req *pSMB; | 
|  | 3259 | struct smb_com_transaction_ioctl_rsp *pSMBr; | 
|  | 3260 | bool is_unicode; | 
|  | 3261 | unsigned int sub_len; | 
|  | 3262 | char *sub_start; | 
|  | 3263 | struct reparse_symlink_data *reparse_buf; | 
|  | 3264 | struct reparse_posix_data *posix_buf; | 
|  | 3265 | __u32 data_offset, data_count; | 
|  | 3266 | char *end_of_smb; | 
|  | 3267 |  | 
|  | 3268 | cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid); | 
|  | 3269 | rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, | 
|  | 3270 | (void **) &pSMBr); | 
|  | 3271 | if (rc) | 
|  | 3272 | return rc; | 
|  | 3273 |  | 
|  | 3274 | pSMB->TotalParameterCount = 0 ; | 
|  | 3275 | pSMB->TotalDataCount = 0; | 
|  | 3276 | pSMB->MaxParameterCount = cpu_to_le32(2); | 
|  | 3277 | /* BB find exact data count max from sess structure BB */ | 
|  | 3278 | pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); | 
|  | 3279 | pSMB->MaxSetupCount = 4; | 
|  | 3280 | pSMB->Reserved = 0; | 
|  | 3281 | pSMB->ParameterOffset = 0; | 
|  | 3282 | pSMB->DataCount = 0; | 
|  | 3283 | pSMB->DataOffset = 0; | 
|  | 3284 | pSMB->SetupCount = 4; | 
|  | 3285 | pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); | 
|  | 3286 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 3287 | pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT); | 
|  | 3288 | pSMB->IsFsctl = 1; /* FSCTL */ | 
|  | 3289 | pSMB->IsRootFlag = 0; | 
|  | 3290 | pSMB->Fid = fid; /* file handle always le */ | 
|  | 3291 | pSMB->ByteCount = 0; | 
|  | 3292 |  | 
|  | 3293 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 3294 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 3295 | if (rc) { | 
|  | 3296 | cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); | 
|  | 3297 | goto qreparse_out; | 
|  | 3298 | } | 
|  | 3299 |  | 
|  | 3300 | data_offset = le32_to_cpu(pSMBr->DataOffset); | 
|  | 3301 | data_count = le32_to_cpu(pSMBr->DataCount); | 
|  | 3302 | if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { | 
|  | 3303 | /* BB also check enough total bytes returned */ | 
|  | 3304 | rc = -EIO;	/* bad smb */ | 
|  | 3305 | goto qreparse_out; | 
|  | 3306 | } | 
|  | 3307 | if (!data_count || (data_count > 2048)) { | 
|  | 3308 | rc = -EIO; | 
|  | 3309 | cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); | 
|  | 3310 | goto qreparse_out; | 
|  | 3311 | } | 
|  | 3312 | end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; | 
|  | 3313 | reparse_buf = (struct reparse_symlink_data *) | 
|  | 3314 | ((char *)&pSMBr->hdr.Protocol + data_offset); | 
|  | 3315 | if ((char *)reparse_buf >= end_of_smb) { | 
|  | 3316 | rc = -EIO; | 
|  | 3317 | goto qreparse_out; | 
|  | 3318 | } | 
|  | 3319 | if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) { | 
|  | 3320 | cifs_dbg(FYI, "NFS style reparse tag\n"); | 
|  | 3321 | posix_buf =  (struct reparse_posix_data *)reparse_buf; | 
|  | 3322 |  | 
|  | 3323 | if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) { | 
|  | 3324 | cifs_dbg(FYI, "unsupported file type 0x%llx\n", | 
|  | 3325 | le64_to_cpu(posix_buf->InodeType)); | 
|  | 3326 | rc = -EOPNOTSUPP; | 
|  | 3327 | goto qreparse_out; | 
|  | 3328 | } | 
|  | 3329 | is_unicode = true; | 
|  | 3330 | sub_len = le16_to_cpu(reparse_buf->ReparseDataLength); | 
|  | 3331 | if (posix_buf->PathBuffer + sub_len > end_of_smb) { | 
|  | 3332 | cifs_dbg(FYI, "reparse buf beyond SMB\n"); | 
|  | 3333 | rc = -EIO; | 
|  | 3334 | goto qreparse_out; | 
|  | 3335 | } | 
|  | 3336 | *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer, | 
|  | 3337 | sub_len, is_unicode, nls_codepage); | 
|  | 3338 | goto qreparse_out; | 
|  | 3339 | } else if (reparse_buf->ReparseTag != | 
|  | 3340 | cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) { | 
|  | 3341 | rc = -EOPNOTSUPP; | 
|  | 3342 | goto qreparse_out; | 
|  | 3343 | } | 
|  | 3344 |  | 
|  | 3345 | /* Reparse tag is NTFS symlink */ | 
|  | 3346 | sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) + | 
|  | 3347 | reparse_buf->PathBuffer; | 
|  | 3348 | sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength); | 
|  | 3349 | if (sub_start + sub_len > end_of_smb) { | 
|  | 3350 | cifs_dbg(FYI, "reparse buf beyond SMB\n"); | 
|  | 3351 | rc = -EIO; | 
|  | 3352 | goto qreparse_out; | 
|  | 3353 | } | 
|  | 3354 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) | 
|  | 3355 | is_unicode = true; | 
|  | 3356 | else | 
|  | 3357 | is_unicode = false; | 
|  | 3358 |  | 
|  | 3359 | /* BB FIXME investigate remapping reserved chars here */ | 
|  | 3360 | *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode, | 
|  | 3361 | nls_codepage); | 
|  | 3362 | if (!*symlinkinfo) | 
|  | 3363 | rc = -ENOMEM; | 
|  | 3364 | qreparse_out: | 
|  | 3365 | cifs_buf_release(pSMB); | 
|  | 3366 |  | 
|  | 3367 | /* | 
|  | 3368 | * Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 3369 | * since file handle passed in no longer valid. | 
|  | 3370 | */ | 
|  | 3371 | return rc; | 
|  | 3372 | } | 
|  | 3373 |  | 
|  | 3374 | int | 
|  | 3375 | CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 3376 | __u16 fid) | 
|  | 3377 | { | 
|  | 3378 | int rc = 0; | 
|  | 3379 | int bytes_returned; | 
|  | 3380 | struct smb_com_transaction_compr_ioctl_req *pSMB; | 
|  | 3381 | struct smb_com_transaction_ioctl_rsp *pSMBr; | 
|  | 3382 |  | 
|  | 3383 | cifs_dbg(FYI, "Set compression for %u\n", fid); | 
|  | 3384 | rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, | 
|  | 3385 | (void **) &pSMBr); | 
|  | 3386 | if (rc) | 
|  | 3387 | return rc; | 
|  | 3388 |  | 
|  | 3389 | pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT); | 
|  | 3390 |  | 
|  | 3391 | pSMB->TotalParameterCount = 0; | 
|  | 3392 | pSMB->TotalDataCount = cpu_to_le32(2); | 
|  | 3393 | pSMB->MaxParameterCount = 0; | 
|  | 3394 | pSMB->MaxDataCount = 0; | 
|  | 3395 | pSMB->MaxSetupCount = 4; | 
|  | 3396 | pSMB->Reserved = 0; | 
|  | 3397 | pSMB->ParameterOffset = 0; | 
|  | 3398 | pSMB->DataCount = cpu_to_le32(2); | 
|  | 3399 | pSMB->DataOffset = | 
|  | 3400 | cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req, | 
|  | 3401 | compression_state) - 4);  /* 84 */ | 
|  | 3402 | pSMB->SetupCount = 4; | 
|  | 3403 | pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); | 
|  | 3404 | pSMB->ParameterCount = 0; | 
|  | 3405 | pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION); | 
|  | 3406 | pSMB->IsFsctl = 1; /* FSCTL */ | 
|  | 3407 | pSMB->IsRootFlag = 0; | 
|  | 3408 | pSMB->Fid = fid; /* file handle always le */ | 
|  | 3409 | /* 3 byte pad, followed by 2 byte compress state */ | 
|  | 3410 | pSMB->ByteCount = cpu_to_le16(5); | 
|  | 3411 | inc_rfc1001_len(pSMB, 5); | 
|  | 3412 |  | 
|  | 3413 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 3414 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 3415 | if (rc) | 
|  | 3416 | cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc); | 
|  | 3417 |  | 
|  | 3418 | cifs_buf_release(pSMB); | 
|  | 3419 |  | 
|  | 3420 | /* | 
|  | 3421 | * Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 3422 | * since file handle passed in no longer valid. | 
|  | 3423 | */ | 
|  | 3424 | return rc; | 
|  | 3425 | } | 
|  | 3426 |  | 
|  | 3427 |  | 
|  | 3428 | #ifdef CONFIG_CIFS_POSIX | 
|  | 3429 |  | 
|  | 3430 | /*Convert an Access Control Entry from wire format to local POSIX xattr format*/ | 
|  | 3431 | static void cifs_convert_ace(struct posix_acl_xattr_entry *ace, | 
|  | 3432 | struct cifs_posix_ace *cifs_ace) | 
|  | 3433 | { | 
|  | 3434 | /* u8 cifs fields do not need le conversion */ | 
|  | 3435 | ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm); | 
|  | 3436 | ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag); | 
|  | 3437 | ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid)); | 
|  | 3438 | /* | 
|  | 3439 | cifs_dbg(FYI, "perm %d tag %d id %d\n", | 
|  | 3440 | ace->e_perm, ace->e_tag, ace->e_id); | 
|  | 3441 | */ | 
|  | 3442 |  | 
|  | 3443 | return; | 
|  | 3444 | } | 
|  | 3445 |  | 
|  | 3446 | /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */ | 
|  | 3447 | static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen, | 
|  | 3448 | const int acl_type, const int size_of_data_area) | 
|  | 3449 | { | 
|  | 3450 | int size =  0; | 
|  | 3451 | int i; | 
|  | 3452 | __u16 count; | 
|  | 3453 | struct cifs_posix_ace *pACE; | 
|  | 3454 | struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src; | 
|  | 3455 | struct posix_acl_xattr_header *local_acl = (void *)trgt; | 
|  | 3456 |  | 
|  | 3457 | if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION) | 
|  | 3458 | return -EOPNOTSUPP; | 
|  | 3459 |  | 
|  | 3460 | if (acl_type == ACL_TYPE_ACCESS) { | 
|  | 3461 | count = le16_to_cpu(cifs_acl->access_entry_count); | 
|  | 3462 | pACE = &cifs_acl->ace_array[0]; | 
|  | 3463 | size = sizeof(struct cifs_posix_acl); | 
|  | 3464 | size += sizeof(struct cifs_posix_ace) * count; | 
|  | 3465 | /* check if we would go beyond end of SMB */ | 
|  | 3466 | if (size_of_data_area < size) { | 
|  | 3467 | cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n", | 
|  | 3468 | size_of_data_area, size); | 
|  | 3469 | return -EINVAL; | 
|  | 3470 | } | 
|  | 3471 | } else if (acl_type == ACL_TYPE_DEFAULT) { | 
|  | 3472 | count = le16_to_cpu(cifs_acl->access_entry_count); | 
|  | 3473 | size = sizeof(struct cifs_posix_acl); | 
|  | 3474 | size += sizeof(struct cifs_posix_ace) * count; | 
|  | 3475 | /* skip past access ACEs to get to default ACEs */ | 
|  | 3476 | pACE = &cifs_acl->ace_array[count]; | 
|  | 3477 | count = le16_to_cpu(cifs_acl->default_entry_count); | 
|  | 3478 | size += sizeof(struct cifs_posix_ace) * count; | 
|  | 3479 | /* check if we would go beyond end of SMB */ | 
|  | 3480 | if (size_of_data_area < size) | 
|  | 3481 | return -EINVAL; | 
|  | 3482 | } else { | 
|  | 3483 | /* illegal type */ | 
|  | 3484 | return -EINVAL; | 
|  | 3485 | } | 
|  | 3486 |  | 
|  | 3487 | size = posix_acl_xattr_size(count); | 
|  | 3488 | if ((buflen == 0) || (local_acl == NULL)) { | 
|  | 3489 | /* used to query ACL EA size */ | 
|  | 3490 | } else if (size > buflen) { | 
|  | 3491 | return -ERANGE; | 
|  | 3492 | } else /* buffer big enough */ { | 
|  | 3493 | struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1); | 
|  | 3494 |  | 
|  | 3495 | local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); | 
|  | 3496 | for (i = 0; i < count ; i++) { | 
|  | 3497 | cifs_convert_ace(&ace[i], pACE); | 
|  | 3498 | pACE++; | 
|  | 3499 | } | 
|  | 3500 | } | 
|  | 3501 | return size; | 
|  | 3502 | } | 
|  | 3503 |  | 
|  | 3504 | static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace, | 
|  | 3505 | const struct posix_acl_xattr_entry *local_ace) | 
|  | 3506 | { | 
|  | 3507 | __u16 rc = 0; /* 0 = ACL converted ok */ | 
|  | 3508 |  | 
|  | 3509 | cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm); | 
|  | 3510 | cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag); | 
|  | 3511 | /* BB is there a better way to handle the large uid? */ | 
|  | 3512 | if (local_ace->e_id == cpu_to_le32(-1)) { | 
|  | 3513 | /* Probably no need to le convert -1 on any arch but can not hurt */ | 
|  | 3514 | cifs_ace->cifs_uid = cpu_to_le64(-1); | 
|  | 3515 | } else | 
|  | 3516 | cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id)); | 
|  | 3517 | /* | 
|  | 3518 | cifs_dbg(FYI, "perm %d tag %d id %d\n", | 
|  | 3519 | ace->e_perm, ace->e_tag, ace->e_id); | 
|  | 3520 | */ | 
|  | 3521 | return rc; | 
|  | 3522 | } | 
|  | 3523 |  | 
|  | 3524 | /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */ | 
|  | 3525 | static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL, | 
|  | 3526 | const int buflen, const int acl_type) | 
|  | 3527 | { | 
|  | 3528 | __u16 rc = 0; | 
|  | 3529 | struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data; | 
|  | 3530 | struct posix_acl_xattr_header *local_acl = (void *)pACL; | 
|  | 3531 | struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1); | 
|  | 3532 | int count; | 
|  | 3533 | int i; | 
|  | 3534 |  | 
|  | 3535 | if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL)) | 
|  | 3536 | return 0; | 
|  | 3537 |  | 
|  | 3538 | count = posix_acl_xattr_count((size_t)buflen); | 
|  | 3539 | cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n", | 
|  | 3540 | count, buflen, le32_to_cpu(local_acl->a_version)); | 
|  | 3541 | if (le32_to_cpu(local_acl->a_version) != 2) { | 
|  | 3542 | cifs_dbg(FYI, "unknown POSIX ACL version %d\n", | 
|  | 3543 | le32_to_cpu(local_acl->a_version)); | 
|  | 3544 | return 0; | 
|  | 3545 | } | 
|  | 3546 | cifs_acl->version = cpu_to_le16(1); | 
|  | 3547 | if (acl_type == ACL_TYPE_ACCESS) { | 
|  | 3548 | cifs_acl->access_entry_count = cpu_to_le16(count); | 
|  | 3549 | cifs_acl->default_entry_count = cpu_to_le16(0xFFFF); | 
|  | 3550 | } else if (acl_type == ACL_TYPE_DEFAULT) { | 
|  | 3551 | cifs_acl->default_entry_count = cpu_to_le16(count); | 
|  | 3552 | cifs_acl->access_entry_count = cpu_to_le16(0xFFFF); | 
|  | 3553 | } else { | 
|  | 3554 | cifs_dbg(FYI, "unknown ACL type %d\n", acl_type); | 
|  | 3555 | return 0; | 
|  | 3556 | } | 
|  | 3557 | for (i = 0; i < count; i++) { | 
|  | 3558 | rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]); | 
|  | 3559 | if (rc != 0) { | 
|  | 3560 | /* ACE not converted */ | 
|  | 3561 | break; | 
|  | 3562 | } | 
|  | 3563 | } | 
|  | 3564 | if (rc == 0) { | 
|  | 3565 | rc = (__u16)(count * sizeof(struct cifs_posix_ace)); | 
|  | 3566 | rc += sizeof(struct cifs_posix_acl); | 
|  | 3567 | /* BB add check to make sure ACL does not overflow SMB */ | 
|  | 3568 | } | 
|  | 3569 | return rc; | 
|  | 3570 | } | 
|  | 3571 |  | 
|  | 3572 | int | 
|  | 3573 | CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 3574 | const unsigned char *searchName, | 
|  | 3575 | char *acl_inf, const int buflen, const int acl_type, | 
|  | 3576 | const struct nls_table *nls_codepage, int remap) | 
|  | 3577 | { | 
|  | 3578 | /* SMB_QUERY_POSIX_ACL */ | 
|  | 3579 | TRANSACTION2_QPI_REQ *pSMB = NULL; | 
|  | 3580 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | 
|  | 3581 | int rc = 0; | 
|  | 3582 | int bytes_returned; | 
|  | 3583 | int name_len; | 
|  | 3584 | __u16 params, byte_count; | 
|  | 3585 |  | 
|  | 3586 | cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName); | 
|  | 3587 |  | 
|  | 3588 | queryAclRetry: | 
|  | 3589 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 3590 | (void **) &pSMBr); | 
|  | 3591 | if (rc) | 
|  | 3592 | return rc; | 
|  | 3593 |  | 
|  | 3594 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 3595 | name_len = | 
|  | 3596 | cifsConvertToUTF16((__le16 *) pSMB->FileName, | 
|  | 3597 | searchName, PATH_MAX, nls_codepage, | 
|  | 3598 | remap); | 
|  | 3599 | name_len++;     /* trailing null */ | 
|  | 3600 | name_len *= 2; | 
|  | 3601 | pSMB->FileName[name_len] = 0; | 
|  | 3602 | pSMB->FileName[name_len+1] = 0; | 
|  | 3603 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 3604 | name_len = strnlen(searchName, PATH_MAX); | 
|  | 3605 | name_len++;     /* trailing null */ | 
|  | 3606 | strncpy(pSMB->FileName, searchName, name_len); | 
|  | 3607 | } | 
|  | 3608 |  | 
|  | 3609 | params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ; | 
|  | 3610 | pSMB->TotalDataCount = 0; | 
|  | 3611 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 3612 | /* BB find exact max data count below from sess structure BB */ | 
|  | 3613 | pSMB->MaxDataCount = cpu_to_le16(4000); | 
|  | 3614 | pSMB->MaxSetupCount = 0; | 
|  | 3615 | pSMB->Reserved = 0; | 
|  | 3616 | pSMB->Flags = 0; | 
|  | 3617 | pSMB->Timeout = 0; | 
|  | 3618 | pSMB->Reserved2 = 0; | 
|  | 3619 | pSMB->ParameterOffset = cpu_to_le16( | 
|  | 3620 | offsetof(struct smb_com_transaction2_qpi_req, | 
|  | 3621 | InformationLevel) - 4); | 
|  | 3622 | pSMB->DataCount = 0; | 
|  | 3623 | pSMB->DataOffset = 0; | 
|  | 3624 | pSMB->SetupCount = 1; | 
|  | 3625 | pSMB->Reserved3 = 0; | 
|  | 3626 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | 
|  | 3627 | byte_count = params + 1 /* pad */ ; | 
|  | 3628 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 3629 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 3630 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL); | 
|  | 3631 | pSMB->Reserved4 = 0; | 
|  | 3632 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 3633 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 3634 |  | 
|  | 3635 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 3636 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 3637 | cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get); | 
|  | 3638 | if (rc) { | 
|  | 3639 | cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc); | 
|  | 3640 | } else { | 
|  | 3641 | /* decode response */ | 
|  | 3642 |  | 
|  | 3643 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 3644 | /* BB also check enough total bytes returned */ | 
|  | 3645 | if (rc || get_bcc(&pSMBr->hdr) < 2) | 
|  | 3646 | rc = -EIO;      /* bad smb */ | 
|  | 3647 | else { | 
|  | 3648 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 3649 | __u16 count = le16_to_cpu(pSMBr->t2.DataCount); | 
|  | 3650 | rc = cifs_copy_posix_acl(acl_inf, | 
|  | 3651 | (char *)&pSMBr->hdr.Protocol+data_offset, | 
|  | 3652 | buflen, acl_type, count); | 
|  | 3653 | } | 
|  | 3654 | } | 
|  | 3655 | cifs_buf_release(pSMB); | 
|  | 3656 | if (rc == -EAGAIN) | 
|  | 3657 | goto queryAclRetry; | 
|  | 3658 | return rc; | 
|  | 3659 | } | 
|  | 3660 |  | 
|  | 3661 | int | 
|  | 3662 | CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 3663 | const unsigned char *fileName, | 
|  | 3664 | const char *local_acl, const int buflen, | 
|  | 3665 | const int acl_type, | 
|  | 3666 | const struct nls_table *nls_codepage, int remap) | 
|  | 3667 | { | 
|  | 3668 | struct smb_com_transaction2_spi_req *pSMB = NULL; | 
|  | 3669 | struct smb_com_transaction2_spi_rsp *pSMBr = NULL; | 
|  | 3670 | char *parm_data; | 
|  | 3671 | int name_len; | 
|  | 3672 | int rc = 0; | 
|  | 3673 | int bytes_returned = 0; | 
|  | 3674 | __u16 params, byte_count, data_count, param_offset, offset; | 
|  | 3675 |  | 
|  | 3676 | cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName); | 
|  | 3677 | setAclRetry: | 
|  | 3678 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 3679 | (void **) &pSMBr); | 
|  | 3680 | if (rc) | 
|  | 3681 | return rc; | 
|  | 3682 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 3683 | name_len = | 
|  | 3684 | cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, | 
|  | 3685 | PATH_MAX, nls_codepage, remap); | 
|  | 3686 | name_len++;     /* trailing null */ | 
|  | 3687 | name_len *= 2; | 
|  | 3688 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 3689 | name_len = strnlen(fileName, PATH_MAX); | 
|  | 3690 | name_len++;     /* trailing null */ | 
|  | 3691 | strncpy(pSMB->FileName, fileName, name_len); | 
|  | 3692 | } | 
|  | 3693 | params = 6 + name_len; | 
|  | 3694 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 3695 | /* BB find max SMB size from sess */ | 
|  | 3696 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 3697 | pSMB->MaxSetupCount = 0; | 
|  | 3698 | pSMB->Reserved = 0; | 
|  | 3699 | pSMB->Flags = 0; | 
|  | 3700 | pSMB->Timeout = 0; | 
|  | 3701 | pSMB->Reserved2 = 0; | 
|  | 3702 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | 
|  | 3703 | InformationLevel) - 4; | 
|  | 3704 | offset = param_offset + params; | 
|  | 3705 | parm_data = ((char *) &pSMB->hdr.Protocol) + offset; | 
|  | 3706 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 3707 |  | 
|  | 3708 | /* convert to on the wire format for POSIX ACL */ | 
|  | 3709 | data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type); | 
|  | 3710 |  | 
|  | 3711 | if (data_count == 0) { | 
|  | 3712 | rc = -EOPNOTSUPP; | 
|  | 3713 | goto setACLerrorExit; | 
|  | 3714 | } | 
|  | 3715 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 3716 | pSMB->SetupCount = 1; | 
|  | 3717 | pSMB->Reserved3 = 0; | 
|  | 3718 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | 
|  | 3719 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL); | 
|  | 3720 | byte_count = 3 /* pad */  + params + data_count; | 
|  | 3721 | pSMB->DataCount = cpu_to_le16(data_count); | 
|  | 3722 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 3723 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 3724 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 3725 | pSMB->Reserved4 = 0; | 
|  | 3726 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 3727 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 3728 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 3729 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 3730 | if (rc) | 
|  | 3731 | cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc); | 
|  | 3732 |  | 
|  | 3733 | setACLerrorExit: | 
|  | 3734 | cifs_buf_release(pSMB); | 
|  | 3735 | if (rc == -EAGAIN) | 
|  | 3736 | goto setAclRetry; | 
|  | 3737 | return rc; | 
|  | 3738 | } | 
|  | 3739 |  | 
|  | 3740 | /* BB fix tabs in this function FIXME BB */ | 
|  | 3741 | int | 
|  | 3742 | CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 3743 | const int netfid, __u64 *pExtAttrBits, __u64 *pMask) | 
|  | 3744 | { | 
|  | 3745 | int rc = 0; | 
|  | 3746 | struct smb_t2_qfi_req *pSMB = NULL; | 
|  | 3747 | struct smb_t2_qfi_rsp *pSMBr = NULL; | 
|  | 3748 | int bytes_returned; | 
|  | 3749 | __u16 params, byte_count; | 
|  | 3750 |  | 
|  | 3751 | cifs_dbg(FYI, "In GetExtAttr\n"); | 
|  | 3752 | if (tcon == NULL) | 
|  | 3753 | return -ENODEV; | 
|  | 3754 |  | 
|  | 3755 | GetExtAttrRetry: | 
|  | 3756 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 3757 | (void **) &pSMBr); | 
|  | 3758 | if (rc) | 
|  | 3759 | return rc; | 
|  | 3760 |  | 
|  | 3761 | params = 2 /* level */ + 2 /* fid */; | 
|  | 3762 | pSMB->t2.TotalDataCount = 0; | 
|  | 3763 | pSMB->t2.MaxParameterCount = cpu_to_le16(4); | 
|  | 3764 | /* BB find exact max data count below from sess structure BB */ | 
|  | 3765 | pSMB->t2.MaxDataCount = cpu_to_le16(4000); | 
|  | 3766 | pSMB->t2.MaxSetupCount = 0; | 
|  | 3767 | pSMB->t2.Reserved = 0; | 
|  | 3768 | pSMB->t2.Flags = 0; | 
|  | 3769 | pSMB->t2.Timeout = 0; | 
|  | 3770 | pSMB->t2.Reserved2 = 0; | 
|  | 3771 | pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, | 
|  | 3772 | Fid) - 4); | 
|  | 3773 | pSMB->t2.DataCount = 0; | 
|  | 3774 | pSMB->t2.DataOffset = 0; | 
|  | 3775 | pSMB->t2.SetupCount = 1; | 
|  | 3776 | pSMB->t2.Reserved3 = 0; | 
|  | 3777 | pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); | 
|  | 3778 | byte_count = params + 1 /* pad */ ; | 
|  | 3779 | pSMB->t2.TotalParameterCount = cpu_to_le16(params); | 
|  | 3780 | pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; | 
|  | 3781 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS); | 
|  | 3782 | pSMB->Pad = 0; | 
|  | 3783 | pSMB->Fid = netfid; | 
|  | 3784 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 3785 | pSMB->t2.ByteCount = cpu_to_le16(byte_count); | 
|  | 3786 |  | 
|  | 3787 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 3788 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 3789 | if (rc) { | 
|  | 3790 | cifs_dbg(FYI, "error %d in GetExtAttr\n", rc); | 
|  | 3791 | } else { | 
|  | 3792 | /* decode response */ | 
|  | 3793 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 3794 | /* BB also check enough total bytes returned */ | 
|  | 3795 | if (rc || get_bcc(&pSMBr->hdr) < 2) | 
|  | 3796 | /* If rc should we check for EOPNOSUPP and | 
|  | 3797 | disable the srvino flag? or in caller? */ | 
|  | 3798 | rc = -EIO;      /* bad smb */ | 
|  | 3799 | else { | 
|  | 3800 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 3801 | __u16 count = le16_to_cpu(pSMBr->t2.DataCount); | 
|  | 3802 | struct file_chattr_info *pfinfo; | 
|  | 3803 | /* BB Do we need a cast or hash here ? */ | 
|  | 3804 | if (count != 16) { | 
|  | 3805 | cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n"); | 
|  | 3806 | rc = -EIO; | 
|  | 3807 | goto GetExtAttrOut; | 
|  | 3808 | } | 
|  | 3809 | pfinfo = (struct file_chattr_info *) | 
|  | 3810 | (data_offset + (char *) &pSMBr->hdr.Protocol); | 
|  | 3811 | *pExtAttrBits = le64_to_cpu(pfinfo->mode); | 
|  | 3812 | *pMask = le64_to_cpu(pfinfo->mask); | 
|  | 3813 | } | 
|  | 3814 | } | 
|  | 3815 | GetExtAttrOut: | 
|  | 3816 | cifs_buf_release(pSMB); | 
|  | 3817 | if (rc == -EAGAIN) | 
|  | 3818 | goto GetExtAttrRetry; | 
|  | 3819 | return rc; | 
|  | 3820 | } | 
|  | 3821 |  | 
|  | 3822 | #endif /* CONFIG_POSIX */ | 
|  | 3823 |  | 
|  | 3824 | #ifdef CONFIG_CIFS_ACL | 
|  | 3825 | /* | 
|  | 3826 | * Initialize NT TRANSACT SMB into small smb request buffer.  This assumes that | 
|  | 3827 | * all NT TRANSACTS that we init here have total parm and data under about 400 | 
|  | 3828 | * bytes (to fit in small cifs buffer size), which is the case so far, it | 
|  | 3829 | * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of | 
|  | 3830 | * returned setup area) and MaxParameterCount (returned parms size) must be set | 
|  | 3831 | * by caller | 
|  | 3832 | */ | 
|  | 3833 | static int | 
|  | 3834 | smb_init_nttransact(const __u16 sub_command, const int setup_count, | 
|  | 3835 | const int parm_len, struct cifs_tcon *tcon, | 
|  | 3836 | void **ret_buf) | 
|  | 3837 | { | 
|  | 3838 | int rc; | 
|  | 3839 | __u32 temp_offset; | 
|  | 3840 | struct smb_com_ntransact_req *pSMB; | 
|  | 3841 |  | 
|  | 3842 | rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, | 
|  | 3843 | (void **)&pSMB); | 
|  | 3844 | if (rc) | 
|  | 3845 | return rc; | 
|  | 3846 | *ret_buf = (void *)pSMB; | 
|  | 3847 | pSMB->Reserved = 0; | 
|  | 3848 | pSMB->TotalParameterCount = cpu_to_le32(parm_len); | 
|  | 3849 | pSMB->TotalDataCount  = 0; | 
|  | 3850 | pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); | 
|  | 3851 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 3852 | pSMB->DataCount  = pSMB->TotalDataCount; | 
|  | 3853 | temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + | 
|  | 3854 | (setup_count * 2) - 4 /* for rfc1001 length itself */; | 
|  | 3855 | pSMB->ParameterOffset = cpu_to_le32(temp_offset); | 
|  | 3856 | pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); | 
|  | 3857 | pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ | 
|  | 3858 | pSMB->SubCommand = cpu_to_le16(sub_command); | 
|  | 3859 | return 0; | 
|  | 3860 | } | 
|  | 3861 |  | 
|  | 3862 | static int | 
|  | 3863 | validate_ntransact(char *buf, char **ppparm, char **ppdata, | 
|  | 3864 | __u32 *pparmlen, __u32 *pdatalen) | 
|  | 3865 | { | 
|  | 3866 | char *end_of_smb; | 
|  | 3867 | __u32 data_count, data_offset, parm_count, parm_offset; | 
|  | 3868 | struct smb_com_ntransact_rsp *pSMBr; | 
|  | 3869 | u16 bcc; | 
|  | 3870 |  | 
|  | 3871 | *pdatalen = 0; | 
|  | 3872 | *pparmlen = 0; | 
|  | 3873 |  | 
|  | 3874 | if (buf == NULL) | 
|  | 3875 | return -EINVAL; | 
|  | 3876 |  | 
|  | 3877 | pSMBr = (struct smb_com_ntransact_rsp *)buf; | 
|  | 3878 |  | 
|  | 3879 | bcc = get_bcc(&pSMBr->hdr); | 
|  | 3880 | end_of_smb = 2 /* sizeof byte count */ + bcc + | 
|  | 3881 | (char *)&pSMBr->ByteCount; | 
|  | 3882 |  | 
|  | 3883 | data_offset = le32_to_cpu(pSMBr->DataOffset); | 
|  | 3884 | data_count = le32_to_cpu(pSMBr->DataCount); | 
|  | 3885 | parm_offset = le32_to_cpu(pSMBr->ParameterOffset); | 
|  | 3886 | parm_count = le32_to_cpu(pSMBr->ParameterCount); | 
|  | 3887 |  | 
|  | 3888 | *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; | 
|  | 3889 | *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; | 
|  | 3890 |  | 
|  | 3891 | /* should we also check that parm and data areas do not overlap? */ | 
|  | 3892 | if (*ppparm > end_of_smb) { | 
|  | 3893 | cifs_dbg(FYI, "parms start after end of smb\n"); | 
|  | 3894 | return -EINVAL; | 
|  | 3895 | } else if (parm_count + *ppparm > end_of_smb) { | 
|  | 3896 | cifs_dbg(FYI, "parm end after end of smb\n"); | 
|  | 3897 | return -EINVAL; | 
|  | 3898 | } else if (*ppdata > end_of_smb) { | 
|  | 3899 | cifs_dbg(FYI, "data starts after end of smb\n"); | 
|  | 3900 | return -EINVAL; | 
|  | 3901 | } else if (data_count + *ppdata > end_of_smb) { | 
|  | 3902 | cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n", | 
|  | 3903 | *ppdata, data_count, (data_count + *ppdata), | 
|  | 3904 | end_of_smb, pSMBr); | 
|  | 3905 | return -EINVAL; | 
|  | 3906 | } else if (parm_count + data_count > bcc) { | 
|  | 3907 | cifs_dbg(FYI, "parm count and data count larger than SMB\n"); | 
|  | 3908 | return -EINVAL; | 
|  | 3909 | } | 
|  | 3910 | *pdatalen = data_count; | 
|  | 3911 | *pparmlen = parm_count; | 
|  | 3912 | return 0; | 
|  | 3913 | } | 
|  | 3914 |  | 
|  | 3915 | /* Get Security Descriptor (by handle) from remote server for a file or dir */ | 
|  | 3916 | int | 
|  | 3917 | CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, | 
|  | 3918 | struct cifs_ntsd **acl_inf, __u32 *pbuflen) | 
|  | 3919 | { | 
|  | 3920 | int rc = 0; | 
|  | 3921 | int buf_type = 0; | 
|  | 3922 | QUERY_SEC_DESC_REQ *pSMB; | 
|  | 3923 | struct kvec iov[1]; | 
|  | 3924 | struct kvec rsp_iov; | 
|  | 3925 |  | 
|  | 3926 | cifs_dbg(FYI, "GetCifsACL\n"); | 
|  | 3927 |  | 
|  | 3928 | *pbuflen = 0; | 
|  | 3929 | *acl_inf = NULL; | 
|  | 3930 |  | 
|  | 3931 | rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, | 
|  | 3932 | 8 /* parm len */, tcon, (void **) &pSMB); | 
|  | 3933 | if (rc) | 
|  | 3934 | return rc; | 
|  | 3935 |  | 
|  | 3936 | pSMB->MaxParameterCount = cpu_to_le32(4); | 
|  | 3937 | /* BB TEST with big acls that might need to be e.g. larger than 16K */ | 
|  | 3938 | pSMB->MaxSetupCount = 0; | 
|  | 3939 | pSMB->Fid = fid; /* file handle always le */ | 
|  | 3940 | pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP | | 
|  | 3941 | CIFS_ACL_DACL); | 
|  | 3942 | pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */ | 
|  | 3943 | inc_rfc1001_len(pSMB, 11); | 
|  | 3944 | iov[0].iov_base = (char *)pSMB; | 
|  | 3945 | iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; | 
|  | 3946 |  | 
|  | 3947 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, | 
|  | 3948 | 0, &rsp_iov); | 
|  | 3949 | cifs_small_buf_release(pSMB); | 
|  | 3950 | cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get); | 
|  | 3951 | if (rc) { | 
|  | 3952 | cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc); | 
|  | 3953 | } else {                /* decode response */ | 
|  | 3954 | __le32 *parm; | 
|  | 3955 | __u32 parm_len; | 
|  | 3956 | __u32 acl_len; | 
|  | 3957 | struct smb_com_ntransact_rsp *pSMBr; | 
|  | 3958 | char *pdata; | 
|  | 3959 |  | 
|  | 3960 | /* validate_nttransact */ | 
|  | 3961 | rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm, | 
|  | 3962 | &pdata, &parm_len, pbuflen); | 
|  | 3963 | if (rc) | 
|  | 3964 | goto qsec_out; | 
|  | 3965 | pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base; | 
|  | 3966 |  | 
|  | 3967 | cifs_dbg(FYI, "smb %p parm %p data %p\n", | 
|  | 3968 | pSMBr, parm, *acl_inf); | 
|  | 3969 |  | 
|  | 3970 | if (le32_to_cpu(pSMBr->ParameterCount) != 4) { | 
|  | 3971 | rc = -EIO;      /* bad smb */ | 
|  | 3972 | *pbuflen = 0; | 
|  | 3973 | goto qsec_out; | 
|  | 3974 | } | 
|  | 3975 |  | 
|  | 3976 | /* BB check that data area is minimum length and as big as acl_len */ | 
|  | 3977 |  | 
|  | 3978 | acl_len = le32_to_cpu(*parm); | 
|  | 3979 | if (acl_len != *pbuflen) { | 
|  | 3980 | cifs_dbg(VFS, "acl length %d does not match %d\n", | 
|  | 3981 | acl_len, *pbuflen); | 
|  | 3982 | if (*pbuflen > acl_len) | 
|  | 3983 | *pbuflen = acl_len; | 
|  | 3984 | } | 
|  | 3985 |  | 
|  | 3986 | /* check if buffer is big enough for the acl | 
|  | 3987 | header followed by the smallest SID */ | 
|  | 3988 | if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) || | 
|  | 3989 | (*pbuflen >= 64 * 1024)) { | 
|  | 3990 | cifs_dbg(VFS, "bad acl length %d\n", *pbuflen); | 
|  | 3991 | rc = -EINVAL; | 
|  | 3992 | *pbuflen = 0; | 
|  | 3993 | } else { | 
|  | 3994 | *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL); | 
|  | 3995 | if (*acl_inf == NULL) { | 
|  | 3996 | *pbuflen = 0; | 
|  | 3997 | rc = -ENOMEM; | 
|  | 3998 | } | 
|  | 3999 | } | 
|  | 4000 | } | 
|  | 4001 | qsec_out: | 
|  | 4002 | free_rsp_buf(buf_type, rsp_iov.iov_base); | 
|  | 4003 | return rc; | 
|  | 4004 | } | 
|  | 4005 |  | 
|  | 4006 | int | 
|  | 4007 | CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, | 
|  | 4008 | struct cifs_ntsd *pntsd, __u32 acllen, int aclflag) | 
|  | 4009 | { | 
|  | 4010 | __u16 byte_count, param_count, data_count, param_offset, data_offset; | 
|  | 4011 | int rc = 0; | 
|  | 4012 | int bytes_returned = 0; | 
|  | 4013 | SET_SEC_DESC_REQ *pSMB = NULL; | 
|  | 4014 | void *pSMBr; | 
|  | 4015 |  | 
|  | 4016 | setCifsAclRetry: | 
|  | 4017 | rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr); | 
|  | 4018 | if (rc) | 
|  | 4019 | return rc; | 
|  | 4020 |  | 
|  | 4021 | pSMB->MaxSetupCount = 0; | 
|  | 4022 | pSMB->Reserved = 0; | 
|  | 4023 |  | 
|  | 4024 | param_count = 8; | 
|  | 4025 | param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4; | 
|  | 4026 | data_count = acllen; | 
|  | 4027 | data_offset = param_offset + param_count; | 
|  | 4028 | byte_count = 3 /* pad */  + param_count; | 
|  | 4029 |  | 
|  | 4030 | pSMB->DataCount = cpu_to_le32(data_count); | 
|  | 4031 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 4032 | pSMB->MaxParameterCount = cpu_to_le32(4); | 
|  | 4033 | pSMB->MaxDataCount = cpu_to_le32(16384); | 
|  | 4034 | pSMB->ParameterCount = cpu_to_le32(param_count); | 
|  | 4035 | pSMB->ParameterOffset = cpu_to_le32(param_offset); | 
|  | 4036 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 4037 | pSMB->DataOffset = cpu_to_le32(data_offset); | 
|  | 4038 | pSMB->SetupCount = 0; | 
|  | 4039 | pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC); | 
|  | 4040 | pSMB->ByteCount = cpu_to_le16(byte_count+data_count); | 
|  | 4041 |  | 
|  | 4042 | pSMB->Fid = fid; /* file handle always le */ | 
|  | 4043 | pSMB->Reserved2 = 0; | 
|  | 4044 | pSMB->AclFlags = cpu_to_le32(aclflag); | 
|  | 4045 |  | 
|  | 4046 | if (pntsd && acllen) { | 
|  | 4047 | memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) + | 
|  | 4048 | data_offset, pntsd, acllen); | 
|  | 4049 | inc_rfc1001_len(pSMB, byte_count + data_count); | 
|  | 4050 | } else | 
|  | 4051 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 4052 |  | 
|  | 4053 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 4054 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 4055 |  | 
|  | 4056 | cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n", | 
|  | 4057 | bytes_returned, rc); | 
|  | 4058 | if (rc) | 
|  | 4059 | cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc); | 
|  | 4060 | cifs_buf_release(pSMB); | 
|  | 4061 |  | 
|  | 4062 | if (rc == -EAGAIN) | 
|  | 4063 | goto setCifsAclRetry; | 
|  | 4064 |  | 
|  | 4065 | return (rc); | 
|  | 4066 | } | 
|  | 4067 |  | 
|  | 4068 | #endif /* CONFIG_CIFS_ACL */ | 
|  | 4069 |  | 
|  | 4070 | /* Legacy Query Path Information call for lookup to old servers such | 
|  | 4071 | as Win9x/WinME */ | 
|  | 4072 | int | 
|  | 4073 | SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 4074 | const char *search_name, FILE_ALL_INFO *data, | 
|  | 4075 | const struct nls_table *nls_codepage, int remap) | 
|  | 4076 | { | 
|  | 4077 | QUERY_INFORMATION_REQ *pSMB; | 
|  | 4078 | QUERY_INFORMATION_RSP *pSMBr; | 
|  | 4079 | int rc = 0; | 
|  | 4080 | int bytes_returned; | 
|  | 4081 | int name_len; | 
|  | 4082 |  | 
|  | 4083 | cifs_dbg(FYI, "In SMBQPath path %s\n", search_name); | 
|  | 4084 | QInfRetry: | 
|  | 4085 | rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB, | 
|  | 4086 | (void **) &pSMBr); | 
|  | 4087 | if (rc) | 
|  | 4088 | return rc; | 
|  | 4089 |  | 
|  | 4090 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 4091 | name_len = | 
|  | 4092 | cifsConvertToUTF16((__le16 *) pSMB->FileName, | 
|  | 4093 | search_name, PATH_MAX, nls_codepage, | 
|  | 4094 | remap); | 
|  | 4095 | name_len++;     /* trailing null */ | 
|  | 4096 | name_len *= 2; | 
|  | 4097 | } else { | 
|  | 4098 | name_len = strnlen(search_name, PATH_MAX); | 
|  | 4099 | name_len++;     /* trailing null */ | 
|  | 4100 | strncpy(pSMB->FileName, search_name, name_len); | 
|  | 4101 | } | 
|  | 4102 | pSMB->BufferFormat = 0x04; | 
|  | 4103 | name_len++; /* account for buffer type byte */ | 
|  | 4104 | inc_rfc1001_len(pSMB, (__u16)name_len); | 
|  | 4105 | pSMB->ByteCount = cpu_to_le16(name_len); | 
|  | 4106 |  | 
|  | 4107 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 4108 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 4109 | if (rc) { | 
|  | 4110 | cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc); | 
|  | 4111 | } else if (data) { | 
|  | 4112 | struct timespec64 ts; | 
|  | 4113 | __u32 time = le32_to_cpu(pSMBr->last_write_time); | 
|  | 4114 |  | 
|  | 4115 | /* decode response */ | 
|  | 4116 | /* BB FIXME - add time zone adjustment BB */ | 
|  | 4117 | memset(data, 0, sizeof(FILE_ALL_INFO)); | 
|  | 4118 | ts.tv_nsec = 0; | 
|  | 4119 | ts.tv_sec = time; | 
|  | 4120 | /* decode time fields */ | 
|  | 4121 | data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts)); | 
|  | 4122 | data->LastWriteTime = data->ChangeTime; | 
|  | 4123 | data->LastAccessTime = 0; | 
|  | 4124 | data->AllocationSize = | 
|  | 4125 | cpu_to_le64(le32_to_cpu(pSMBr->size)); | 
|  | 4126 | data->EndOfFile = data->AllocationSize; | 
|  | 4127 | data->Attributes = | 
|  | 4128 | cpu_to_le32(le16_to_cpu(pSMBr->attr)); | 
|  | 4129 | } else | 
|  | 4130 | rc = -EIO; /* bad buffer passed in */ | 
|  | 4131 |  | 
|  | 4132 | cifs_buf_release(pSMB); | 
|  | 4133 |  | 
|  | 4134 | if (rc == -EAGAIN) | 
|  | 4135 | goto QInfRetry; | 
|  | 4136 |  | 
|  | 4137 | return rc; | 
|  | 4138 | } | 
|  | 4139 |  | 
|  | 4140 | int | 
|  | 4141 | CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 4142 | u16 netfid, FILE_ALL_INFO *pFindData) | 
|  | 4143 | { | 
|  | 4144 | struct smb_t2_qfi_req *pSMB = NULL; | 
|  | 4145 | struct smb_t2_qfi_rsp *pSMBr = NULL; | 
|  | 4146 | int rc = 0; | 
|  | 4147 | int bytes_returned; | 
|  | 4148 | __u16 params, byte_count; | 
|  | 4149 |  | 
|  | 4150 | QFileInfoRetry: | 
|  | 4151 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 4152 | (void **) &pSMBr); | 
|  | 4153 | if (rc) | 
|  | 4154 | return rc; | 
|  | 4155 |  | 
|  | 4156 | params = 2 /* level */ + 2 /* fid */; | 
|  | 4157 | pSMB->t2.TotalDataCount = 0; | 
|  | 4158 | pSMB->t2.MaxParameterCount = cpu_to_le16(4); | 
|  | 4159 | /* BB find exact max data count below from sess structure BB */ | 
|  | 4160 | pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize); | 
|  | 4161 | pSMB->t2.MaxSetupCount = 0; | 
|  | 4162 | pSMB->t2.Reserved = 0; | 
|  | 4163 | pSMB->t2.Flags = 0; | 
|  | 4164 | pSMB->t2.Timeout = 0; | 
|  | 4165 | pSMB->t2.Reserved2 = 0; | 
|  | 4166 | pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, | 
|  | 4167 | Fid) - 4); | 
|  | 4168 | pSMB->t2.DataCount = 0; | 
|  | 4169 | pSMB->t2.DataOffset = 0; | 
|  | 4170 | pSMB->t2.SetupCount = 1; | 
|  | 4171 | pSMB->t2.Reserved3 = 0; | 
|  | 4172 | pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); | 
|  | 4173 | byte_count = params + 1 /* pad */ ; | 
|  | 4174 | pSMB->t2.TotalParameterCount = cpu_to_le16(params); | 
|  | 4175 | pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; | 
|  | 4176 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); | 
|  | 4177 | pSMB->Pad = 0; | 
|  | 4178 | pSMB->Fid = netfid; | 
|  | 4179 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 4180 | pSMB->t2.ByteCount = cpu_to_le16(byte_count); | 
|  | 4181 |  | 
|  | 4182 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 4183 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 4184 | if (rc) { | 
|  | 4185 | cifs_dbg(FYI, "Send error in QFileInfo = %d", rc); | 
|  | 4186 | } else {		/* decode response */ | 
|  | 4187 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 4188 |  | 
|  | 4189 | if (rc) /* BB add auto retry on EOPNOTSUPP? */ | 
|  | 4190 | rc = -EIO; | 
|  | 4191 | else if (get_bcc(&pSMBr->hdr) < 40) | 
|  | 4192 | rc = -EIO;	/* bad smb */ | 
|  | 4193 | else if (pFindData) { | 
|  | 4194 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 4195 | memcpy((char *) pFindData, | 
|  | 4196 | (char *) &pSMBr->hdr.Protocol + | 
|  | 4197 | data_offset, sizeof(FILE_ALL_INFO)); | 
|  | 4198 | } else | 
|  | 4199 | rc = -ENOMEM; | 
|  | 4200 | } | 
|  | 4201 | cifs_buf_release(pSMB); | 
|  | 4202 | if (rc == -EAGAIN) | 
|  | 4203 | goto QFileInfoRetry; | 
|  | 4204 |  | 
|  | 4205 | return rc; | 
|  | 4206 | } | 
|  | 4207 |  | 
|  | 4208 | int | 
|  | 4209 | CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 4210 | const char *search_name, FILE_ALL_INFO *data, | 
|  | 4211 | int legacy /* old style infolevel */, | 
|  | 4212 | const struct nls_table *nls_codepage, int remap) | 
|  | 4213 | { | 
|  | 4214 | /* level 263 SMB_QUERY_FILE_ALL_INFO */ | 
|  | 4215 | TRANSACTION2_QPI_REQ *pSMB = NULL; | 
|  | 4216 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | 
|  | 4217 | int rc = 0; | 
|  | 4218 | int bytes_returned; | 
|  | 4219 | int name_len; | 
|  | 4220 | __u16 params, byte_count; | 
|  | 4221 |  | 
|  | 4222 | /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */ | 
|  | 4223 | QPathInfoRetry: | 
|  | 4224 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 4225 | (void **) &pSMBr); | 
|  | 4226 | if (rc) | 
|  | 4227 | return rc; | 
|  | 4228 |  | 
|  | 4229 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 4230 | name_len = | 
|  | 4231 | cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name, | 
|  | 4232 | PATH_MAX, nls_codepage, remap); | 
|  | 4233 | name_len++;	/* trailing null */ | 
|  | 4234 | name_len *= 2; | 
|  | 4235 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 4236 | name_len = strnlen(search_name, PATH_MAX); | 
|  | 4237 | name_len++;	/* trailing null */ | 
|  | 4238 | strncpy(pSMB->FileName, search_name, name_len); | 
|  | 4239 | } | 
|  | 4240 |  | 
|  | 4241 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; | 
|  | 4242 | pSMB->TotalDataCount = 0; | 
|  | 4243 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 4244 | /* BB find exact max SMB PDU from sess structure BB */ | 
|  | 4245 | pSMB->MaxDataCount = cpu_to_le16(4000); | 
|  | 4246 | pSMB->MaxSetupCount = 0; | 
|  | 4247 | pSMB->Reserved = 0; | 
|  | 4248 | pSMB->Flags = 0; | 
|  | 4249 | pSMB->Timeout = 0; | 
|  | 4250 | pSMB->Reserved2 = 0; | 
|  | 4251 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | 
|  | 4252 | struct smb_com_transaction2_qpi_req, InformationLevel) - 4); | 
|  | 4253 | pSMB->DataCount = 0; | 
|  | 4254 | pSMB->DataOffset = 0; | 
|  | 4255 | pSMB->SetupCount = 1; | 
|  | 4256 | pSMB->Reserved3 = 0; | 
|  | 4257 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | 
|  | 4258 | byte_count = params + 1 /* pad */ ; | 
|  | 4259 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 4260 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 4261 | if (legacy) | 
|  | 4262 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD); | 
|  | 4263 | else | 
|  | 4264 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); | 
|  | 4265 | pSMB->Reserved4 = 0; | 
|  | 4266 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 4267 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 4268 |  | 
|  | 4269 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 4270 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 4271 | if (rc) { | 
|  | 4272 | cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc); | 
|  | 4273 | } else {		/* decode response */ | 
|  | 4274 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 4275 |  | 
|  | 4276 | if (rc) /* BB add auto retry on EOPNOTSUPP? */ | 
|  | 4277 | rc = -EIO; | 
|  | 4278 | else if (!legacy && get_bcc(&pSMBr->hdr) < 40) | 
|  | 4279 | rc = -EIO;	/* bad smb */ | 
|  | 4280 | else if (legacy && get_bcc(&pSMBr->hdr) < 24) | 
|  | 4281 | rc = -EIO;  /* 24 or 26 expected but we do not read | 
|  | 4282 | last field */ | 
|  | 4283 | else if (data) { | 
|  | 4284 | int size; | 
|  | 4285 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 4286 |  | 
|  | 4287 | /* | 
|  | 4288 | * On legacy responses we do not read the last field, | 
|  | 4289 | * EAsize, fortunately since it varies by subdialect and | 
|  | 4290 | * also note it differs on Set vs Get, ie two bytes or 4 | 
|  | 4291 | * bytes depending but we don't care here. | 
|  | 4292 | */ | 
|  | 4293 | if (legacy) | 
|  | 4294 | size = sizeof(FILE_INFO_STANDARD); | 
|  | 4295 | else | 
|  | 4296 | size = sizeof(FILE_ALL_INFO); | 
|  | 4297 | memcpy((char *) data, (char *) &pSMBr->hdr.Protocol + | 
|  | 4298 | data_offset, size); | 
|  | 4299 | } else | 
|  | 4300 | rc = -ENOMEM; | 
|  | 4301 | } | 
|  | 4302 | cifs_buf_release(pSMB); | 
|  | 4303 | if (rc == -EAGAIN) | 
|  | 4304 | goto QPathInfoRetry; | 
|  | 4305 |  | 
|  | 4306 | return rc; | 
|  | 4307 | } | 
|  | 4308 |  | 
|  | 4309 | int | 
|  | 4310 | CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 4311 | u16 netfid, FILE_UNIX_BASIC_INFO *pFindData) | 
|  | 4312 | { | 
|  | 4313 | struct smb_t2_qfi_req *pSMB = NULL; | 
|  | 4314 | struct smb_t2_qfi_rsp *pSMBr = NULL; | 
|  | 4315 | int rc = 0; | 
|  | 4316 | int bytes_returned; | 
|  | 4317 | __u16 params, byte_count; | 
|  | 4318 |  | 
|  | 4319 | UnixQFileInfoRetry: | 
|  | 4320 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 4321 | (void **) &pSMBr); | 
|  | 4322 | if (rc) | 
|  | 4323 | return rc; | 
|  | 4324 |  | 
|  | 4325 | params = 2 /* level */ + 2 /* fid */; | 
|  | 4326 | pSMB->t2.TotalDataCount = 0; | 
|  | 4327 | pSMB->t2.MaxParameterCount = cpu_to_le16(4); | 
|  | 4328 | /* BB find exact max data count below from sess structure BB */ | 
|  | 4329 | pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize); | 
|  | 4330 | pSMB->t2.MaxSetupCount = 0; | 
|  | 4331 | pSMB->t2.Reserved = 0; | 
|  | 4332 | pSMB->t2.Flags = 0; | 
|  | 4333 | pSMB->t2.Timeout = 0; | 
|  | 4334 | pSMB->t2.Reserved2 = 0; | 
|  | 4335 | pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, | 
|  | 4336 | Fid) - 4); | 
|  | 4337 | pSMB->t2.DataCount = 0; | 
|  | 4338 | pSMB->t2.DataOffset = 0; | 
|  | 4339 | pSMB->t2.SetupCount = 1; | 
|  | 4340 | pSMB->t2.Reserved3 = 0; | 
|  | 4341 | pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); | 
|  | 4342 | byte_count = params + 1 /* pad */ ; | 
|  | 4343 | pSMB->t2.TotalParameterCount = cpu_to_le16(params); | 
|  | 4344 | pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; | 
|  | 4345 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); | 
|  | 4346 | pSMB->Pad = 0; | 
|  | 4347 | pSMB->Fid = netfid; | 
|  | 4348 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 4349 | pSMB->t2.ByteCount = cpu_to_le16(byte_count); | 
|  | 4350 |  | 
|  | 4351 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 4352 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 4353 | if (rc) { | 
|  | 4354 | cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc); | 
|  | 4355 | } else {		/* decode response */ | 
|  | 4356 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 4357 |  | 
|  | 4358 | if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { | 
|  | 4359 | cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n"); | 
|  | 4360 | rc = -EIO;	/* bad smb */ | 
|  | 4361 | } else { | 
|  | 4362 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 4363 | memcpy((char *) pFindData, | 
|  | 4364 | (char *) &pSMBr->hdr.Protocol + | 
|  | 4365 | data_offset, | 
|  | 4366 | sizeof(FILE_UNIX_BASIC_INFO)); | 
|  | 4367 | } | 
|  | 4368 | } | 
|  | 4369 |  | 
|  | 4370 | cifs_buf_release(pSMB); | 
|  | 4371 | if (rc == -EAGAIN) | 
|  | 4372 | goto UnixQFileInfoRetry; | 
|  | 4373 |  | 
|  | 4374 | return rc; | 
|  | 4375 | } | 
|  | 4376 |  | 
|  | 4377 | int | 
|  | 4378 | CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 4379 | const unsigned char *searchName, | 
|  | 4380 | FILE_UNIX_BASIC_INFO *pFindData, | 
|  | 4381 | const struct nls_table *nls_codepage, int remap) | 
|  | 4382 | { | 
|  | 4383 | /* SMB_QUERY_FILE_UNIX_BASIC */ | 
|  | 4384 | TRANSACTION2_QPI_REQ *pSMB = NULL; | 
|  | 4385 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | 
|  | 4386 | int rc = 0; | 
|  | 4387 | int bytes_returned = 0; | 
|  | 4388 | int name_len; | 
|  | 4389 | __u16 params, byte_count; | 
|  | 4390 |  | 
|  | 4391 | cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName); | 
|  | 4392 | UnixQPathInfoRetry: | 
|  | 4393 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 4394 | (void **) &pSMBr); | 
|  | 4395 | if (rc) | 
|  | 4396 | return rc; | 
|  | 4397 |  | 
|  | 4398 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 4399 | name_len = | 
|  | 4400 | cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, | 
|  | 4401 | PATH_MAX, nls_codepage, remap); | 
|  | 4402 | name_len++;	/* trailing null */ | 
|  | 4403 | name_len *= 2; | 
|  | 4404 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 4405 | name_len = strnlen(searchName, PATH_MAX); | 
|  | 4406 | name_len++;	/* trailing null */ | 
|  | 4407 | strncpy(pSMB->FileName, searchName, name_len); | 
|  | 4408 | } | 
|  | 4409 |  | 
|  | 4410 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; | 
|  | 4411 | pSMB->TotalDataCount = 0; | 
|  | 4412 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 4413 | /* BB find exact max SMB PDU from sess structure BB */ | 
|  | 4414 | pSMB->MaxDataCount = cpu_to_le16(4000); | 
|  | 4415 | pSMB->MaxSetupCount = 0; | 
|  | 4416 | pSMB->Reserved = 0; | 
|  | 4417 | pSMB->Flags = 0; | 
|  | 4418 | pSMB->Timeout = 0; | 
|  | 4419 | pSMB->Reserved2 = 0; | 
|  | 4420 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | 
|  | 4421 | struct smb_com_transaction2_qpi_req, InformationLevel) - 4); | 
|  | 4422 | pSMB->DataCount = 0; | 
|  | 4423 | pSMB->DataOffset = 0; | 
|  | 4424 | pSMB->SetupCount = 1; | 
|  | 4425 | pSMB->Reserved3 = 0; | 
|  | 4426 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | 
|  | 4427 | byte_count = params + 1 /* pad */ ; | 
|  | 4428 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 4429 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 4430 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); | 
|  | 4431 | pSMB->Reserved4 = 0; | 
|  | 4432 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 4433 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 4434 |  | 
|  | 4435 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 4436 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 4437 | if (rc) { | 
|  | 4438 | cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc); | 
|  | 4439 | } else {		/* decode response */ | 
|  | 4440 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 4441 |  | 
|  | 4442 | if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { | 
|  | 4443 | cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n"); | 
|  | 4444 | rc = -EIO;	/* bad smb */ | 
|  | 4445 | } else { | 
|  | 4446 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 4447 | memcpy((char *) pFindData, | 
|  | 4448 | (char *) &pSMBr->hdr.Protocol + | 
|  | 4449 | data_offset, | 
|  | 4450 | sizeof(FILE_UNIX_BASIC_INFO)); | 
|  | 4451 | } | 
|  | 4452 | } | 
|  | 4453 | cifs_buf_release(pSMB); | 
|  | 4454 | if (rc == -EAGAIN) | 
|  | 4455 | goto UnixQPathInfoRetry; | 
|  | 4456 |  | 
|  | 4457 | return rc; | 
|  | 4458 | } | 
|  | 4459 |  | 
|  | 4460 | /* xid, tcon, searchName and codepage are input parms, rest are returned */ | 
|  | 4461 | int | 
|  | 4462 | CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 4463 | const char *searchName, struct cifs_sb_info *cifs_sb, | 
|  | 4464 | __u16 *pnetfid, __u16 search_flags, | 
|  | 4465 | struct cifs_search_info *psrch_inf, bool msearch) | 
|  | 4466 | { | 
|  | 4467 | /* level 257 SMB_ */ | 
|  | 4468 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; | 
|  | 4469 | TRANSACTION2_FFIRST_RSP *pSMBr = NULL; | 
|  | 4470 | T2_FFIRST_RSP_PARMS *parms; | 
|  | 4471 | int rc = 0; | 
|  | 4472 | int bytes_returned = 0; | 
|  | 4473 | int name_len, remap; | 
|  | 4474 | __u16 params, byte_count; | 
|  | 4475 | struct nls_table *nls_codepage; | 
|  | 4476 |  | 
|  | 4477 | cifs_dbg(FYI, "In FindFirst for %s\n", searchName); | 
|  | 4478 |  | 
|  | 4479 | findFirstRetry: | 
|  | 4480 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 4481 | (void **) &pSMBr); | 
|  | 4482 | if (rc) | 
|  | 4483 | return rc; | 
|  | 4484 |  | 
|  | 4485 | nls_codepage = cifs_sb->local_nls; | 
|  | 4486 | remap = cifs_remap(cifs_sb); | 
|  | 4487 |  | 
|  | 4488 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 4489 | name_len = | 
|  | 4490 | cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, | 
|  | 4491 | PATH_MAX, nls_codepage, remap); | 
|  | 4492 | /* We can not add the asterik earlier in case | 
|  | 4493 | it got remapped to 0xF03A as if it were part of the | 
|  | 4494 | directory name instead of a wildcard */ | 
|  | 4495 | name_len *= 2; | 
|  | 4496 | if (msearch) { | 
|  | 4497 | pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb); | 
|  | 4498 | pSMB->FileName[name_len+1] = 0; | 
|  | 4499 | pSMB->FileName[name_len+2] = '*'; | 
|  | 4500 | pSMB->FileName[name_len+3] = 0; | 
|  | 4501 | name_len += 4; /* now the trailing null */ | 
|  | 4502 | /* null terminate just in case */ | 
|  | 4503 | pSMB->FileName[name_len] = 0; | 
|  | 4504 | pSMB->FileName[name_len+1] = 0; | 
|  | 4505 | name_len += 2; | 
|  | 4506 | } | 
|  | 4507 | } else {	/* BB add check for overrun of SMB buf BB */ | 
|  | 4508 | name_len = strnlen(searchName, PATH_MAX); | 
|  | 4509 | /* BB fix here and in unicode clause above ie | 
|  | 4510 | if (name_len > buffersize-header) | 
|  | 4511 | free buffer exit; BB */ | 
|  | 4512 | strncpy(pSMB->FileName, searchName, name_len); | 
|  | 4513 | if (msearch) { | 
|  | 4514 | pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb); | 
|  | 4515 | pSMB->FileName[name_len+1] = '*'; | 
|  | 4516 | pSMB->FileName[name_len+2] = 0; | 
|  | 4517 | name_len += 3; | 
|  | 4518 | } | 
|  | 4519 | } | 
|  | 4520 |  | 
|  | 4521 | params = 12 + name_len /* includes null */ ; | 
|  | 4522 | pSMB->TotalDataCount = 0;	/* no EAs */ | 
|  | 4523 | pSMB->MaxParameterCount = cpu_to_le16(10); | 
|  | 4524 | pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00); | 
|  | 4525 | pSMB->MaxSetupCount = 0; | 
|  | 4526 | pSMB->Reserved = 0; | 
|  | 4527 | pSMB->Flags = 0; | 
|  | 4528 | pSMB->Timeout = 0; | 
|  | 4529 | pSMB->Reserved2 = 0; | 
|  | 4530 | byte_count = params + 1 /* pad */ ; | 
|  | 4531 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 4532 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 4533 | pSMB->ParameterOffset = cpu_to_le16( | 
|  | 4534 | offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) | 
|  | 4535 | - 4); | 
|  | 4536 | pSMB->DataCount = 0; | 
|  | 4537 | pSMB->DataOffset = 0; | 
|  | 4538 | pSMB->SetupCount = 1;	/* one byte, no need to make endian neutral */ | 
|  | 4539 | pSMB->Reserved3 = 0; | 
|  | 4540 | pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); | 
|  | 4541 | pSMB->SearchAttributes = | 
|  | 4542 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | | 
|  | 4543 | ATTR_DIRECTORY); | 
|  | 4544 | pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO)); | 
|  | 4545 | pSMB->SearchFlags = cpu_to_le16(search_flags); | 
|  | 4546 | pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); | 
|  | 4547 |  | 
|  | 4548 | /* BB what should we set StorageType to? Does it matter? BB */ | 
|  | 4549 | pSMB->SearchStorageType = 0; | 
|  | 4550 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 4551 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 4552 |  | 
|  | 4553 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 4554 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 4555 | cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst); | 
|  | 4556 |  | 
|  | 4557 | if (rc) {/* BB add logic to retry regular search if Unix search | 
|  | 4558 | rejected unexpectedly by server */ | 
|  | 4559 | /* BB Add code to handle unsupported level rc */ | 
|  | 4560 | cifs_dbg(FYI, "Error in FindFirst = %d\n", rc); | 
|  | 4561 |  | 
|  | 4562 | cifs_buf_release(pSMB); | 
|  | 4563 |  | 
|  | 4564 | /* BB eventually could optimize out free and realloc of buf */ | 
|  | 4565 | /*    for this case */ | 
|  | 4566 | if (rc == -EAGAIN) | 
|  | 4567 | goto findFirstRetry; | 
|  | 4568 | } else { /* decode response */ | 
|  | 4569 | /* BB remember to free buffer if error BB */ | 
|  | 4570 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 4571 | if (rc == 0) { | 
|  | 4572 | unsigned int lnoff; | 
|  | 4573 |  | 
|  | 4574 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) | 
|  | 4575 | psrch_inf->unicode = true; | 
|  | 4576 | else | 
|  | 4577 | psrch_inf->unicode = false; | 
|  | 4578 |  | 
|  | 4579 | psrch_inf->ntwrk_buf_start = (char *)pSMBr; | 
|  | 4580 | psrch_inf->smallBuf = 0; | 
|  | 4581 | psrch_inf->srch_entries_start = | 
|  | 4582 | (char *) &pSMBr->hdr.Protocol + | 
|  | 4583 | le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 4584 | parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol + | 
|  | 4585 | le16_to_cpu(pSMBr->t2.ParameterOffset)); | 
|  | 4586 |  | 
|  | 4587 | if (parms->EndofSearch) | 
|  | 4588 | psrch_inf->endOfSearch = true; | 
|  | 4589 | else | 
|  | 4590 | psrch_inf->endOfSearch = false; | 
|  | 4591 |  | 
|  | 4592 | psrch_inf->entries_in_buffer = | 
|  | 4593 | le16_to_cpu(parms->SearchCount); | 
|  | 4594 | psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + | 
|  | 4595 | psrch_inf->entries_in_buffer; | 
|  | 4596 | lnoff = le16_to_cpu(parms->LastNameOffset); | 
|  | 4597 | if (CIFSMaxBufSize < lnoff) { | 
|  | 4598 | cifs_dbg(VFS, "ignoring corrupt resume name\n"); | 
|  | 4599 | psrch_inf->last_entry = NULL; | 
|  | 4600 | return rc; | 
|  | 4601 | } | 
|  | 4602 |  | 
|  | 4603 | psrch_inf->last_entry = psrch_inf->srch_entries_start + | 
|  | 4604 | lnoff; | 
|  | 4605 |  | 
|  | 4606 | if (pnetfid) | 
|  | 4607 | *pnetfid = parms->SearchHandle; | 
|  | 4608 | } else { | 
|  | 4609 | cifs_buf_release(pSMB); | 
|  | 4610 | } | 
|  | 4611 | } | 
|  | 4612 |  | 
|  | 4613 | return rc; | 
|  | 4614 | } | 
|  | 4615 |  | 
|  | 4616 | int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 4617 | __u16 searchHandle, __u16 search_flags, | 
|  | 4618 | struct cifs_search_info *psrch_inf) | 
|  | 4619 | { | 
|  | 4620 | TRANSACTION2_FNEXT_REQ *pSMB = NULL; | 
|  | 4621 | TRANSACTION2_FNEXT_RSP *pSMBr = NULL; | 
|  | 4622 | T2_FNEXT_RSP_PARMS *parms; | 
|  | 4623 | char *response_data; | 
|  | 4624 | int rc = 0; | 
|  | 4625 | int bytes_returned; | 
|  | 4626 | unsigned int name_len; | 
|  | 4627 | __u16 params, byte_count; | 
|  | 4628 |  | 
|  | 4629 | cifs_dbg(FYI, "In FindNext\n"); | 
|  | 4630 |  | 
|  | 4631 | if (psrch_inf->endOfSearch) | 
|  | 4632 | return -ENOENT; | 
|  | 4633 |  | 
|  | 4634 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 4635 | (void **) &pSMBr); | 
|  | 4636 | if (rc) | 
|  | 4637 | return rc; | 
|  | 4638 |  | 
|  | 4639 | params = 14; /* includes 2 bytes of null string, converted to LE below*/ | 
|  | 4640 | byte_count = 0; | 
|  | 4641 | pSMB->TotalDataCount = 0;       /* no EAs */ | 
|  | 4642 | pSMB->MaxParameterCount = cpu_to_le16(8); | 
|  | 4643 | pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00); | 
|  | 4644 | pSMB->MaxSetupCount = 0; | 
|  | 4645 | pSMB->Reserved = 0; | 
|  | 4646 | pSMB->Flags = 0; | 
|  | 4647 | pSMB->Timeout = 0; | 
|  | 4648 | pSMB->Reserved2 = 0; | 
|  | 4649 | pSMB->ParameterOffset =  cpu_to_le16( | 
|  | 4650 | offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4); | 
|  | 4651 | pSMB->DataCount = 0; | 
|  | 4652 | pSMB->DataOffset = 0; | 
|  | 4653 | pSMB->SetupCount = 1; | 
|  | 4654 | pSMB->Reserved3 = 0; | 
|  | 4655 | pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT); | 
|  | 4656 | pSMB->SearchHandle = searchHandle;      /* always kept as le */ | 
|  | 4657 | pSMB->SearchCount = | 
|  | 4658 | cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO)); | 
|  | 4659 | pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); | 
|  | 4660 | pSMB->ResumeKey = psrch_inf->resume_key; | 
|  | 4661 | pSMB->SearchFlags = cpu_to_le16(search_flags); | 
|  | 4662 |  | 
|  | 4663 | name_len = psrch_inf->resume_name_len; | 
|  | 4664 | params += name_len; | 
|  | 4665 | if (name_len < PATH_MAX) { | 
|  | 4666 | memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len); | 
|  | 4667 | byte_count += name_len; | 
|  | 4668 | /* 14 byte parm len above enough for 2 byte null terminator */ | 
|  | 4669 | pSMB->ResumeFileName[name_len] = 0; | 
|  | 4670 | pSMB->ResumeFileName[name_len+1] = 0; | 
|  | 4671 | } else { | 
|  | 4672 | rc = -EINVAL; | 
|  | 4673 | goto FNext2_err_exit; | 
|  | 4674 | } | 
|  | 4675 | byte_count = params + 1 /* pad */ ; | 
|  | 4676 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 4677 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 4678 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 4679 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 4680 |  | 
|  | 4681 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 4682 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 4683 | cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext); | 
|  | 4684 | if (rc) { | 
|  | 4685 | if (rc == -EBADF) { | 
|  | 4686 | psrch_inf->endOfSearch = true; | 
|  | 4687 | cifs_buf_release(pSMB); | 
|  | 4688 | rc = 0; /* search probably was closed at end of search*/ | 
|  | 4689 | } else | 
|  | 4690 | cifs_dbg(FYI, "FindNext returned = %d\n", rc); | 
|  | 4691 | } else {                /* decode response */ | 
|  | 4692 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 4693 |  | 
|  | 4694 | if (rc == 0) { | 
|  | 4695 | unsigned int lnoff; | 
|  | 4696 |  | 
|  | 4697 | /* BB fixme add lock for file (srch_info) struct here */ | 
|  | 4698 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) | 
|  | 4699 | psrch_inf->unicode = true; | 
|  | 4700 | else | 
|  | 4701 | psrch_inf->unicode = false; | 
|  | 4702 | response_data = (char *) &pSMBr->hdr.Protocol + | 
|  | 4703 | le16_to_cpu(pSMBr->t2.ParameterOffset); | 
|  | 4704 | parms = (T2_FNEXT_RSP_PARMS *)response_data; | 
|  | 4705 | response_data = (char *)&pSMBr->hdr.Protocol + | 
|  | 4706 | le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 4707 | if (psrch_inf->smallBuf) | 
|  | 4708 | cifs_small_buf_release( | 
|  | 4709 | psrch_inf->ntwrk_buf_start); | 
|  | 4710 | else | 
|  | 4711 | cifs_buf_release(psrch_inf->ntwrk_buf_start); | 
|  | 4712 | psrch_inf->srch_entries_start = response_data; | 
|  | 4713 | psrch_inf->ntwrk_buf_start = (char *)pSMB; | 
|  | 4714 | psrch_inf->smallBuf = 0; | 
|  | 4715 | if (parms->EndofSearch) | 
|  | 4716 | psrch_inf->endOfSearch = true; | 
|  | 4717 | else | 
|  | 4718 | psrch_inf->endOfSearch = false; | 
|  | 4719 | psrch_inf->entries_in_buffer = | 
|  | 4720 | le16_to_cpu(parms->SearchCount); | 
|  | 4721 | psrch_inf->index_of_last_entry += | 
|  | 4722 | psrch_inf->entries_in_buffer; | 
|  | 4723 | lnoff = le16_to_cpu(parms->LastNameOffset); | 
|  | 4724 | if (CIFSMaxBufSize < lnoff) { | 
|  | 4725 | cifs_dbg(VFS, "ignoring corrupt resume name\n"); | 
|  | 4726 | psrch_inf->last_entry = NULL; | 
|  | 4727 | return rc; | 
|  | 4728 | } else | 
|  | 4729 | psrch_inf->last_entry = | 
|  | 4730 | psrch_inf->srch_entries_start + lnoff; | 
|  | 4731 |  | 
|  | 4732 | /*  cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n", | 
|  | 4733 | psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */ | 
|  | 4734 |  | 
|  | 4735 | /* BB fixme add unlock here */ | 
|  | 4736 | } | 
|  | 4737 |  | 
|  | 4738 | } | 
|  | 4739 |  | 
|  | 4740 | /* BB On error, should we leave previous search buf (and count and | 
|  | 4741 | last entry fields) intact or free the previous one? */ | 
|  | 4742 |  | 
|  | 4743 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 4744 | since file handle passed in no longer valid */ | 
|  | 4745 | FNext2_err_exit: | 
|  | 4746 | if (rc != 0) | 
|  | 4747 | cifs_buf_release(pSMB); | 
|  | 4748 | return rc; | 
|  | 4749 | } | 
|  | 4750 |  | 
|  | 4751 | int | 
|  | 4752 | CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 4753 | const __u16 searchHandle) | 
|  | 4754 | { | 
|  | 4755 | int rc = 0; | 
|  | 4756 | FINDCLOSE_REQ *pSMB = NULL; | 
|  | 4757 |  | 
|  | 4758 | cifs_dbg(FYI, "In CIFSSMBFindClose\n"); | 
|  | 4759 | rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB); | 
|  | 4760 |  | 
|  | 4761 | /* no sense returning error if session restarted | 
|  | 4762 | as file handle has been closed */ | 
|  | 4763 | if (rc == -EAGAIN) | 
|  | 4764 | return 0; | 
|  | 4765 | if (rc) | 
|  | 4766 | return rc; | 
|  | 4767 |  | 
|  | 4768 | pSMB->FileID = searchHandle; | 
|  | 4769 | pSMB->ByteCount = 0; | 
|  | 4770 | rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); | 
|  | 4771 | cifs_small_buf_release(pSMB); | 
|  | 4772 | if (rc) | 
|  | 4773 | cifs_dbg(VFS, "Send error in FindClose = %d\n", rc); | 
|  | 4774 |  | 
|  | 4775 | cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose); | 
|  | 4776 |  | 
|  | 4777 | /* Since session is dead, search handle closed on server already */ | 
|  | 4778 | if (rc == -EAGAIN) | 
|  | 4779 | rc = 0; | 
|  | 4780 |  | 
|  | 4781 | return rc; | 
|  | 4782 | } | 
|  | 4783 |  | 
|  | 4784 | int | 
|  | 4785 | CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 4786 | const char *search_name, __u64 *inode_number, | 
|  | 4787 | const struct nls_table *nls_codepage, int remap) | 
|  | 4788 | { | 
|  | 4789 | int rc = 0; | 
|  | 4790 | TRANSACTION2_QPI_REQ *pSMB = NULL; | 
|  | 4791 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | 
|  | 4792 | int name_len, bytes_returned; | 
|  | 4793 | __u16 params, byte_count; | 
|  | 4794 |  | 
|  | 4795 | cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name); | 
|  | 4796 | if (tcon == NULL) | 
|  | 4797 | return -ENODEV; | 
|  | 4798 |  | 
|  | 4799 | GetInodeNumberRetry: | 
|  | 4800 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 4801 | (void **) &pSMBr); | 
|  | 4802 | if (rc) | 
|  | 4803 | return rc; | 
|  | 4804 |  | 
|  | 4805 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 4806 | name_len = | 
|  | 4807 | cifsConvertToUTF16((__le16 *) pSMB->FileName, | 
|  | 4808 | search_name, PATH_MAX, nls_codepage, | 
|  | 4809 | remap); | 
|  | 4810 | name_len++;     /* trailing null */ | 
|  | 4811 | name_len *= 2; | 
|  | 4812 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 4813 | name_len = strnlen(search_name, PATH_MAX); | 
|  | 4814 | name_len++;     /* trailing null */ | 
|  | 4815 | strncpy(pSMB->FileName, search_name, name_len); | 
|  | 4816 | } | 
|  | 4817 |  | 
|  | 4818 | params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ; | 
|  | 4819 | pSMB->TotalDataCount = 0; | 
|  | 4820 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 4821 | /* BB find exact max data count below from sess structure BB */ | 
|  | 4822 | pSMB->MaxDataCount = cpu_to_le16(4000); | 
|  | 4823 | pSMB->MaxSetupCount = 0; | 
|  | 4824 | pSMB->Reserved = 0; | 
|  | 4825 | pSMB->Flags = 0; | 
|  | 4826 | pSMB->Timeout = 0; | 
|  | 4827 | pSMB->Reserved2 = 0; | 
|  | 4828 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | 
|  | 4829 | struct smb_com_transaction2_qpi_req, InformationLevel) - 4); | 
|  | 4830 | pSMB->DataCount = 0; | 
|  | 4831 | pSMB->DataOffset = 0; | 
|  | 4832 | pSMB->SetupCount = 1; | 
|  | 4833 | pSMB->Reserved3 = 0; | 
|  | 4834 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | 
|  | 4835 | byte_count = params + 1 /* pad */ ; | 
|  | 4836 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 4837 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 4838 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO); | 
|  | 4839 | pSMB->Reserved4 = 0; | 
|  | 4840 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 4841 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 4842 |  | 
|  | 4843 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 4844 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 4845 | if (rc) { | 
|  | 4846 | cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc); | 
|  | 4847 | } else { | 
|  | 4848 | /* decode response */ | 
|  | 4849 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 4850 | /* BB also check enough total bytes returned */ | 
|  | 4851 | if (rc || get_bcc(&pSMBr->hdr) < 2) | 
|  | 4852 | /* If rc should we check for EOPNOSUPP and | 
|  | 4853 | disable the srvino flag? or in caller? */ | 
|  | 4854 | rc = -EIO;      /* bad smb */ | 
|  | 4855 | else { | 
|  | 4856 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 4857 | __u16 count = le16_to_cpu(pSMBr->t2.DataCount); | 
|  | 4858 | struct file_internal_info *pfinfo; | 
|  | 4859 | /* BB Do we need a cast or hash here ? */ | 
|  | 4860 | if (count < 8) { | 
|  | 4861 | cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n"); | 
|  | 4862 | rc = -EIO; | 
|  | 4863 | goto GetInodeNumOut; | 
|  | 4864 | } | 
|  | 4865 | pfinfo = (struct file_internal_info *) | 
|  | 4866 | (data_offset + (char *) &pSMBr->hdr.Protocol); | 
|  | 4867 | *inode_number = le64_to_cpu(pfinfo->UniqueId); | 
|  | 4868 | } | 
|  | 4869 | } | 
|  | 4870 | GetInodeNumOut: | 
|  | 4871 | cifs_buf_release(pSMB); | 
|  | 4872 | if (rc == -EAGAIN) | 
|  | 4873 | goto GetInodeNumberRetry; | 
|  | 4874 | return rc; | 
|  | 4875 | } | 
|  | 4876 |  | 
|  | 4877 | int | 
|  | 4878 | CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, | 
|  | 4879 | const char *search_name, struct dfs_info3_param **target_nodes, | 
|  | 4880 | unsigned int *num_of_nodes, | 
|  | 4881 | const struct nls_table *nls_codepage, int remap) | 
|  | 4882 | { | 
|  | 4883 | /* TRANS2_GET_DFS_REFERRAL */ | 
|  | 4884 | TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; | 
|  | 4885 | TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; | 
|  | 4886 | int rc = 0; | 
|  | 4887 | int bytes_returned; | 
|  | 4888 | int name_len; | 
|  | 4889 | __u16 params, byte_count; | 
|  | 4890 | *num_of_nodes = 0; | 
|  | 4891 | *target_nodes = NULL; | 
|  | 4892 |  | 
|  | 4893 | cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name); | 
|  | 4894 | if (ses == NULL || ses->tcon_ipc == NULL) | 
|  | 4895 | return -ENODEV; | 
|  | 4896 |  | 
|  | 4897 | getDFSRetry: | 
|  | 4898 | rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB, | 
|  | 4899 | (void **) &pSMBr); | 
|  | 4900 | if (rc) | 
|  | 4901 | return rc; | 
|  | 4902 |  | 
|  | 4903 | /* server pointer checked in called function, | 
|  | 4904 | but should never be null here anyway */ | 
|  | 4905 | pSMB->hdr.Mid = get_next_mid(ses->server); | 
|  | 4906 | pSMB->hdr.Tid = ses->tcon_ipc->tid; | 
|  | 4907 | pSMB->hdr.Uid = ses->Suid; | 
|  | 4908 | if (ses->capabilities & CAP_STATUS32) | 
|  | 4909 | pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS; | 
|  | 4910 | if (ses->capabilities & CAP_DFS) | 
|  | 4911 | pSMB->hdr.Flags2 |= SMBFLG2_DFS; | 
|  | 4912 |  | 
|  | 4913 | if (ses->capabilities & CAP_UNICODE) { | 
|  | 4914 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 
|  | 4915 | name_len = | 
|  | 4916 | cifsConvertToUTF16((__le16 *) pSMB->RequestFileName, | 
|  | 4917 | search_name, PATH_MAX, nls_codepage, | 
|  | 4918 | remap); | 
|  | 4919 | name_len++;	/* trailing null */ | 
|  | 4920 | name_len *= 2; | 
|  | 4921 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 4922 | name_len = strnlen(search_name, PATH_MAX); | 
|  | 4923 | name_len++;	/* trailing null */ | 
|  | 4924 | strncpy(pSMB->RequestFileName, search_name, name_len); | 
|  | 4925 | } | 
|  | 4926 |  | 
|  | 4927 | if (ses->server->sign) | 
|  | 4928 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 
|  | 4929 |  | 
|  | 4930 | pSMB->hdr.Uid = ses->Suid; | 
|  | 4931 |  | 
|  | 4932 | params = 2 /* level */  + name_len /*includes null */ ; | 
|  | 4933 | pSMB->TotalDataCount = 0; | 
|  | 4934 | pSMB->DataCount = 0; | 
|  | 4935 | pSMB->DataOffset = 0; | 
|  | 4936 | pSMB->MaxParameterCount = 0; | 
|  | 4937 | /* BB find exact max SMB PDU from sess structure BB */ | 
|  | 4938 | pSMB->MaxDataCount = cpu_to_le16(4000); | 
|  | 4939 | pSMB->MaxSetupCount = 0; | 
|  | 4940 | pSMB->Reserved = 0; | 
|  | 4941 | pSMB->Flags = 0; | 
|  | 4942 | pSMB->Timeout = 0; | 
|  | 4943 | pSMB->Reserved2 = 0; | 
|  | 4944 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | 
|  | 4945 | struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4); | 
|  | 4946 | pSMB->SetupCount = 1; | 
|  | 4947 | pSMB->Reserved3 = 0; | 
|  | 4948 | pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL); | 
|  | 4949 | byte_count = params + 3 /* pad */ ; | 
|  | 4950 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 4951 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 4952 | pSMB->MaxReferralLevel = cpu_to_le16(3); | 
|  | 4953 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 4954 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 4955 |  | 
|  | 4956 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | 
|  | 4957 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 4958 | if (rc) { | 
|  | 4959 | cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc); | 
|  | 4960 | goto GetDFSRefExit; | 
|  | 4961 | } | 
|  | 4962 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 4963 |  | 
|  | 4964 | /* BB Also check if enough total bytes returned? */ | 
|  | 4965 | if (rc || get_bcc(&pSMBr->hdr) < 17) { | 
|  | 4966 | rc = -EIO;      /* bad smb */ | 
|  | 4967 | goto GetDFSRefExit; | 
|  | 4968 | } | 
|  | 4969 |  | 
|  | 4970 | cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d  Offset %d\n", | 
|  | 4971 | get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset)); | 
|  | 4972 |  | 
|  | 4973 | /* parse returned result into more usable form */ | 
|  | 4974 | rc = parse_dfs_referrals(&pSMBr->dfs_data, | 
|  | 4975 | le16_to_cpu(pSMBr->t2.DataCount), | 
|  | 4976 | num_of_nodes, target_nodes, nls_codepage, | 
|  | 4977 | remap, search_name, | 
|  | 4978 | (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0); | 
|  | 4979 |  | 
|  | 4980 | GetDFSRefExit: | 
|  | 4981 | cifs_buf_release(pSMB); | 
|  | 4982 |  | 
|  | 4983 | if (rc == -EAGAIN) | 
|  | 4984 | goto getDFSRetry; | 
|  | 4985 |  | 
|  | 4986 | return rc; | 
|  | 4987 | } | 
|  | 4988 |  | 
|  | 4989 | /* Query File System Info such as free space to old servers such as Win 9x */ | 
|  | 4990 | int | 
|  | 4991 | SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 4992 | struct kstatfs *FSData) | 
|  | 4993 | { | 
|  | 4994 | /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */ | 
|  | 4995 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | 
|  | 4996 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | 
|  | 4997 | FILE_SYSTEM_ALLOC_INFO *response_data; | 
|  | 4998 | int rc = 0; | 
|  | 4999 | int bytes_returned = 0; | 
|  | 5000 | __u16 params, byte_count; | 
|  | 5001 |  | 
|  | 5002 | cifs_dbg(FYI, "OldQFSInfo\n"); | 
|  | 5003 | oldQFSInfoRetry: | 
|  | 5004 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 5005 | (void **) &pSMBr); | 
|  | 5006 | if (rc) | 
|  | 5007 | return rc; | 
|  | 5008 |  | 
|  | 5009 | params = 2;     /* level */ | 
|  | 5010 | pSMB->TotalDataCount = 0; | 
|  | 5011 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 5012 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 5013 | pSMB->MaxSetupCount = 0; | 
|  | 5014 | pSMB->Reserved = 0; | 
|  | 5015 | pSMB->Flags = 0; | 
|  | 5016 | pSMB->Timeout = 0; | 
|  | 5017 | pSMB->Reserved2 = 0; | 
|  | 5018 | byte_count = params + 1 /* pad */ ; | 
|  | 5019 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 5020 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 5021 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | 
|  | 5022 | struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); | 
|  | 5023 | pSMB->DataCount = 0; | 
|  | 5024 | pSMB->DataOffset = 0; | 
|  | 5025 | pSMB->SetupCount = 1; | 
|  | 5026 | pSMB->Reserved3 = 0; | 
|  | 5027 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 
|  | 5028 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION); | 
|  | 5029 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5030 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5031 |  | 
|  | 5032 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 5033 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 5034 | if (rc) { | 
|  | 5035 | cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc); | 
|  | 5036 | } else {                /* decode response */ | 
|  | 5037 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 5038 |  | 
|  | 5039 | if (rc || get_bcc(&pSMBr->hdr) < 18) | 
|  | 5040 | rc = -EIO;      /* bad smb */ | 
|  | 5041 | else { | 
|  | 5042 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 5043 | cifs_dbg(FYI, "qfsinf resp BCC: %d  Offset %d\n", | 
|  | 5044 | get_bcc(&pSMBr->hdr), data_offset); | 
|  | 5045 |  | 
|  | 5046 | response_data = (FILE_SYSTEM_ALLOC_INFO *) | 
|  | 5047 | (((char *) &pSMBr->hdr.Protocol) + data_offset); | 
|  | 5048 | FSData->f_bsize = | 
|  | 5049 | le16_to_cpu(response_data->BytesPerSector) * | 
|  | 5050 | le32_to_cpu(response_data-> | 
|  | 5051 | SectorsPerAllocationUnit); | 
|  | 5052 | FSData->f_blocks = | 
|  | 5053 | le32_to_cpu(response_data->TotalAllocationUnits); | 
|  | 5054 | FSData->f_bfree = FSData->f_bavail = | 
|  | 5055 | le32_to_cpu(response_data->FreeAllocationUnits); | 
|  | 5056 | cifs_dbg(FYI, "Blocks: %lld  Free: %lld Block size %ld\n", | 
|  | 5057 | (unsigned long long)FSData->f_blocks, | 
|  | 5058 | (unsigned long long)FSData->f_bfree, | 
|  | 5059 | FSData->f_bsize); | 
|  | 5060 | } | 
|  | 5061 | } | 
|  | 5062 | cifs_buf_release(pSMB); | 
|  | 5063 |  | 
|  | 5064 | if (rc == -EAGAIN) | 
|  | 5065 | goto oldQFSInfoRetry; | 
|  | 5066 |  | 
|  | 5067 | return rc; | 
|  | 5068 | } | 
|  | 5069 |  | 
|  | 5070 | int | 
|  | 5071 | CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 5072 | struct kstatfs *FSData) | 
|  | 5073 | { | 
|  | 5074 | /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ | 
|  | 5075 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | 
|  | 5076 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | 
|  | 5077 | FILE_SYSTEM_INFO *response_data; | 
|  | 5078 | int rc = 0; | 
|  | 5079 | int bytes_returned = 0; | 
|  | 5080 | __u16 params, byte_count; | 
|  | 5081 |  | 
|  | 5082 | cifs_dbg(FYI, "In QFSInfo\n"); | 
|  | 5083 | QFSInfoRetry: | 
|  | 5084 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 5085 | (void **) &pSMBr); | 
|  | 5086 | if (rc) | 
|  | 5087 | return rc; | 
|  | 5088 |  | 
|  | 5089 | params = 2;	/* level */ | 
|  | 5090 | pSMB->TotalDataCount = 0; | 
|  | 5091 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 5092 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 5093 | pSMB->MaxSetupCount = 0; | 
|  | 5094 | pSMB->Reserved = 0; | 
|  | 5095 | pSMB->Flags = 0; | 
|  | 5096 | pSMB->Timeout = 0; | 
|  | 5097 | pSMB->Reserved2 = 0; | 
|  | 5098 | byte_count = params + 1 /* pad */ ; | 
|  | 5099 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 5100 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 5101 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | 
|  | 5102 | struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); | 
|  | 5103 | pSMB->DataCount = 0; | 
|  | 5104 | pSMB->DataOffset = 0; | 
|  | 5105 | pSMB->SetupCount = 1; | 
|  | 5106 | pSMB->Reserved3 = 0; | 
|  | 5107 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 
|  | 5108 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); | 
|  | 5109 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5110 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5111 |  | 
|  | 5112 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 5113 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 5114 | if (rc) { | 
|  | 5115 | cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc); | 
|  | 5116 | } else {		/* decode response */ | 
|  | 5117 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 5118 |  | 
|  | 5119 | if (rc || get_bcc(&pSMBr->hdr) < 24) | 
|  | 5120 | rc = -EIO;	/* bad smb */ | 
|  | 5121 | else { | 
|  | 5122 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 5123 |  | 
|  | 5124 | response_data = | 
|  | 5125 | (FILE_SYSTEM_INFO | 
|  | 5126 | *) (((char *) &pSMBr->hdr.Protocol) + | 
|  | 5127 | data_offset); | 
|  | 5128 | FSData->f_bsize = | 
|  | 5129 | le32_to_cpu(response_data->BytesPerSector) * | 
|  | 5130 | le32_to_cpu(response_data-> | 
|  | 5131 | SectorsPerAllocationUnit); | 
|  | 5132 | FSData->f_blocks = | 
|  | 5133 | le64_to_cpu(response_data->TotalAllocationUnits); | 
|  | 5134 | FSData->f_bfree = FSData->f_bavail = | 
|  | 5135 | le64_to_cpu(response_data->FreeAllocationUnits); | 
|  | 5136 | cifs_dbg(FYI, "Blocks: %lld  Free: %lld Block size %ld\n", | 
|  | 5137 | (unsigned long long)FSData->f_blocks, | 
|  | 5138 | (unsigned long long)FSData->f_bfree, | 
|  | 5139 | FSData->f_bsize); | 
|  | 5140 | } | 
|  | 5141 | } | 
|  | 5142 | cifs_buf_release(pSMB); | 
|  | 5143 |  | 
|  | 5144 | if (rc == -EAGAIN) | 
|  | 5145 | goto QFSInfoRetry; | 
|  | 5146 |  | 
|  | 5147 | return rc; | 
|  | 5148 | } | 
|  | 5149 |  | 
|  | 5150 | int | 
|  | 5151 | CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon) | 
|  | 5152 | { | 
|  | 5153 | /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */ | 
|  | 5154 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | 
|  | 5155 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | 
|  | 5156 | FILE_SYSTEM_ATTRIBUTE_INFO *response_data; | 
|  | 5157 | int rc = 0; | 
|  | 5158 | int bytes_returned = 0; | 
|  | 5159 | __u16 params, byte_count; | 
|  | 5160 |  | 
|  | 5161 | cifs_dbg(FYI, "In QFSAttributeInfo\n"); | 
|  | 5162 | QFSAttributeRetry: | 
|  | 5163 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 5164 | (void **) &pSMBr); | 
|  | 5165 | if (rc) | 
|  | 5166 | return rc; | 
|  | 5167 |  | 
|  | 5168 | params = 2;	/* level */ | 
|  | 5169 | pSMB->TotalDataCount = 0; | 
|  | 5170 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 5171 | /* BB find exact max SMB PDU from sess structure BB */ | 
|  | 5172 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 5173 | pSMB->MaxSetupCount = 0; | 
|  | 5174 | pSMB->Reserved = 0; | 
|  | 5175 | pSMB->Flags = 0; | 
|  | 5176 | pSMB->Timeout = 0; | 
|  | 5177 | pSMB->Reserved2 = 0; | 
|  | 5178 | byte_count = params + 1 /* pad */ ; | 
|  | 5179 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 5180 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 5181 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | 
|  | 5182 | struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); | 
|  | 5183 | pSMB->DataCount = 0; | 
|  | 5184 | pSMB->DataOffset = 0; | 
|  | 5185 | pSMB->SetupCount = 1; | 
|  | 5186 | pSMB->Reserved3 = 0; | 
|  | 5187 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 
|  | 5188 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); | 
|  | 5189 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5190 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5191 |  | 
|  | 5192 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 5193 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 5194 | if (rc) { | 
|  | 5195 | cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc); | 
|  | 5196 | } else {		/* decode response */ | 
|  | 5197 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 5198 |  | 
|  | 5199 | if (rc || get_bcc(&pSMBr->hdr) < 13) { | 
|  | 5200 | /* BB also check if enough bytes returned */ | 
|  | 5201 | rc = -EIO;	/* bad smb */ | 
|  | 5202 | } else { | 
|  | 5203 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 5204 | response_data = | 
|  | 5205 | (FILE_SYSTEM_ATTRIBUTE_INFO | 
|  | 5206 | *) (((char *) &pSMBr->hdr.Protocol) + | 
|  | 5207 | data_offset); | 
|  | 5208 | memcpy(&tcon->fsAttrInfo, response_data, | 
|  | 5209 | sizeof(FILE_SYSTEM_ATTRIBUTE_INFO)); | 
|  | 5210 | } | 
|  | 5211 | } | 
|  | 5212 | cifs_buf_release(pSMB); | 
|  | 5213 |  | 
|  | 5214 | if (rc == -EAGAIN) | 
|  | 5215 | goto QFSAttributeRetry; | 
|  | 5216 |  | 
|  | 5217 | return rc; | 
|  | 5218 | } | 
|  | 5219 |  | 
|  | 5220 | int | 
|  | 5221 | CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon) | 
|  | 5222 | { | 
|  | 5223 | /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ | 
|  | 5224 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | 
|  | 5225 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | 
|  | 5226 | FILE_SYSTEM_DEVICE_INFO *response_data; | 
|  | 5227 | int rc = 0; | 
|  | 5228 | int bytes_returned = 0; | 
|  | 5229 | __u16 params, byte_count; | 
|  | 5230 |  | 
|  | 5231 | cifs_dbg(FYI, "In QFSDeviceInfo\n"); | 
|  | 5232 | QFSDeviceRetry: | 
|  | 5233 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 5234 | (void **) &pSMBr); | 
|  | 5235 | if (rc) | 
|  | 5236 | return rc; | 
|  | 5237 |  | 
|  | 5238 | params = 2;	/* level */ | 
|  | 5239 | pSMB->TotalDataCount = 0; | 
|  | 5240 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 5241 | /* BB find exact max SMB PDU from sess structure BB */ | 
|  | 5242 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 5243 | pSMB->MaxSetupCount = 0; | 
|  | 5244 | pSMB->Reserved = 0; | 
|  | 5245 | pSMB->Flags = 0; | 
|  | 5246 | pSMB->Timeout = 0; | 
|  | 5247 | pSMB->Reserved2 = 0; | 
|  | 5248 | byte_count = params + 1 /* pad */ ; | 
|  | 5249 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 5250 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 5251 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | 
|  | 5252 | struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); | 
|  | 5253 |  | 
|  | 5254 | pSMB->DataCount = 0; | 
|  | 5255 | pSMB->DataOffset = 0; | 
|  | 5256 | pSMB->SetupCount = 1; | 
|  | 5257 | pSMB->Reserved3 = 0; | 
|  | 5258 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 
|  | 5259 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); | 
|  | 5260 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5261 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5262 |  | 
|  | 5263 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 5264 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 5265 | if (rc) { | 
|  | 5266 | cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc); | 
|  | 5267 | } else {		/* decode response */ | 
|  | 5268 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 5269 |  | 
|  | 5270 | if (rc || get_bcc(&pSMBr->hdr) < | 
|  | 5271 | sizeof(FILE_SYSTEM_DEVICE_INFO)) | 
|  | 5272 | rc = -EIO;	/* bad smb */ | 
|  | 5273 | else { | 
|  | 5274 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 5275 | response_data = | 
|  | 5276 | (FILE_SYSTEM_DEVICE_INFO *) | 
|  | 5277 | (((char *) &pSMBr->hdr.Protocol) + | 
|  | 5278 | data_offset); | 
|  | 5279 | memcpy(&tcon->fsDevInfo, response_data, | 
|  | 5280 | sizeof(FILE_SYSTEM_DEVICE_INFO)); | 
|  | 5281 | } | 
|  | 5282 | } | 
|  | 5283 | cifs_buf_release(pSMB); | 
|  | 5284 |  | 
|  | 5285 | if (rc == -EAGAIN) | 
|  | 5286 | goto QFSDeviceRetry; | 
|  | 5287 |  | 
|  | 5288 | return rc; | 
|  | 5289 | } | 
|  | 5290 |  | 
|  | 5291 | int | 
|  | 5292 | CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon) | 
|  | 5293 | { | 
|  | 5294 | /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */ | 
|  | 5295 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | 
|  | 5296 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | 
|  | 5297 | FILE_SYSTEM_UNIX_INFO *response_data; | 
|  | 5298 | int rc = 0; | 
|  | 5299 | int bytes_returned = 0; | 
|  | 5300 | __u16 params, byte_count; | 
|  | 5301 |  | 
|  | 5302 | cifs_dbg(FYI, "In QFSUnixInfo\n"); | 
|  | 5303 | QFSUnixRetry: | 
|  | 5304 | rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon, | 
|  | 5305 | (void **) &pSMB, (void **) &pSMBr); | 
|  | 5306 | if (rc) | 
|  | 5307 | return rc; | 
|  | 5308 |  | 
|  | 5309 | params = 2;	/* level */ | 
|  | 5310 | pSMB->TotalDataCount = 0; | 
|  | 5311 | pSMB->DataCount = 0; | 
|  | 5312 | pSMB->DataOffset = 0; | 
|  | 5313 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 5314 | /* BB find exact max SMB PDU from sess structure BB */ | 
|  | 5315 | pSMB->MaxDataCount = cpu_to_le16(100); | 
|  | 5316 | pSMB->MaxSetupCount = 0; | 
|  | 5317 | pSMB->Reserved = 0; | 
|  | 5318 | pSMB->Flags = 0; | 
|  | 5319 | pSMB->Timeout = 0; | 
|  | 5320 | pSMB->Reserved2 = 0; | 
|  | 5321 | byte_count = params + 1 /* pad */ ; | 
|  | 5322 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 5323 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 5324 | pSMB->ParameterOffset = cpu_to_le16(offsetof(struct | 
|  | 5325 | smb_com_transaction2_qfsi_req, InformationLevel) - 4); | 
|  | 5326 | pSMB->SetupCount = 1; | 
|  | 5327 | pSMB->Reserved3 = 0; | 
|  | 5328 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 
|  | 5329 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); | 
|  | 5330 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5331 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5332 |  | 
|  | 5333 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 5334 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 5335 | if (rc) { | 
|  | 5336 | cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc); | 
|  | 5337 | } else {		/* decode response */ | 
|  | 5338 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 5339 |  | 
|  | 5340 | if (rc || get_bcc(&pSMBr->hdr) < 13) { | 
|  | 5341 | rc = -EIO;	/* bad smb */ | 
|  | 5342 | } else { | 
|  | 5343 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 5344 | response_data = | 
|  | 5345 | (FILE_SYSTEM_UNIX_INFO | 
|  | 5346 | *) (((char *) &pSMBr->hdr.Protocol) + | 
|  | 5347 | data_offset); | 
|  | 5348 | memcpy(&tcon->fsUnixInfo, response_data, | 
|  | 5349 | sizeof(FILE_SYSTEM_UNIX_INFO)); | 
|  | 5350 | } | 
|  | 5351 | } | 
|  | 5352 | cifs_buf_release(pSMB); | 
|  | 5353 |  | 
|  | 5354 | if (rc == -EAGAIN) | 
|  | 5355 | goto QFSUnixRetry; | 
|  | 5356 |  | 
|  | 5357 |  | 
|  | 5358 | return rc; | 
|  | 5359 | } | 
|  | 5360 |  | 
|  | 5361 | int | 
|  | 5362 | CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap) | 
|  | 5363 | { | 
|  | 5364 | /* level 0x200  SMB_SET_CIFS_UNIX_INFO */ | 
|  | 5365 | TRANSACTION2_SETFSI_REQ *pSMB = NULL; | 
|  | 5366 | TRANSACTION2_SETFSI_RSP *pSMBr = NULL; | 
|  | 5367 | int rc = 0; | 
|  | 5368 | int bytes_returned = 0; | 
|  | 5369 | __u16 params, param_offset, offset, byte_count; | 
|  | 5370 |  | 
|  | 5371 | cifs_dbg(FYI, "In SETFSUnixInfo\n"); | 
|  | 5372 | SETFSUnixRetry: | 
|  | 5373 | /* BB switch to small buf init to save memory */ | 
|  | 5374 | rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon, | 
|  | 5375 | (void **) &pSMB, (void **) &pSMBr); | 
|  | 5376 | if (rc) | 
|  | 5377 | return rc; | 
|  | 5378 |  | 
|  | 5379 | params = 4;	/* 2 bytes zero followed by info level. */ | 
|  | 5380 | pSMB->MaxSetupCount = 0; | 
|  | 5381 | pSMB->Reserved = 0; | 
|  | 5382 | pSMB->Flags = 0; | 
|  | 5383 | pSMB->Timeout = 0; | 
|  | 5384 | pSMB->Reserved2 = 0; | 
|  | 5385 | param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) | 
|  | 5386 | - 4; | 
|  | 5387 | offset = param_offset + params; | 
|  | 5388 |  | 
|  | 5389 | pSMB->MaxParameterCount = cpu_to_le16(4); | 
|  | 5390 | /* BB find exact max SMB PDU from sess structure BB */ | 
|  | 5391 | pSMB->MaxDataCount = cpu_to_le16(100); | 
|  | 5392 | pSMB->SetupCount = 1; | 
|  | 5393 | pSMB->Reserved3 = 0; | 
|  | 5394 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); | 
|  | 5395 | byte_count = 1 /* pad */ + params + 12; | 
|  | 5396 |  | 
|  | 5397 | pSMB->DataCount = cpu_to_le16(12); | 
|  | 5398 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 5399 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 5400 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 5401 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 5402 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 5403 |  | 
|  | 5404 | /* Params. */ | 
|  | 5405 | pSMB->FileNum = 0; | 
|  | 5406 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO); | 
|  | 5407 |  | 
|  | 5408 | /* Data. */ | 
|  | 5409 | pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION); | 
|  | 5410 | pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); | 
|  | 5411 | pSMB->ClientUnixCap = cpu_to_le64(cap); | 
|  | 5412 |  | 
|  | 5413 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5414 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5415 |  | 
|  | 5416 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 5417 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 5418 | if (rc) { | 
|  | 5419 | cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc); | 
|  | 5420 | } else {		/* decode response */ | 
|  | 5421 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 5422 | if (rc) | 
|  | 5423 | rc = -EIO;	/* bad smb */ | 
|  | 5424 | } | 
|  | 5425 | cifs_buf_release(pSMB); | 
|  | 5426 |  | 
|  | 5427 | if (rc == -EAGAIN) | 
|  | 5428 | goto SETFSUnixRetry; | 
|  | 5429 |  | 
|  | 5430 | return rc; | 
|  | 5431 | } | 
|  | 5432 |  | 
|  | 5433 |  | 
|  | 5434 |  | 
|  | 5435 | int | 
|  | 5436 | CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 5437 | struct kstatfs *FSData) | 
|  | 5438 | { | 
|  | 5439 | /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */ | 
|  | 5440 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | 
|  | 5441 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | 
|  | 5442 | FILE_SYSTEM_POSIX_INFO *response_data; | 
|  | 5443 | int rc = 0; | 
|  | 5444 | int bytes_returned = 0; | 
|  | 5445 | __u16 params, byte_count; | 
|  | 5446 |  | 
|  | 5447 | cifs_dbg(FYI, "In QFSPosixInfo\n"); | 
|  | 5448 | QFSPosixRetry: | 
|  | 5449 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 5450 | (void **) &pSMBr); | 
|  | 5451 | if (rc) | 
|  | 5452 | return rc; | 
|  | 5453 |  | 
|  | 5454 | params = 2;	/* level */ | 
|  | 5455 | pSMB->TotalDataCount = 0; | 
|  | 5456 | pSMB->DataCount = 0; | 
|  | 5457 | pSMB->DataOffset = 0; | 
|  | 5458 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 5459 | /* BB find exact max SMB PDU from sess structure BB */ | 
|  | 5460 | pSMB->MaxDataCount = cpu_to_le16(100); | 
|  | 5461 | pSMB->MaxSetupCount = 0; | 
|  | 5462 | pSMB->Reserved = 0; | 
|  | 5463 | pSMB->Flags = 0; | 
|  | 5464 | pSMB->Timeout = 0; | 
|  | 5465 | pSMB->Reserved2 = 0; | 
|  | 5466 | byte_count = params + 1 /* pad */ ; | 
|  | 5467 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 5468 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 5469 | pSMB->ParameterOffset = cpu_to_le16(offsetof(struct | 
|  | 5470 | smb_com_transaction2_qfsi_req, InformationLevel) - 4); | 
|  | 5471 | pSMB->SetupCount = 1; | 
|  | 5472 | pSMB->Reserved3 = 0; | 
|  | 5473 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 
|  | 5474 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO); | 
|  | 5475 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5476 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5477 |  | 
|  | 5478 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 5479 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 5480 | if (rc) { | 
|  | 5481 | cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc); | 
|  | 5482 | } else {		/* decode response */ | 
|  | 5483 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 5484 |  | 
|  | 5485 | if (rc || get_bcc(&pSMBr->hdr) < 13) { | 
|  | 5486 | rc = -EIO;	/* bad smb */ | 
|  | 5487 | } else { | 
|  | 5488 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 5489 | response_data = | 
|  | 5490 | (FILE_SYSTEM_POSIX_INFO | 
|  | 5491 | *) (((char *) &pSMBr->hdr.Protocol) + | 
|  | 5492 | data_offset); | 
|  | 5493 | FSData->f_bsize = | 
|  | 5494 | le32_to_cpu(response_data->BlockSize); | 
|  | 5495 | FSData->f_blocks = | 
|  | 5496 | le64_to_cpu(response_data->TotalBlocks); | 
|  | 5497 | FSData->f_bfree = | 
|  | 5498 | le64_to_cpu(response_data->BlocksAvail); | 
|  | 5499 | if (response_data->UserBlocksAvail == cpu_to_le64(-1)) { | 
|  | 5500 | FSData->f_bavail = FSData->f_bfree; | 
|  | 5501 | } else { | 
|  | 5502 | FSData->f_bavail = | 
|  | 5503 | le64_to_cpu(response_data->UserBlocksAvail); | 
|  | 5504 | } | 
|  | 5505 | if (response_data->TotalFileNodes != cpu_to_le64(-1)) | 
|  | 5506 | FSData->f_files = | 
|  | 5507 | le64_to_cpu(response_data->TotalFileNodes); | 
|  | 5508 | if (response_data->FreeFileNodes != cpu_to_le64(-1)) | 
|  | 5509 | FSData->f_ffree = | 
|  | 5510 | le64_to_cpu(response_data->FreeFileNodes); | 
|  | 5511 | } | 
|  | 5512 | } | 
|  | 5513 | cifs_buf_release(pSMB); | 
|  | 5514 |  | 
|  | 5515 | if (rc == -EAGAIN) | 
|  | 5516 | goto QFSPosixRetry; | 
|  | 5517 |  | 
|  | 5518 | return rc; | 
|  | 5519 | } | 
|  | 5520 |  | 
|  | 5521 |  | 
|  | 5522 | /* | 
|  | 5523 | * We can not use write of zero bytes trick to set file size due to need for | 
|  | 5524 | * large file support. Also note that this SetPathInfo is preferred to | 
|  | 5525 | * SetFileInfo based method in next routine which is only needed to work around | 
|  | 5526 | * a sharing violation bugin Samba which this routine can run into. | 
|  | 5527 | */ | 
|  | 5528 | int | 
|  | 5529 | CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 5530 | const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb, | 
|  | 5531 | bool set_allocation) | 
|  | 5532 | { | 
|  | 5533 | struct smb_com_transaction2_spi_req *pSMB = NULL; | 
|  | 5534 | struct smb_com_transaction2_spi_rsp *pSMBr = NULL; | 
|  | 5535 | struct file_end_of_file_info *parm_data; | 
|  | 5536 | int name_len; | 
|  | 5537 | int rc = 0; | 
|  | 5538 | int bytes_returned = 0; | 
|  | 5539 | int remap = cifs_remap(cifs_sb); | 
|  | 5540 |  | 
|  | 5541 | __u16 params, byte_count, data_count, param_offset, offset; | 
|  | 5542 |  | 
|  | 5543 | cifs_dbg(FYI, "In SetEOF\n"); | 
|  | 5544 | SetEOFRetry: | 
|  | 5545 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 5546 | (void **) &pSMBr); | 
|  | 5547 | if (rc) | 
|  | 5548 | return rc; | 
|  | 5549 |  | 
|  | 5550 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 5551 | name_len = | 
|  | 5552 | cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name, | 
|  | 5553 | PATH_MAX, cifs_sb->local_nls, remap); | 
|  | 5554 | name_len++;	/* trailing null */ | 
|  | 5555 | name_len *= 2; | 
|  | 5556 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 5557 | name_len = strnlen(file_name, PATH_MAX); | 
|  | 5558 | name_len++;	/* trailing null */ | 
|  | 5559 | strncpy(pSMB->FileName, file_name, name_len); | 
|  | 5560 | } | 
|  | 5561 | params = 6 + name_len; | 
|  | 5562 | data_count = sizeof(struct file_end_of_file_info); | 
|  | 5563 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 5564 | pSMB->MaxDataCount = cpu_to_le16(4100); | 
|  | 5565 | pSMB->MaxSetupCount = 0; | 
|  | 5566 | pSMB->Reserved = 0; | 
|  | 5567 | pSMB->Flags = 0; | 
|  | 5568 | pSMB->Timeout = 0; | 
|  | 5569 | pSMB->Reserved2 = 0; | 
|  | 5570 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | 
|  | 5571 | InformationLevel) - 4; | 
|  | 5572 | offset = param_offset + params; | 
|  | 5573 | if (set_allocation) { | 
|  | 5574 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | 
|  | 5575 | pSMB->InformationLevel = | 
|  | 5576 | cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); | 
|  | 5577 | else | 
|  | 5578 | pSMB->InformationLevel = | 
|  | 5579 | cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); | 
|  | 5580 | } else /* Set File Size */  { | 
|  | 5581 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | 
|  | 5582 | pSMB->InformationLevel = | 
|  | 5583 | cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); | 
|  | 5584 | else | 
|  | 5585 | pSMB->InformationLevel = | 
|  | 5586 | cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); | 
|  | 5587 | } | 
|  | 5588 |  | 
|  | 5589 | parm_data = | 
|  | 5590 | (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + | 
|  | 5591 | offset); | 
|  | 5592 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 5593 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 5594 | pSMB->SetupCount = 1; | 
|  | 5595 | pSMB->Reserved3 = 0; | 
|  | 5596 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | 
|  | 5597 | byte_count = 3 /* pad */  + params + data_count; | 
|  | 5598 | pSMB->DataCount = cpu_to_le16(data_count); | 
|  | 5599 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 5600 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 5601 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 5602 | pSMB->Reserved4 = 0; | 
|  | 5603 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5604 | parm_data->FileSize = cpu_to_le64(size); | 
|  | 5605 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5606 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 5607 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 5608 | if (rc) | 
|  | 5609 | cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc); | 
|  | 5610 |  | 
|  | 5611 | cifs_buf_release(pSMB); | 
|  | 5612 |  | 
|  | 5613 | if (rc == -EAGAIN) | 
|  | 5614 | goto SetEOFRetry; | 
|  | 5615 |  | 
|  | 5616 | return rc; | 
|  | 5617 | } | 
|  | 5618 |  | 
|  | 5619 | int | 
|  | 5620 | CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 5621 | struct cifsFileInfo *cfile, __u64 size, bool set_allocation) | 
|  | 5622 | { | 
|  | 5623 | struct smb_com_transaction2_sfi_req *pSMB  = NULL; | 
|  | 5624 | struct file_end_of_file_info *parm_data; | 
|  | 5625 | int rc = 0; | 
|  | 5626 | __u16 params, param_offset, offset, byte_count, count; | 
|  | 5627 |  | 
|  | 5628 | cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n", | 
|  | 5629 | (long long)size); | 
|  | 5630 | rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); | 
|  | 5631 |  | 
|  | 5632 | if (rc) | 
|  | 5633 | return rc; | 
|  | 5634 |  | 
|  | 5635 | pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid); | 
|  | 5636 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16)); | 
|  | 5637 |  | 
|  | 5638 | params = 6; | 
|  | 5639 | pSMB->MaxSetupCount = 0; | 
|  | 5640 | pSMB->Reserved = 0; | 
|  | 5641 | pSMB->Flags = 0; | 
|  | 5642 | pSMB->Timeout = 0; | 
|  | 5643 | pSMB->Reserved2 = 0; | 
|  | 5644 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | 
|  | 5645 | offset = param_offset + params; | 
|  | 5646 |  | 
|  | 5647 | count = sizeof(struct file_end_of_file_info); | 
|  | 5648 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 5649 | /* BB find exact max SMB PDU from sess structure BB */ | 
|  | 5650 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 5651 | pSMB->SetupCount = 1; | 
|  | 5652 | pSMB->Reserved3 = 0; | 
|  | 5653 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | 
|  | 5654 | byte_count = 3 /* pad */  + params + count; | 
|  | 5655 | pSMB->DataCount = cpu_to_le16(count); | 
|  | 5656 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 5657 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 5658 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 5659 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 5660 | parm_data = | 
|  | 5661 | (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) | 
|  | 5662 | + offset); | 
|  | 5663 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 5664 | parm_data->FileSize = cpu_to_le64(size); | 
|  | 5665 | pSMB->Fid = cfile->fid.netfid; | 
|  | 5666 | if (set_allocation) { | 
|  | 5667 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | 
|  | 5668 | pSMB->InformationLevel = | 
|  | 5669 | cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); | 
|  | 5670 | else | 
|  | 5671 | pSMB->InformationLevel = | 
|  | 5672 | cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); | 
|  | 5673 | } else /* Set File Size */  { | 
|  | 5674 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | 
|  | 5675 | pSMB->InformationLevel = | 
|  | 5676 | cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); | 
|  | 5677 | else | 
|  | 5678 | pSMB->InformationLevel = | 
|  | 5679 | cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); | 
|  | 5680 | } | 
|  | 5681 | pSMB->Reserved4 = 0; | 
|  | 5682 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5683 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5684 | rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); | 
|  | 5685 | cifs_small_buf_release(pSMB); | 
|  | 5686 | if (rc) { | 
|  | 5687 | cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n", | 
|  | 5688 | rc); | 
|  | 5689 | } | 
|  | 5690 |  | 
|  | 5691 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 5692 | since file handle passed in no longer valid */ | 
|  | 5693 |  | 
|  | 5694 | return rc; | 
|  | 5695 | } | 
|  | 5696 |  | 
|  | 5697 | /* Some legacy servers such as NT4 require that the file times be set on | 
|  | 5698 | an open handle, rather than by pathname - this is awkward due to | 
|  | 5699 | potential access conflicts on the open, but it is unavoidable for these | 
|  | 5700 | old servers since the only other choice is to go from 100 nanosecond DCE | 
|  | 5701 | time and resort to the original setpathinfo level which takes the ancient | 
|  | 5702 | DOS time format with 2 second granularity */ | 
|  | 5703 | int | 
|  | 5704 | CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 5705 | const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener) | 
|  | 5706 | { | 
|  | 5707 | struct smb_com_transaction2_sfi_req *pSMB  = NULL; | 
|  | 5708 | char *data_offset; | 
|  | 5709 | int rc = 0; | 
|  | 5710 | __u16 params, param_offset, offset, byte_count, count; | 
|  | 5711 |  | 
|  | 5712 | cifs_dbg(FYI, "Set Times (via SetFileInfo)\n"); | 
|  | 5713 | rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); | 
|  | 5714 |  | 
|  | 5715 | if (rc) | 
|  | 5716 | return rc; | 
|  | 5717 |  | 
|  | 5718 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); | 
|  | 5719 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); | 
|  | 5720 |  | 
|  | 5721 | params = 6; | 
|  | 5722 | pSMB->MaxSetupCount = 0; | 
|  | 5723 | pSMB->Reserved = 0; | 
|  | 5724 | pSMB->Flags = 0; | 
|  | 5725 | pSMB->Timeout = 0; | 
|  | 5726 | pSMB->Reserved2 = 0; | 
|  | 5727 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | 
|  | 5728 | offset = param_offset + params; | 
|  | 5729 |  | 
|  | 5730 | data_offset = (char *)pSMB + | 
|  | 5731 | offsetof(struct smb_hdr, Protocol) + offset; | 
|  | 5732 |  | 
|  | 5733 | count = sizeof(FILE_BASIC_INFO); | 
|  | 5734 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 5735 | /* BB find max SMB PDU from sess */ | 
|  | 5736 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 5737 | pSMB->SetupCount = 1; | 
|  | 5738 | pSMB->Reserved3 = 0; | 
|  | 5739 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | 
|  | 5740 | byte_count = 3 /* pad */  + params + count; | 
|  | 5741 | pSMB->DataCount = cpu_to_le16(count); | 
|  | 5742 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 5743 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 5744 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 5745 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 5746 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 5747 | pSMB->Fid = fid; | 
|  | 5748 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | 
|  | 5749 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2); | 
|  | 5750 | else | 
|  | 5751 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); | 
|  | 5752 | pSMB->Reserved4 = 0; | 
|  | 5753 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5754 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5755 | memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); | 
|  | 5756 | rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); | 
|  | 5757 | cifs_small_buf_release(pSMB); | 
|  | 5758 | if (rc) | 
|  | 5759 | cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n", | 
|  | 5760 | rc); | 
|  | 5761 |  | 
|  | 5762 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 5763 | since file handle passed in no longer valid */ | 
|  | 5764 |  | 
|  | 5765 | return rc; | 
|  | 5766 | } | 
|  | 5767 |  | 
|  | 5768 | int | 
|  | 5769 | CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 5770 | bool delete_file, __u16 fid, __u32 pid_of_opener) | 
|  | 5771 | { | 
|  | 5772 | struct smb_com_transaction2_sfi_req *pSMB  = NULL; | 
|  | 5773 | char *data_offset; | 
|  | 5774 | int rc = 0; | 
|  | 5775 | __u16 params, param_offset, offset, byte_count, count; | 
|  | 5776 |  | 
|  | 5777 | cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n"); | 
|  | 5778 | rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); | 
|  | 5779 |  | 
|  | 5780 | if (rc) | 
|  | 5781 | return rc; | 
|  | 5782 |  | 
|  | 5783 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); | 
|  | 5784 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); | 
|  | 5785 |  | 
|  | 5786 | params = 6; | 
|  | 5787 | pSMB->MaxSetupCount = 0; | 
|  | 5788 | pSMB->Reserved = 0; | 
|  | 5789 | pSMB->Flags = 0; | 
|  | 5790 | pSMB->Timeout = 0; | 
|  | 5791 | pSMB->Reserved2 = 0; | 
|  | 5792 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | 
|  | 5793 | offset = param_offset + params; | 
|  | 5794 |  | 
|  | 5795 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | 
|  | 5796 |  | 
|  | 5797 | count = 1; | 
|  | 5798 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 5799 | /* BB find max SMB PDU from sess */ | 
|  | 5800 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 5801 | pSMB->SetupCount = 1; | 
|  | 5802 | pSMB->Reserved3 = 0; | 
|  | 5803 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | 
|  | 5804 | byte_count = 3 /* pad */  + params + count; | 
|  | 5805 | pSMB->DataCount = cpu_to_le16(count); | 
|  | 5806 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 5807 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 5808 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 5809 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 5810 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 5811 | pSMB->Fid = fid; | 
|  | 5812 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO); | 
|  | 5813 | pSMB->Reserved4 = 0; | 
|  | 5814 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5815 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5816 | *data_offset = delete_file ? 1 : 0; | 
|  | 5817 | rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); | 
|  | 5818 | cifs_small_buf_release(pSMB); | 
|  | 5819 | if (rc) | 
|  | 5820 | cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc); | 
|  | 5821 |  | 
|  | 5822 | return rc; | 
|  | 5823 | } | 
|  | 5824 |  | 
|  | 5825 | int | 
|  | 5826 | CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 5827 | const char *fileName, const FILE_BASIC_INFO *data, | 
|  | 5828 | const struct nls_table *nls_codepage, int remap) | 
|  | 5829 | { | 
|  | 5830 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 
|  | 5831 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 
|  | 5832 | int name_len; | 
|  | 5833 | int rc = 0; | 
|  | 5834 | int bytes_returned = 0; | 
|  | 5835 | char *data_offset; | 
|  | 5836 | __u16 params, param_offset, offset, byte_count, count; | 
|  | 5837 |  | 
|  | 5838 | cifs_dbg(FYI, "In SetTimes\n"); | 
|  | 5839 |  | 
|  | 5840 | SetTimesRetry: | 
|  | 5841 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 5842 | (void **) &pSMBr); | 
|  | 5843 | if (rc) | 
|  | 5844 | return rc; | 
|  | 5845 |  | 
|  | 5846 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 5847 | name_len = | 
|  | 5848 | cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, | 
|  | 5849 | PATH_MAX, nls_codepage, remap); | 
|  | 5850 | name_len++;	/* trailing null */ | 
|  | 5851 | name_len *= 2; | 
|  | 5852 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 5853 | name_len = strnlen(fileName, PATH_MAX); | 
|  | 5854 | name_len++;	/* trailing null */ | 
|  | 5855 | strncpy(pSMB->FileName, fileName, name_len); | 
|  | 5856 | } | 
|  | 5857 |  | 
|  | 5858 | params = 6 + name_len; | 
|  | 5859 | count = sizeof(FILE_BASIC_INFO); | 
|  | 5860 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 5861 | /* BB find max SMB PDU from sess structure BB */ | 
|  | 5862 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 5863 | pSMB->MaxSetupCount = 0; | 
|  | 5864 | pSMB->Reserved = 0; | 
|  | 5865 | pSMB->Flags = 0; | 
|  | 5866 | pSMB->Timeout = 0; | 
|  | 5867 | pSMB->Reserved2 = 0; | 
|  | 5868 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | 
|  | 5869 | InformationLevel) - 4; | 
|  | 5870 | offset = param_offset + params; | 
|  | 5871 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | 
|  | 5872 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 5873 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 5874 | pSMB->SetupCount = 1; | 
|  | 5875 | pSMB->Reserved3 = 0; | 
|  | 5876 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | 
|  | 5877 | byte_count = 3 /* pad */  + params + count; | 
|  | 5878 |  | 
|  | 5879 | pSMB->DataCount = cpu_to_le16(count); | 
|  | 5880 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 5881 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 5882 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 5883 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | 
|  | 5884 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2); | 
|  | 5885 | else | 
|  | 5886 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); | 
|  | 5887 | pSMB->Reserved4 = 0; | 
|  | 5888 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 5889 | memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); | 
|  | 5890 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 5891 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 5892 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 5893 | if (rc) | 
|  | 5894 | cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc); | 
|  | 5895 |  | 
|  | 5896 | cifs_buf_release(pSMB); | 
|  | 5897 |  | 
|  | 5898 | if (rc == -EAGAIN) | 
|  | 5899 | goto SetTimesRetry; | 
|  | 5900 |  | 
|  | 5901 | return rc; | 
|  | 5902 | } | 
|  | 5903 |  | 
|  | 5904 | /* Can not be used to set time stamps yet (due to old DOS time format) */ | 
|  | 5905 | /* Can be used to set attributes */ | 
|  | 5906 | #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug | 
|  | 5907 | handling it anyway and NT4 was what we thought it would be needed for | 
|  | 5908 | Do not delete it until we prove whether needed for Win9x though */ | 
|  | 5909 | int | 
|  | 5910 | CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName, | 
|  | 5911 | __u16 dos_attrs, const struct nls_table *nls_codepage) | 
|  | 5912 | { | 
|  | 5913 | SETATTR_REQ *pSMB = NULL; | 
|  | 5914 | SETATTR_RSP *pSMBr = NULL; | 
|  | 5915 | int rc = 0; | 
|  | 5916 | int bytes_returned; | 
|  | 5917 | int name_len; | 
|  | 5918 |  | 
|  | 5919 | cifs_dbg(FYI, "In SetAttrLegacy\n"); | 
|  | 5920 |  | 
|  | 5921 | SetAttrLgcyRetry: | 
|  | 5922 | rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB, | 
|  | 5923 | (void **) &pSMBr); | 
|  | 5924 | if (rc) | 
|  | 5925 | return rc; | 
|  | 5926 |  | 
|  | 5927 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 5928 | name_len = | 
|  | 5929 | ConvertToUTF16((__le16 *) pSMB->fileName, fileName, | 
|  | 5930 | PATH_MAX, nls_codepage); | 
|  | 5931 | name_len++;     /* trailing null */ | 
|  | 5932 | name_len *= 2; | 
|  | 5933 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 5934 | name_len = strnlen(fileName, PATH_MAX); | 
|  | 5935 | name_len++;     /* trailing null */ | 
|  | 5936 | strncpy(pSMB->fileName, fileName, name_len); | 
|  | 5937 | } | 
|  | 5938 | pSMB->attr = cpu_to_le16(dos_attrs); | 
|  | 5939 | pSMB->BufferFormat = 0x04; | 
|  | 5940 | inc_rfc1001_len(pSMB, name_len + 1); | 
|  | 5941 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 
|  | 5942 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 5943 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 5944 | if (rc) | 
|  | 5945 | cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc); | 
|  | 5946 |  | 
|  | 5947 | cifs_buf_release(pSMB); | 
|  | 5948 |  | 
|  | 5949 | if (rc == -EAGAIN) | 
|  | 5950 | goto SetAttrLgcyRetry; | 
|  | 5951 |  | 
|  | 5952 | return rc; | 
|  | 5953 | } | 
|  | 5954 | #endif /* temporarily unneeded SetAttr legacy function */ | 
|  | 5955 |  | 
|  | 5956 | static void | 
|  | 5957 | cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, | 
|  | 5958 | const struct cifs_unix_set_info_args *args) | 
|  | 5959 | { | 
|  | 5960 | u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64; | 
|  | 5961 | u64 mode = args->mode; | 
|  | 5962 |  | 
|  | 5963 | if (uid_valid(args->uid)) | 
|  | 5964 | uid = from_kuid(&init_user_ns, args->uid); | 
|  | 5965 | if (gid_valid(args->gid)) | 
|  | 5966 | gid = from_kgid(&init_user_ns, args->gid); | 
|  | 5967 |  | 
|  | 5968 | /* | 
|  | 5969 | * Samba server ignores set of file size to zero due to bugs in some | 
|  | 5970 | * older clients, but we should be precise - we use SetFileSize to | 
|  | 5971 | * set file size and do not want to truncate file size to zero | 
|  | 5972 | * accidentally as happened on one Samba server beta by putting | 
|  | 5973 | * zero instead of -1 here | 
|  | 5974 | */ | 
|  | 5975 | data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); | 
|  | 5976 | data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64); | 
|  | 5977 | data_offset->LastStatusChange = cpu_to_le64(args->ctime); | 
|  | 5978 | data_offset->LastAccessTime = cpu_to_le64(args->atime); | 
|  | 5979 | data_offset->LastModificationTime = cpu_to_le64(args->mtime); | 
|  | 5980 | data_offset->Uid = cpu_to_le64(uid); | 
|  | 5981 | data_offset->Gid = cpu_to_le64(gid); | 
|  | 5982 | /* better to leave device as zero when it is  */ | 
|  | 5983 | data_offset->DevMajor = cpu_to_le64(MAJOR(args->device)); | 
|  | 5984 | data_offset->DevMinor = cpu_to_le64(MINOR(args->device)); | 
|  | 5985 | data_offset->Permissions = cpu_to_le64(mode); | 
|  | 5986 |  | 
|  | 5987 | if (S_ISREG(mode)) | 
|  | 5988 | data_offset->Type = cpu_to_le32(UNIX_FILE); | 
|  | 5989 | else if (S_ISDIR(mode)) | 
|  | 5990 | data_offset->Type = cpu_to_le32(UNIX_DIR); | 
|  | 5991 | else if (S_ISLNK(mode)) | 
|  | 5992 | data_offset->Type = cpu_to_le32(UNIX_SYMLINK); | 
|  | 5993 | else if (S_ISCHR(mode)) | 
|  | 5994 | data_offset->Type = cpu_to_le32(UNIX_CHARDEV); | 
|  | 5995 | else if (S_ISBLK(mode)) | 
|  | 5996 | data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV); | 
|  | 5997 | else if (S_ISFIFO(mode)) | 
|  | 5998 | data_offset->Type = cpu_to_le32(UNIX_FIFO); | 
|  | 5999 | else if (S_ISSOCK(mode)) | 
|  | 6000 | data_offset->Type = cpu_to_le32(UNIX_SOCKET); | 
|  | 6001 | } | 
|  | 6002 |  | 
|  | 6003 | int | 
|  | 6004 | CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 6005 | const struct cifs_unix_set_info_args *args, | 
|  | 6006 | u16 fid, u32 pid_of_opener) | 
|  | 6007 | { | 
|  | 6008 | struct smb_com_transaction2_sfi_req *pSMB  = NULL; | 
|  | 6009 | char *data_offset; | 
|  | 6010 | int rc = 0; | 
|  | 6011 | u16 params, param_offset, offset, byte_count, count; | 
|  | 6012 |  | 
|  | 6013 | cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n"); | 
|  | 6014 | rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); | 
|  | 6015 |  | 
|  | 6016 | if (rc) | 
|  | 6017 | return rc; | 
|  | 6018 |  | 
|  | 6019 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); | 
|  | 6020 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); | 
|  | 6021 |  | 
|  | 6022 | params = 6; | 
|  | 6023 | pSMB->MaxSetupCount = 0; | 
|  | 6024 | pSMB->Reserved = 0; | 
|  | 6025 | pSMB->Flags = 0; | 
|  | 6026 | pSMB->Timeout = 0; | 
|  | 6027 | pSMB->Reserved2 = 0; | 
|  | 6028 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | 
|  | 6029 | offset = param_offset + params; | 
|  | 6030 |  | 
|  | 6031 | data_offset = (char *)pSMB + | 
|  | 6032 | offsetof(struct smb_hdr, Protocol) + offset; | 
|  | 6033 |  | 
|  | 6034 | count = sizeof(FILE_UNIX_BASIC_INFO); | 
|  | 6035 |  | 
|  | 6036 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 6037 | /* BB find max SMB PDU from sess */ | 
|  | 6038 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 6039 | pSMB->SetupCount = 1; | 
|  | 6040 | pSMB->Reserved3 = 0; | 
|  | 6041 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | 
|  | 6042 | byte_count = 3 /* pad */  + params + count; | 
|  | 6043 | pSMB->DataCount = cpu_to_le16(count); | 
|  | 6044 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 6045 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 6046 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 6047 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 6048 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 6049 | pSMB->Fid = fid; | 
|  | 6050 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); | 
|  | 6051 | pSMB->Reserved4 = 0; | 
|  | 6052 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 6053 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 6054 |  | 
|  | 6055 | cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args); | 
|  | 6056 |  | 
|  | 6057 | rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); | 
|  | 6058 | cifs_small_buf_release(pSMB); | 
|  | 6059 | if (rc) | 
|  | 6060 | cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n", | 
|  | 6061 | rc); | 
|  | 6062 |  | 
|  | 6063 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 
|  | 6064 | since file handle passed in no longer valid */ | 
|  | 6065 |  | 
|  | 6066 | return rc; | 
|  | 6067 | } | 
|  | 6068 |  | 
|  | 6069 | int | 
|  | 6070 | CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 6071 | const char *file_name, | 
|  | 6072 | const struct cifs_unix_set_info_args *args, | 
|  | 6073 | const struct nls_table *nls_codepage, int remap) | 
|  | 6074 | { | 
|  | 6075 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 
|  | 6076 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 
|  | 6077 | int name_len; | 
|  | 6078 | int rc = 0; | 
|  | 6079 | int bytes_returned = 0; | 
|  | 6080 | FILE_UNIX_BASIC_INFO *data_offset; | 
|  | 6081 | __u16 params, param_offset, offset, count, byte_count; | 
|  | 6082 |  | 
|  | 6083 | cifs_dbg(FYI, "In SetUID/GID/Mode\n"); | 
|  | 6084 | setPermsRetry: | 
|  | 6085 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 6086 | (void **) &pSMBr); | 
|  | 6087 | if (rc) | 
|  | 6088 | return rc; | 
|  | 6089 |  | 
|  | 6090 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 6091 | name_len = | 
|  | 6092 | cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name, | 
|  | 6093 | PATH_MAX, nls_codepage, remap); | 
|  | 6094 | name_len++;	/* trailing null */ | 
|  | 6095 | name_len *= 2; | 
|  | 6096 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 6097 | name_len = strnlen(file_name, PATH_MAX); | 
|  | 6098 | name_len++;	/* trailing null */ | 
|  | 6099 | strncpy(pSMB->FileName, file_name, name_len); | 
|  | 6100 | } | 
|  | 6101 |  | 
|  | 6102 | params = 6 + name_len; | 
|  | 6103 | count = sizeof(FILE_UNIX_BASIC_INFO); | 
|  | 6104 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 6105 | /* BB find max SMB PDU from sess structure BB */ | 
|  | 6106 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 6107 | pSMB->MaxSetupCount = 0; | 
|  | 6108 | pSMB->Reserved = 0; | 
|  | 6109 | pSMB->Flags = 0; | 
|  | 6110 | pSMB->Timeout = 0; | 
|  | 6111 | pSMB->Reserved2 = 0; | 
|  | 6112 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | 
|  | 6113 | InformationLevel) - 4; | 
|  | 6114 | offset = param_offset + params; | 
|  | 6115 | data_offset = | 
|  | 6116 | (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol + | 
|  | 6117 | offset); | 
|  | 6118 | memset(data_offset, 0, count); | 
|  | 6119 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 6120 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 6121 | pSMB->SetupCount = 1; | 
|  | 6122 | pSMB->Reserved3 = 0; | 
|  | 6123 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | 
|  | 6124 | byte_count = 3 /* pad */  + params + count; | 
|  | 6125 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 6126 | pSMB->DataCount = cpu_to_le16(count); | 
|  | 6127 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 6128 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 6129 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); | 
|  | 6130 | pSMB->Reserved4 = 0; | 
|  | 6131 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 6132 |  | 
|  | 6133 | cifs_fill_unix_set_info(data_offset, args); | 
|  | 6134 |  | 
|  | 6135 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 6136 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 6137 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 6138 | if (rc) | 
|  | 6139 | cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc); | 
|  | 6140 |  | 
|  | 6141 | cifs_buf_release(pSMB); | 
|  | 6142 | if (rc == -EAGAIN) | 
|  | 6143 | goto setPermsRetry; | 
|  | 6144 | return rc; | 
|  | 6145 | } | 
|  | 6146 |  | 
|  | 6147 | #ifdef CONFIG_CIFS_XATTR | 
|  | 6148 | /* | 
|  | 6149 | * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common | 
|  | 6150 | * function used by listxattr and getxattr type calls. When ea_name is set, | 
|  | 6151 | * it looks for that attribute name and stuffs that value into the EAData | 
|  | 6152 | * buffer. When ea_name is NULL, it stuffs a list of attribute names into the | 
|  | 6153 | * buffer. In both cases, the return value is either the length of the | 
|  | 6154 | * resulting data or a negative error code. If EAData is a NULL pointer then | 
|  | 6155 | * the data isn't copied to it, but the length is returned. | 
|  | 6156 | */ | 
|  | 6157 | ssize_t | 
|  | 6158 | CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 6159 | const unsigned char *searchName, const unsigned char *ea_name, | 
|  | 6160 | char *EAData, size_t buf_size, | 
|  | 6161 | struct cifs_sb_info *cifs_sb) | 
|  | 6162 | { | 
|  | 6163 | /* BB assumes one setup word */ | 
|  | 6164 | TRANSACTION2_QPI_REQ *pSMB = NULL; | 
|  | 6165 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | 
|  | 6166 | int remap = cifs_remap(cifs_sb); | 
|  | 6167 | struct nls_table *nls_codepage = cifs_sb->local_nls; | 
|  | 6168 | int rc = 0; | 
|  | 6169 | int bytes_returned; | 
|  | 6170 | int list_len; | 
|  | 6171 | struct fealist *ea_response_data; | 
|  | 6172 | struct fea *temp_fea; | 
|  | 6173 | char *temp_ptr; | 
|  | 6174 | char *end_of_smb; | 
|  | 6175 | __u16 params, byte_count, data_offset; | 
|  | 6176 | unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0; | 
|  | 6177 |  | 
|  | 6178 | cifs_dbg(FYI, "In Query All EAs path %s\n", searchName); | 
|  | 6179 | QAllEAsRetry: | 
|  | 6180 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 6181 | (void **) &pSMBr); | 
|  | 6182 | if (rc) | 
|  | 6183 | return rc; | 
|  | 6184 |  | 
|  | 6185 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 6186 | list_len = | 
|  | 6187 | cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, | 
|  | 6188 | PATH_MAX, nls_codepage, remap); | 
|  | 6189 | list_len++;	/* trailing null */ | 
|  | 6190 | list_len *= 2; | 
|  | 6191 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 6192 | list_len = strnlen(searchName, PATH_MAX); | 
|  | 6193 | list_len++;	/* trailing null */ | 
|  | 6194 | strncpy(pSMB->FileName, searchName, list_len); | 
|  | 6195 | } | 
|  | 6196 |  | 
|  | 6197 | params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */; | 
|  | 6198 | pSMB->TotalDataCount = 0; | 
|  | 6199 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 6200 | /* BB find exact max SMB PDU from sess structure BB */ | 
|  | 6201 | pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize); | 
|  | 6202 | pSMB->MaxSetupCount = 0; | 
|  | 6203 | pSMB->Reserved = 0; | 
|  | 6204 | pSMB->Flags = 0; | 
|  | 6205 | pSMB->Timeout = 0; | 
|  | 6206 | pSMB->Reserved2 = 0; | 
|  | 6207 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | 
|  | 6208 | struct smb_com_transaction2_qpi_req, InformationLevel) - 4); | 
|  | 6209 | pSMB->DataCount = 0; | 
|  | 6210 | pSMB->DataOffset = 0; | 
|  | 6211 | pSMB->SetupCount = 1; | 
|  | 6212 | pSMB->Reserved3 = 0; | 
|  | 6213 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | 
|  | 6214 | byte_count = params + 1 /* pad */ ; | 
|  | 6215 | pSMB->TotalParameterCount = cpu_to_le16(params); | 
|  | 6216 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 6217 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); | 
|  | 6218 | pSMB->Reserved4 = 0; | 
|  | 6219 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 6220 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 6221 |  | 
|  | 6222 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 6223 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 6224 | if (rc) { | 
|  | 6225 | cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc); | 
|  | 6226 | goto QAllEAsOut; | 
|  | 6227 | } | 
|  | 6228 |  | 
|  | 6229 |  | 
|  | 6230 | /* BB also check enough total bytes returned */ | 
|  | 6231 | /* BB we need to improve the validity checking | 
|  | 6232 | of these trans2 responses */ | 
|  | 6233 |  | 
|  | 6234 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 
|  | 6235 | if (rc || get_bcc(&pSMBr->hdr) < 4) { | 
|  | 6236 | rc = -EIO;	/* bad smb */ | 
|  | 6237 | goto QAllEAsOut; | 
|  | 6238 | } | 
|  | 6239 |  | 
|  | 6240 | /* check that length of list is not more than bcc */ | 
|  | 6241 | /* check that each entry does not go beyond length | 
|  | 6242 | of list */ | 
|  | 6243 | /* check that each element of each entry does not | 
|  | 6244 | go beyond end of list */ | 
|  | 6245 | /* validate_trans2_offsets() */ | 
|  | 6246 | /* BB check if start of smb + data_offset > &bcc+ bcc */ | 
|  | 6247 |  | 
|  | 6248 | data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 
|  | 6249 | ea_response_data = (struct fealist *) | 
|  | 6250 | (((char *) &pSMBr->hdr.Protocol) + data_offset); | 
|  | 6251 |  | 
|  | 6252 | list_len = le32_to_cpu(ea_response_data->list_len); | 
|  | 6253 | cifs_dbg(FYI, "ea length %d\n", list_len); | 
|  | 6254 | if (list_len <= 8) { | 
|  | 6255 | cifs_dbg(FYI, "empty EA list returned from server\n"); | 
|  | 6256 | /* didn't find the named attribute */ | 
|  | 6257 | if (ea_name) | 
|  | 6258 | rc = -ENODATA; | 
|  | 6259 | goto QAllEAsOut; | 
|  | 6260 | } | 
|  | 6261 |  | 
|  | 6262 | /* make sure list_len doesn't go past end of SMB */ | 
|  | 6263 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr); | 
|  | 6264 | if ((char *)ea_response_data + list_len > end_of_smb) { | 
|  | 6265 | cifs_dbg(FYI, "EA list appears to go beyond SMB\n"); | 
|  | 6266 | rc = -EIO; | 
|  | 6267 | goto QAllEAsOut; | 
|  | 6268 | } | 
|  | 6269 |  | 
|  | 6270 | /* account for ea list len */ | 
|  | 6271 | list_len -= 4; | 
|  | 6272 | temp_fea = ea_response_data->list; | 
|  | 6273 | temp_ptr = (char *)temp_fea; | 
|  | 6274 | while (list_len > 0) { | 
|  | 6275 | unsigned int name_len; | 
|  | 6276 | __u16 value_len; | 
|  | 6277 |  | 
|  | 6278 | list_len -= 4; | 
|  | 6279 | temp_ptr += 4; | 
|  | 6280 | /* make sure we can read name_len and value_len */ | 
|  | 6281 | if (list_len < 0) { | 
|  | 6282 | cifs_dbg(FYI, "EA entry goes beyond length of list\n"); | 
|  | 6283 | rc = -EIO; | 
|  | 6284 | goto QAllEAsOut; | 
|  | 6285 | } | 
|  | 6286 |  | 
|  | 6287 | name_len = temp_fea->name_len; | 
|  | 6288 | value_len = le16_to_cpu(temp_fea->value_len); | 
|  | 6289 | list_len -= name_len + 1 + value_len; | 
|  | 6290 | if (list_len < 0) { | 
|  | 6291 | cifs_dbg(FYI, "EA entry goes beyond length of list\n"); | 
|  | 6292 | rc = -EIO; | 
|  | 6293 | goto QAllEAsOut; | 
|  | 6294 | } | 
|  | 6295 |  | 
|  | 6296 | if (ea_name) { | 
|  | 6297 | if (ea_name_len == name_len && | 
|  | 6298 | memcmp(ea_name, temp_ptr, name_len) == 0) { | 
|  | 6299 | temp_ptr += name_len + 1; | 
|  | 6300 | rc = value_len; | 
|  | 6301 | if (buf_size == 0) | 
|  | 6302 | goto QAllEAsOut; | 
|  | 6303 | if ((size_t)value_len > buf_size) { | 
|  | 6304 | rc = -ERANGE; | 
|  | 6305 | goto QAllEAsOut; | 
|  | 6306 | } | 
|  | 6307 | memcpy(EAData, temp_ptr, value_len); | 
|  | 6308 | goto QAllEAsOut; | 
|  | 6309 | } | 
|  | 6310 | } else { | 
|  | 6311 | /* account for prefix user. and trailing null */ | 
|  | 6312 | rc += (5 + 1 + name_len); | 
|  | 6313 | if (rc < (int) buf_size) { | 
|  | 6314 | memcpy(EAData, "user.", 5); | 
|  | 6315 | EAData += 5; | 
|  | 6316 | memcpy(EAData, temp_ptr, name_len); | 
|  | 6317 | EAData += name_len; | 
|  | 6318 | /* null terminate name */ | 
|  | 6319 | *EAData = 0; | 
|  | 6320 | ++EAData; | 
|  | 6321 | } else if (buf_size == 0) { | 
|  | 6322 | /* skip copy - calc size only */ | 
|  | 6323 | } else { | 
|  | 6324 | /* stop before overrun buffer */ | 
|  | 6325 | rc = -ERANGE; | 
|  | 6326 | break; | 
|  | 6327 | } | 
|  | 6328 | } | 
|  | 6329 | temp_ptr += name_len + 1 + value_len; | 
|  | 6330 | temp_fea = (struct fea *)temp_ptr; | 
|  | 6331 | } | 
|  | 6332 |  | 
|  | 6333 | /* didn't find the named attribute */ | 
|  | 6334 | if (ea_name) | 
|  | 6335 | rc = -ENODATA; | 
|  | 6336 |  | 
|  | 6337 | QAllEAsOut: | 
|  | 6338 | cifs_buf_release(pSMB); | 
|  | 6339 | if (rc == -EAGAIN) | 
|  | 6340 | goto QAllEAsRetry; | 
|  | 6341 |  | 
|  | 6342 | return (ssize_t)rc; | 
|  | 6343 | } | 
|  | 6344 |  | 
|  | 6345 | int | 
|  | 6346 | CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 6347 | const char *fileName, const char *ea_name, const void *ea_value, | 
|  | 6348 | const __u16 ea_value_len, const struct nls_table *nls_codepage, | 
|  | 6349 | struct cifs_sb_info *cifs_sb) | 
|  | 6350 | { | 
|  | 6351 | struct smb_com_transaction2_spi_req *pSMB = NULL; | 
|  | 6352 | struct smb_com_transaction2_spi_rsp *pSMBr = NULL; | 
|  | 6353 | struct fealist *parm_data; | 
|  | 6354 | int name_len; | 
|  | 6355 | int rc = 0; | 
|  | 6356 | int bytes_returned = 0; | 
|  | 6357 | __u16 params, param_offset, byte_count, offset, count; | 
|  | 6358 | int remap = cifs_remap(cifs_sb); | 
|  | 6359 |  | 
|  | 6360 | cifs_dbg(FYI, "In SetEA\n"); | 
|  | 6361 | SetEARetry: | 
|  | 6362 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 
|  | 6363 | (void **) &pSMBr); | 
|  | 6364 | if (rc) | 
|  | 6365 | return rc; | 
|  | 6366 |  | 
|  | 6367 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 
|  | 6368 | name_len = | 
|  | 6369 | cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, | 
|  | 6370 | PATH_MAX, nls_codepage, remap); | 
|  | 6371 | name_len++;	/* trailing null */ | 
|  | 6372 | name_len *= 2; | 
|  | 6373 | } else {	/* BB improve the check for buffer overruns BB */ | 
|  | 6374 | name_len = strnlen(fileName, PATH_MAX); | 
|  | 6375 | name_len++;	/* trailing null */ | 
|  | 6376 | strncpy(pSMB->FileName, fileName, name_len); | 
|  | 6377 | } | 
|  | 6378 |  | 
|  | 6379 | params = 6 + name_len; | 
|  | 6380 |  | 
|  | 6381 | /* done calculating parms using name_len of file name, | 
|  | 6382 | now use name_len to calculate length of ea name | 
|  | 6383 | we are going to create in the inode xattrs */ | 
|  | 6384 | if (ea_name == NULL) | 
|  | 6385 | name_len = 0; | 
|  | 6386 | else | 
|  | 6387 | name_len = strnlen(ea_name, 255); | 
|  | 6388 |  | 
|  | 6389 | count = sizeof(*parm_data) + ea_value_len + name_len; | 
|  | 6390 | pSMB->MaxParameterCount = cpu_to_le16(2); | 
|  | 6391 | /* BB find max SMB PDU from sess */ | 
|  | 6392 | pSMB->MaxDataCount = cpu_to_le16(1000); | 
|  | 6393 | pSMB->MaxSetupCount = 0; | 
|  | 6394 | pSMB->Reserved = 0; | 
|  | 6395 | pSMB->Flags = 0; | 
|  | 6396 | pSMB->Timeout = 0; | 
|  | 6397 | pSMB->Reserved2 = 0; | 
|  | 6398 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | 
|  | 6399 | InformationLevel) - 4; | 
|  | 6400 | offset = param_offset + params; | 
|  | 6401 | pSMB->InformationLevel = | 
|  | 6402 | cpu_to_le16(SMB_SET_FILE_EA); | 
|  | 6403 |  | 
|  | 6404 | parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset; | 
|  | 6405 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | 
|  | 6406 | pSMB->DataOffset = cpu_to_le16(offset); | 
|  | 6407 | pSMB->SetupCount = 1; | 
|  | 6408 | pSMB->Reserved3 = 0; | 
|  | 6409 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | 
|  | 6410 | byte_count = 3 /* pad */  + params + count; | 
|  | 6411 | pSMB->DataCount = cpu_to_le16(count); | 
|  | 6412 | parm_data->list_len = cpu_to_le32(count); | 
|  | 6413 | parm_data->list[0].EA_flags = 0; | 
|  | 6414 | /* we checked above that name len is less than 255 */ | 
|  | 6415 | parm_data->list[0].name_len = (__u8)name_len; | 
|  | 6416 | /* EA names are always ASCII */ | 
|  | 6417 | if (ea_name) | 
|  | 6418 | strncpy(parm_data->list[0].name, ea_name, name_len); | 
|  | 6419 | parm_data->list[0].name[name_len] = 0; | 
|  | 6420 | parm_data->list[0].value_len = cpu_to_le16(ea_value_len); | 
|  | 6421 | /* caller ensures that ea_value_len is less than 64K but | 
|  | 6422 | we need to ensure that it fits within the smb */ | 
|  | 6423 |  | 
|  | 6424 | /*BB add length check to see if it would fit in | 
|  | 6425 | negotiated SMB buffer size BB */ | 
|  | 6426 | /* if (ea_value_len > buffer_size - 512 (enough for header)) */ | 
|  | 6427 | if (ea_value_len) | 
|  | 6428 | memcpy(parm_data->list[0].name+name_len+1, | 
|  | 6429 | ea_value, ea_value_len); | 
|  | 6430 |  | 
|  | 6431 | pSMB->TotalDataCount = pSMB->DataCount; | 
|  | 6432 | pSMB->ParameterCount = cpu_to_le16(params); | 
|  | 6433 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 
|  | 6434 | pSMB->Reserved4 = 0; | 
|  | 6435 | inc_rfc1001_len(pSMB, byte_count); | 
|  | 6436 | pSMB->ByteCount = cpu_to_le16(byte_count); | 
|  | 6437 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 6438 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 
|  | 6439 | if (rc) | 
|  | 6440 | cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc); | 
|  | 6441 |  | 
|  | 6442 | cifs_buf_release(pSMB); | 
|  | 6443 |  | 
|  | 6444 | if (rc == -EAGAIN) | 
|  | 6445 | goto SetEARetry; | 
|  | 6446 |  | 
|  | 6447 | return rc; | 
|  | 6448 | } | 
|  | 6449 | #endif | 
|  | 6450 |  | 
|  | 6451 | #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */ | 
|  | 6452 | /* | 
|  | 6453 | *	Years ago the kernel added a "dnotify" function for Samba server, | 
|  | 6454 | *	to allow network clients (such as Windows) to display updated | 
|  | 6455 | *	lists of files in directory listings automatically when | 
|  | 6456 | *	files are added by one user when another user has the | 
|  | 6457 | *	same directory open on their desktop.  The Linux cifs kernel | 
|  | 6458 | *	client hooked into the kernel side of this interface for | 
|  | 6459 | *	the same reason, but ironically when the VFS moved from | 
|  | 6460 | *	"dnotify" to "inotify" it became harder to plug in Linux | 
|  | 6461 | *	network file system clients (the most obvious use case | 
|  | 6462 | *	for notify interfaces is when multiple users can update | 
|  | 6463 | *	the contents of the same directory - exactly what network | 
|  | 6464 | *	file systems can do) although the server (Samba) could | 
|  | 6465 | *	still use it.  For the short term we leave the worker | 
|  | 6466 | *	function ifdeffed out (below) until inotify is fixed | 
|  | 6467 | *	in the VFS to make it easier to plug in network file | 
|  | 6468 | *	system clients.  If inotify turns out to be permanently | 
|  | 6469 | *	incompatible for network fs clients, we could instead simply | 
|  | 6470 | *	expose this config flag by adding a future cifs (and smb2) notify ioctl. | 
|  | 6471 | */ | 
|  | 6472 | int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon, | 
|  | 6473 | const int notify_subdirs, const __u16 netfid, | 
|  | 6474 | __u32 filter, struct file *pfile, int multishot, | 
|  | 6475 | const struct nls_table *nls_codepage) | 
|  | 6476 | { | 
|  | 6477 | int rc = 0; | 
|  | 6478 | struct smb_com_transaction_change_notify_req *pSMB = NULL; | 
|  | 6479 | struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL; | 
|  | 6480 | struct dir_notify_req *dnotify_req; | 
|  | 6481 | int bytes_returned; | 
|  | 6482 |  | 
|  | 6483 | cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid); | 
|  | 6484 | rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, | 
|  | 6485 | (void **) &pSMBr); | 
|  | 6486 | if (rc) | 
|  | 6487 | return rc; | 
|  | 6488 |  | 
|  | 6489 | pSMB->TotalParameterCount = 0 ; | 
|  | 6490 | pSMB->TotalDataCount = 0; | 
|  | 6491 | pSMB->MaxParameterCount = cpu_to_le32(2); | 
|  | 6492 | pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); | 
|  | 6493 | pSMB->MaxSetupCount = 4; | 
|  | 6494 | pSMB->Reserved = 0; | 
|  | 6495 | pSMB->ParameterOffset = 0; | 
|  | 6496 | pSMB->DataCount = 0; | 
|  | 6497 | pSMB->DataOffset = 0; | 
|  | 6498 | pSMB->SetupCount = 4; /* single byte does not need le conversion */ | 
|  | 6499 | pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); | 
|  | 6500 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 
|  | 6501 | if (notify_subdirs) | 
|  | 6502 | pSMB->WatchTree = 1; /* one byte - no le conversion needed */ | 
|  | 6503 | pSMB->Reserved2 = 0; | 
|  | 6504 | pSMB->CompletionFilter = cpu_to_le32(filter); | 
|  | 6505 | pSMB->Fid = netfid; /* file handle always le */ | 
|  | 6506 | pSMB->ByteCount = 0; | 
|  | 6507 |  | 
|  | 6508 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 
|  | 6509 | (struct smb_hdr *)pSMBr, &bytes_returned, | 
|  | 6510 | CIFS_ASYNC_OP); | 
|  | 6511 | if (rc) { | 
|  | 6512 | cifs_dbg(FYI, "Error in Notify = %d\n", rc); | 
|  | 6513 | } else { | 
|  | 6514 | /* Add file to outstanding requests */ | 
|  | 6515 | /* BB change to kmem cache alloc */ | 
|  | 6516 | dnotify_req = kmalloc( | 
|  | 6517 | sizeof(struct dir_notify_req), | 
|  | 6518 | GFP_KERNEL); | 
|  | 6519 | if (dnotify_req) { | 
|  | 6520 | dnotify_req->Pid = pSMB->hdr.Pid; | 
|  | 6521 | dnotify_req->PidHigh = pSMB->hdr.PidHigh; | 
|  | 6522 | dnotify_req->Mid = pSMB->hdr.Mid; | 
|  | 6523 | dnotify_req->Tid = pSMB->hdr.Tid; | 
|  | 6524 | dnotify_req->Uid = pSMB->hdr.Uid; | 
|  | 6525 | dnotify_req->netfid = netfid; | 
|  | 6526 | dnotify_req->pfile = pfile; | 
|  | 6527 | dnotify_req->filter = filter; | 
|  | 6528 | dnotify_req->multishot = multishot; | 
|  | 6529 | spin_lock(&GlobalMid_Lock); | 
|  | 6530 | list_add_tail(&dnotify_req->lhead, | 
|  | 6531 | &GlobalDnotifyReqList); | 
|  | 6532 | spin_unlock(&GlobalMid_Lock); | 
|  | 6533 | } else | 
|  | 6534 | rc = -ENOMEM; | 
|  | 6535 | } | 
|  | 6536 | cifs_buf_release(pSMB); | 
|  | 6537 | return rc; | 
|  | 6538 | } | 
|  | 6539 | #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ |