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