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