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