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