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