gro: Allow tunnel stacking in the case of FOU/GUE
[linux/fpc-iii.git] / fs / cifs / cifssmb.c
blobf1a5067d54947cb017572585a177b70c072db2d4
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(&cifs_file_list_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(&cifs_file_list_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 wait_event_interruptible_timeout(server->response_q,
154 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
156 /* are we still trying to reconnect? */
157 if (server->tcpStatus != CifsNeedReconnect)
158 break;
161 * on "soft" mounts we wait once. Hard mounts keep
162 * retrying until process is killed or server comes
163 * back on-line
165 if (!tcon->retry) {
166 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
167 return -EHOSTDOWN;
171 if (!ses->need_reconnect && !tcon->need_reconnect)
172 return 0;
174 nls_codepage = load_nls_default();
177 * need to prevent multiple threads trying to simultaneously
178 * reconnect the same SMB session
180 mutex_lock(&ses->session_mutex);
181 rc = cifs_negotiate_protocol(0, ses);
182 if (rc == 0 && ses->need_reconnect)
183 rc = cifs_setup_session(0, ses, nls_codepage);
185 /* do we need to reconnect tcon? */
186 if (rc || !tcon->need_reconnect) {
187 mutex_unlock(&ses->session_mutex);
188 goto out;
191 cifs_mark_open_files_invalid(tcon);
192 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
193 mutex_unlock(&ses->session_mutex);
194 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
196 if (rc)
197 goto out;
199 atomic_inc(&tconInfoReconnectCount);
201 /* tell server Unix caps we support */
202 if (ses->capabilities & CAP_UNIX)
203 reset_cifs_unix_caps(0, tcon, NULL, NULL);
206 * Removed call to reopen open files here. It is safer (and faster) to
207 * reopen files one at a time as needed in read and write.
209 * FIXME: what about file locks? don't we need to reclaim them ASAP?
212 out:
214 * Check if handle based operation so we know whether we can continue
215 * or not without returning to caller to reset file handle
217 switch (smb_command) {
218 case SMB_COM_READ_ANDX:
219 case SMB_COM_WRITE_ANDX:
220 case SMB_COM_CLOSE:
221 case SMB_COM_FIND_CLOSE2:
222 case SMB_COM_LOCKING_ANDX:
223 rc = -EAGAIN;
226 unload_nls(nls_codepage);
227 return rc;
230 /* Allocate and return pointer to an SMB request buffer, and set basic
231 SMB information in the SMB header. If the return code is zero, this
232 function must have filled in request_buf pointer */
233 static int
234 small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
235 void **request_buf)
237 int rc;
239 rc = cifs_reconnect_tcon(tcon, smb_command);
240 if (rc)
241 return rc;
243 *request_buf = cifs_small_buf_get();
244 if (*request_buf == NULL) {
245 /* BB should we add a retry in here if not a writepage? */
246 return -ENOMEM;
249 header_assemble((struct smb_hdr *) *request_buf, smb_command,
250 tcon, wct);
252 if (tcon != NULL)
253 cifs_stats_inc(&tcon->num_smbs_sent);
255 return 0;
259 small_smb_init_no_tc(const int smb_command, const int wct,
260 struct cifs_ses *ses, void **request_buf)
262 int rc;
263 struct smb_hdr *buffer;
265 rc = small_smb_init(smb_command, wct, NULL, request_buf);
266 if (rc)
267 return rc;
269 buffer = (struct smb_hdr *)*request_buf;
270 buffer->Mid = get_next_mid(ses->server);
271 if (ses->capabilities & CAP_UNICODE)
272 buffer->Flags2 |= SMBFLG2_UNICODE;
273 if (ses->capabilities & CAP_STATUS32)
274 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
276 /* uid, tid can stay at zero as set in header assemble */
278 /* BB add support for turning on the signing when
279 this function is used after 1st of session setup requests */
281 return rc;
284 /* If the return code is zero, this function must fill in request_buf pointer */
285 static int
286 __smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
287 void **request_buf, void **response_buf)
289 *request_buf = cifs_buf_get();
290 if (*request_buf == NULL) {
291 /* BB should we add a retry in here if not a writepage? */
292 return -ENOMEM;
294 /* Although the original thought was we needed the response buf for */
295 /* potential retries of smb operations it turns out we can determine */
296 /* from the mid flags when the request buffer can be resent without */
297 /* having to use a second distinct buffer for the response */
298 if (response_buf)
299 *response_buf = *request_buf;
301 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
302 wct);
304 if (tcon != NULL)
305 cifs_stats_inc(&tcon->num_smbs_sent);
307 return 0;
310 /* If the return code is zero, this function must fill in request_buf pointer */
311 static int
312 smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
313 void **request_buf, void **response_buf)
315 int rc;
317 rc = cifs_reconnect_tcon(tcon, smb_command);
318 if (rc)
319 return rc;
321 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
324 static int
325 smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
326 void **request_buf, void **response_buf)
328 if (tcon->ses->need_reconnect || tcon->need_reconnect)
329 return -EHOSTDOWN;
331 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
334 static int validate_t2(struct smb_t2_rsp *pSMB)
336 unsigned int total_size;
338 /* check for plausible wct */
339 if (pSMB->hdr.WordCount < 10)
340 goto vt2_err;
342 /* check for parm and data offset going beyond end of smb */
343 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
344 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
345 goto vt2_err;
347 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
348 if (total_size >= 512)
349 goto vt2_err;
351 /* check that bcc is at least as big as parms + data, and that it is
352 * less than negotiated smb buffer
354 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
355 if (total_size > get_bcc(&pSMB->hdr) ||
356 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
357 goto vt2_err;
359 return 0;
360 vt2_err:
361 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
362 sizeof(struct smb_t2_rsp) + 16);
363 return -EINVAL;
366 static int
367 decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
369 int rc = 0;
370 u16 count;
371 char *guid = pSMBr->u.extended_response.GUID;
372 struct TCP_Server_Info *server = ses->server;
374 count = get_bcc(&pSMBr->hdr);
375 if (count < SMB1_CLIENT_GUID_SIZE)
376 return -EIO;
378 spin_lock(&cifs_tcp_ses_lock);
379 if (server->srv_count > 1) {
380 spin_unlock(&cifs_tcp_ses_lock);
381 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
382 cifs_dbg(FYI, "server UID changed\n");
383 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
385 } else {
386 spin_unlock(&cifs_tcp_ses_lock);
387 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
390 if (count == SMB1_CLIENT_GUID_SIZE) {
391 server->sec_ntlmssp = true;
392 } else {
393 count -= SMB1_CLIENT_GUID_SIZE;
394 rc = decode_negTokenInit(
395 pSMBr->u.extended_response.SecurityBlob, count, server);
396 if (rc != 1)
397 return -EINVAL;
400 return 0;
404 cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
406 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
407 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
408 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
411 * Is signing required by mnt options? If not then check
412 * global_secflags to see if it is there.
414 if (!mnt_sign_required)
415 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
416 CIFSSEC_MUST_SIGN);
419 * If signing is required then it's automatically enabled too,
420 * otherwise, check to see if the secflags allow it.
422 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
423 (global_secflags & CIFSSEC_MAY_SIGN);
425 /* If server requires signing, does client allow it? */
426 if (srv_sign_required) {
427 if (!mnt_sign_enabled) {
428 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
429 return -ENOTSUPP;
431 server->sign = true;
434 /* If client requires signing, does server allow it? */
435 if (mnt_sign_required) {
436 if (!srv_sign_enabled) {
437 cifs_dbg(VFS, "Server does not support signing!");
438 return -ENOTSUPP;
440 server->sign = true;
443 return 0;
446 #ifdef CONFIG_CIFS_WEAK_PW_HASH
447 static int
448 decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
450 __s16 tmp;
451 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
453 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
454 return -EOPNOTSUPP;
456 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
457 server->maxReq = min_t(unsigned int,
458 le16_to_cpu(rsp->MaxMpxCount),
459 cifs_max_pending);
460 set_credits(server, server->maxReq);
461 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
462 /* even though we do not use raw we might as well set this
463 accurately, in case we ever find a need for it */
464 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
465 server->max_rw = 0xFF00;
466 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
467 } else {
468 server->max_rw = 0;/* do not need to use raw anyway */
469 server->capabilities = CAP_MPX_MODE;
471 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
472 if (tmp == -1) {
473 /* OS/2 often does not set timezone therefore
474 * we must use server time to calc time zone.
475 * Could deviate slightly from the right zone.
476 * Smallest defined timezone difference is 15 minutes
477 * (i.e. Nepal). Rounding up/down is done to match
478 * this requirement.
480 int val, seconds, remain, result;
481 struct timespec ts, utc;
482 utc = CURRENT_TIME;
483 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
484 rsp->SrvTime.Time, 0);
485 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
486 (int)ts.tv_sec, (int)utc.tv_sec,
487 (int)(utc.tv_sec - ts.tv_sec));
488 val = (int)(utc.tv_sec - ts.tv_sec);
489 seconds = abs(val);
490 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
491 remain = seconds % MIN_TZ_ADJ;
492 if (remain >= (MIN_TZ_ADJ / 2))
493 result += MIN_TZ_ADJ;
494 if (val < 0)
495 result = -result;
496 server->timeAdj = result;
497 } else {
498 server->timeAdj = (int)tmp;
499 server->timeAdj *= 60; /* also in seconds */
501 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
504 /* BB get server time for time conversions and add
505 code to use it and timezone since this is not UTC */
507 if (rsp->EncryptionKeyLength ==
508 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
509 memcpy(server->cryptkey, rsp->EncryptionKey,
510 CIFS_CRYPTO_KEY_SIZE);
511 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
512 return -EIO; /* need cryptkey unless plain text */
515 cifs_dbg(FYI, "LANMAN negotiated\n");
516 return 0;
518 #else
519 static inline int
520 decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
522 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
523 return -EOPNOTSUPP;
525 #endif
527 static bool
528 should_set_ext_sec_flag(enum securityEnum sectype)
530 switch (sectype) {
531 case RawNTLMSSP:
532 case Kerberos:
533 return true;
534 case Unspecified:
535 if (global_secflags &
536 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
537 return true;
538 /* Fallthrough */
539 default:
540 return false;
545 CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
547 NEGOTIATE_REQ *pSMB;
548 NEGOTIATE_RSP *pSMBr;
549 int rc = 0;
550 int bytes_returned;
551 int i;
552 struct TCP_Server_Info *server = ses->server;
553 u16 count;
555 if (!server) {
556 WARN(1, "%s: server is NULL!\n", __func__);
557 return -EIO;
560 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
561 (void **) &pSMB, (void **) &pSMBr);
562 if (rc)
563 return rc;
565 pSMB->hdr.Mid = get_next_mid(server);
566 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
568 if (should_set_ext_sec_flag(ses->sectype)) {
569 cifs_dbg(FYI, "Requesting extended security.");
570 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
573 count = 0;
574 for (i = 0; i < CIFS_NUM_PROT; i++) {
575 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
576 count += strlen(protocols[i].name) + 1;
577 /* null at end of source and target buffers anyway */
579 inc_rfc1001_len(pSMB, count);
580 pSMB->ByteCount = cpu_to_le16(count);
582 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
583 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
584 if (rc != 0)
585 goto neg_err_exit;
587 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
588 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
589 /* Check wct = 1 error case */
590 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
591 /* core returns wct = 1, but we do not ask for core - otherwise
592 small wct just comes when dialect index is -1 indicating we
593 could not negotiate a common dialect */
594 rc = -EOPNOTSUPP;
595 goto neg_err_exit;
596 } else if (pSMBr->hdr.WordCount == 13) {
597 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
598 rc = decode_lanman_negprot_rsp(server, pSMBr);
599 goto signing_check;
600 } else if (pSMBr->hdr.WordCount != 17) {
601 /* unknown wct */
602 rc = -EOPNOTSUPP;
603 goto neg_err_exit;
605 /* else wct == 17, NTLM or better */
607 server->sec_mode = pSMBr->SecurityMode;
608 if ((server->sec_mode & SECMODE_USER) == 0)
609 cifs_dbg(FYI, "share mode security\n");
611 /* one byte, so no need to convert this or EncryptionKeyLen from
612 little endian */
613 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
614 cifs_max_pending);
615 set_credits(server, server->maxReq);
616 /* probably no need to store and check maxvcs */
617 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
618 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
619 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
620 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
621 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
622 server->timeAdj *= 60;
624 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
625 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
626 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
627 CIFS_CRYPTO_KEY_SIZE);
628 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
629 server->capabilities & CAP_EXTENDED_SECURITY) &&
630 (pSMBr->EncryptionKeyLength == 0)) {
631 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
632 rc = decode_ext_sec_blob(ses, pSMBr);
633 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
634 rc = -EIO; /* no crypt key only if plain text pwd */
635 } else {
636 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
637 server->capabilities &= ~CAP_EXTENDED_SECURITY;
640 signing_check:
641 if (!rc)
642 rc = cifs_enable_signing(server, ses->sign);
643 neg_err_exit:
644 cifs_buf_release(pSMB);
646 cifs_dbg(FYI, "negprot rc %d\n", rc);
647 return rc;
651 CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
653 struct smb_hdr *smb_buffer;
654 int rc = 0;
656 cifs_dbg(FYI, "In tree disconnect\n");
658 /* BB: do we need to check this? These should never be NULL. */
659 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
660 return -EIO;
663 * No need to return error on this operation if tid invalidated and
664 * closed on server already e.g. due to tcp session crashing. Also,
665 * the tcon is no longer on the list, so no need to take lock before
666 * checking this.
668 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
669 return 0;
671 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
672 (void **)&smb_buffer);
673 if (rc)
674 return rc;
676 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
677 if (rc)
678 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
680 /* No need to return error on this operation if tid invalidated and
681 closed on server already e.g. due to tcp session crashing */
682 if (rc == -EAGAIN)
683 rc = 0;
685 return rc;
689 * This is a no-op for now. We're not really interested in the reply, but
690 * rather in the fact that the server sent one and that server->lstrp
691 * gets updated.
693 * FIXME: maybe we should consider checking that the reply matches request?
695 static void
696 cifs_echo_callback(struct mid_q_entry *mid)
698 struct TCP_Server_Info *server = mid->callback_data;
700 DeleteMidQEntry(mid);
701 add_credits(server, 1, CIFS_ECHO_OP);
705 CIFSSMBEcho(struct TCP_Server_Info *server)
707 ECHO_REQ *smb;
708 int rc = 0;
709 struct kvec iov;
710 struct smb_rqst rqst = { .rq_iov = &iov,
711 .rq_nvec = 1 };
713 cifs_dbg(FYI, "In echo request\n");
715 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
716 if (rc)
717 return rc;
719 /* set up echo request */
720 smb->hdr.Tid = 0xffff;
721 smb->hdr.WordCount = 1;
722 put_unaligned_le16(1, &smb->EchoCount);
723 put_bcc(1, &smb->hdr);
724 smb->Data[0] = 'a';
725 inc_rfc1001_len(smb, 3);
726 iov.iov_base = smb;
727 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
729 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
730 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
731 if (rc)
732 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
734 cifs_small_buf_release(smb);
736 return rc;
740 CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
742 LOGOFF_ANDX_REQ *pSMB;
743 int rc = 0;
745 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
748 * BB: do we need to check validity of ses and server? They should
749 * always be valid since we have an active reference. If not, that
750 * should probably be a BUG()
752 if (!ses || !ses->server)
753 return -EIO;
755 mutex_lock(&ses->session_mutex);
756 if (ses->need_reconnect)
757 goto session_already_dead; /* no need to send SMBlogoff if uid
758 already closed due to reconnect */
759 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
760 if (rc) {
761 mutex_unlock(&ses->session_mutex);
762 return rc;
765 pSMB->hdr.Mid = get_next_mid(ses->server);
767 if (ses->server->sign)
768 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
770 pSMB->hdr.Uid = ses->Suid;
772 pSMB->AndXCommand = 0xFF;
773 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
774 session_already_dead:
775 mutex_unlock(&ses->session_mutex);
777 /* if session dead then we do not need to do ulogoff,
778 since server closed smb session, no sense reporting
779 error */
780 if (rc == -EAGAIN)
781 rc = 0;
782 return rc;
786 CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
787 const char *fileName, __u16 type,
788 const struct nls_table *nls_codepage, int remap)
790 TRANSACTION2_SPI_REQ *pSMB = NULL;
791 TRANSACTION2_SPI_RSP *pSMBr = NULL;
792 struct unlink_psx_rq *pRqD;
793 int name_len;
794 int rc = 0;
795 int bytes_returned = 0;
796 __u16 params, param_offset, offset, byte_count;
798 cifs_dbg(FYI, "In POSIX delete\n");
799 PsxDelete:
800 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
801 (void **) &pSMBr);
802 if (rc)
803 return rc;
805 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
806 name_len =
807 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
808 PATH_MAX, nls_codepage, remap);
809 name_len++; /* trailing null */
810 name_len *= 2;
811 } else { /* BB add path length overrun check */
812 name_len = strnlen(fileName, PATH_MAX);
813 name_len++; /* trailing null */
814 strncpy(pSMB->FileName, fileName, name_len);
817 params = 6 + name_len;
818 pSMB->MaxParameterCount = cpu_to_le16(2);
819 pSMB->MaxDataCount = 0; /* BB double check this with jra */
820 pSMB->MaxSetupCount = 0;
821 pSMB->Reserved = 0;
822 pSMB->Flags = 0;
823 pSMB->Timeout = 0;
824 pSMB->Reserved2 = 0;
825 param_offset = offsetof(struct smb_com_transaction2_spi_req,
826 InformationLevel) - 4;
827 offset = param_offset + params;
829 /* Setup pointer to Request Data (inode type) */
830 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
831 pRqD->type = cpu_to_le16(type);
832 pSMB->ParameterOffset = cpu_to_le16(param_offset);
833 pSMB->DataOffset = cpu_to_le16(offset);
834 pSMB->SetupCount = 1;
835 pSMB->Reserved3 = 0;
836 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
837 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
839 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
840 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
841 pSMB->ParameterCount = cpu_to_le16(params);
842 pSMB->TotalParameterCount = pSMB->ParameterCount;
843 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
844 pSMB->Reserved4 = 0;
845 inc_rfc1001_len(pSMB, byte_count);
846 pSMB->ByteCount = cpu_to_le16(byte_count);
847 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
848 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
849 if (rc)
850 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
851 cifs_buf_release(pSMB);
853 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
855 if (rc == -EAGAIN)
856 goto PsxDelete;
858 return rc;
862 CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
863 struct cifs_sb_info *cifs_sb)
865 DELETE_FILE_REQ *pSMB = NULL;
866 DELETE_FILE_RSP *pSMBr = NULL;
867 int rc = 0;
868 int bytes_returned;
869 int name_len;
870 int remap = cifs_remap(cifs_sb);
872 DelFileRetry:
873 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
874 (void **) &pSMBr);
875 if (rc)
876 return rc;
878 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
879 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
880 PATH_MAX, cifs_sb->local_nls,
881 remap);
882 name_len++; /* trailing null */
883 name_len *= 2;
884 } else { /* BB improve check for buffer overruns BB */
885 name_len = strnlen(name, PATH_MAX);
886 name_len++; /* trailing null */
887 strncpy(pSMB->fileName, name, name_len);
889 pSMB->SearchAttributes =
890 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
891 pSMB->BufferFormat = 0x04;
892 inc_rfc1001_len(pSMB, name_len + 1);
893 pSMB->ByteCount = cpu_to_le16(name_len + 1);
894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
896 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
897 if (rc)
898 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
900 cifs_buf_release(pSMB);
901 if (rc == -EAGAIN)
902 goto DelFileRetry;
904 return rc;
908 CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
909 struct cifs_sb_info *cifs_sb)
911 DELETE_DIRECTORY_REQ *pSMB = NULL;
912 DELETE_DIRECTORY_RSP *pSMBr = NULL;
913 int rc = 0;
914 int bytes_returned;
915 int name_len;
916 int remap = cifs_remap(cifs_sb);
918 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
919 RmDirRetry:
920 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
921 (void **) &pSMBr);
922 if (rc)
923 return rc;
925 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
926 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
927 PATH_MAX, cifs_sb->local_nls,
928 remap);
929 name_len++; /* trailing null */
930 name_len *= 2;
931 } else { /* BB improve check for buffer overruns BB */
932 name_len = strnlen(name, PATH_MAX);
933 name_len++; /* trailing null */
934 strncpy(pSMB->DirName, name, name_len);
937 pSMB->BufferFormat = 0x04;
938 inc_rfc1001_len(pSMB, name_len + 1);
939 pSMB->ByteCount = cpu_to_le16(name_len + 1);
940 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
941 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
942 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
943 if (rc)
944 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
946 cifs_buf_release(pSMB);
947 if (rc == -EAGAIN)
948 goto RmDirRetry;
949 return rc;
953 CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
954 struct cifs_sb_info *cifs_sb)
956 int rc = 0;
957 CREATE_DIRECTORY_REQ *pSMB = NULL;
958 CREATE_DIRECTORY_RSP *pSMBr = NULL;
959 int bytes_returned;
960 int name_len;
961 int remap = cifs_remap(cifs_sb);
963 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
964 MkDirRetry:
965 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
966 (void **) &pSMBr);
967 if (rc)
968 return rc;
970 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
971 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
972 PATH_MAX, cifs_sb->local_nls,
973 remap);
974 name_len++; /* trailing null */
975 name_len *= 2;
976 } else { /* BB improve check for buffer overruns BB */
977 name_len = strnlen(name, PATH_MAX);
978 name_len++; /* trailing null */
979 strncpy(pSMB->DirName, name, name_len);
982 pSMB->BufferFormat = 0x04;
983 inc_rfc1001_len(pSMB, name_len + 1);
984 pSMB->ByteCount = cpu_to_le16(name_len + 1);
985 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
986 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
987 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
988 if (rc)
989 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
991 cifs_buf_release(pSMB);
992 if (rc == -EAGAIN)
993 goto MkDirRetry;
994 return rc;
998 CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
999 __u32 posix_flags, __u64 mode, __u16 *netfid,
1000 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1001 const char *name, const struct nls_table *nls_codepage,
1002 int remap)
1004 TRANSACTION2_SPI_REQ *pSMB = NULL;
1005 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1006 int name_len;
1007 int rc = 0;
1008 int bytes_returned = 0;
1009 __u16 params, param_offset, offset, byte_count, count;
1010 OPEN_PSX_REQ *pdata;
1011 OPEN_PSX_RSP *psx_rsp;
1013 cifs_dbg(FYI, "In POSIX Create\n");
1014 PsxCreat:
1015 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1016 (void **) &pSMBr);
1017 if (rc)
1018 return rc;
1020 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1021 name_len =
1022 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1023 PATH_MAX, nls_codepage, remap);
1024 name_len++; /* trailing null */
1025 name_len *= 2;
1026 } else { /* BB improve the check for buffer overruns BB */
1027 name_len = strnlen(name, PATH_MAX);
1028 name_len++; /* trailing null */
1029 strncpy(pSMB->FileName, name, name_len);
1032 params = 6 + name_len;
1033 count = sizeof(OPEN_PSX_REQ);
1034 pSMB->MaxParameterCount = cpu_to_le16(2);
1035 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1036 pSMB->MaxSetupCount = 0;
1037 pSMB->Reserved = 0;
1038 pSMB->Flags = 0;
1039 pSMB->Timeout = 0;
1040 pSMB->Reserved2 = 0;
1041 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1042 InformationLevel) - 4;
1043 offset = param_offset + params;
1044 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1045 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1046 pdata->Permissions = cpu_to_le64(mode);
1047 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1048 pdata->OpenFlags = cpu_to_le32(*pOplock);
1049 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1050 pSMB->DataOffset = cpu_to_le16(offset);
1051 pSMB->SetupCount = 1;
1052 pSMB->Reserved3 = 0;
1053 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1054 byte_count = 3 /* pad */ + params + count;
1056 pSMB->DataCount = cpu_to_le16(count);
1057 pSMB->ParameterCount = cpu_to_le16(params);
1058 pSMB->TotalDataCount = pSMB->DataCount;
1059 pSMB->TotalParameterCount = pSMB->ParameterCount;
1060 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1061 pSMB->Reserved4 = 0;
1062 inc_rfc1001_len(pSMB, byte_count);
1063 pSMB->ByteCount = cpu_to_le16(byte_count);
1064 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1065 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1066 if (rc) {
1067 cifs_dbg(FYI, "Posix create returned %d\n", rc);
1068 goto psx_create_err;
1071 cifs_dbg(FYI, "copying inode info\n");
1072 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1074 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
1075 rc = -EIO; /* bad smb */
1076 goto psx_create_err;
1079 /* copy return information to pRetData */
1080 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1081 + le16_to_cpu(pSMBr->t2.DataOffset));
1083 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1084 if (netfid)
1085 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1086 /* Let caller know file was created so we can set the mode. */
1087 /* Do we care about the CreateAction in any other cases? */
1088 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1089 *pOplock |= CIFS_CREATE_ACTION;
1090 /* check to make sure response data is there */
1091 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1092 pRetData->Type = cpu_to_le32(-1); /* unknown */
1093 cifs_dbg(NOISY, "unknown type\n");
1094 } else {
1095 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
1096 + sizeof(FILE_UNIX_BASIC_INFO)) {
1097 cifs_dbg(VFS, "Open response data too small\n");
1098 pRetData->Type = cpu_to_le32(-1);
1099 goto psx_create_err;
1101 memcpy((char *) pRetData,
1102 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1103 sizeof(FILE_UNIX_BASIC_INFO));
1106 psx_create_err:
1107 cifs_buf_release(pSMB);
1109 if (posix_flags & SMB_O_DIRECTORY)
1110 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
1111 else
1112 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
1114 if (rc == -EAGAIN)
1115 goto PsxCreat;
1117 return rc;
1120 static __u16 convert_disposition(int disposition)
1122 __u16 ofun = 0;
1124 switch (disposition) {
1125 case FILE_SUPERSEDE:
1126 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1127 break;
1128 case FILE_OPEN:
1129 ofun = SMBOPEN_OAPPEND;
1130 break;
1131 case FILE_CREATE:
1132 ofun = SMBOPEN_OCREATE;
1133 break;
1134 case FILE_OPEN_IF:
1135 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1136 break;
1137 case FILE_OVERWRITE:
1138 ofun = SMBOPEN_OTRUNC;
1139 break;
1140 case FILE_OVERWRITE_IF:
1141 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1142 break;
1143 default:
1144 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
1145 ofun = SMBOPEN_OAPPEND; /* regular open */
1147 return ofun;
1150 static int
1151 access_flags_to_smbopen_mode(const int access_flags)
1153 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1155 if (masked_flags == GENERIC_READ)
1156 return SMBOPEN_READ;
1157 else if (masked_flags == GENERIC_WRITE)
1158 return SMBOPEN_WRITE;
1160 /* just go for read/write */
1161 return SMBOPEN_READWRITE;
1165 SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
1166 const char *fileName, const int openDisposition,
1167 const int access_flags, const int create_options, __u16 *netfid,
1168 int *pOplock, FILE_ALL_INFO *pfile_info,
1169 const struct nls_table *nls_codepage, int remap)
1171 int rc = -EACCES;
1172 OPENX_REQ *pSMB = NULL;
1173 OPENX_RSP *pSMBr = NULL;
1174 int bytes_returned;
1175 int name_len;
1176 __u16 count;
1178 OldOpenRetry:
1179 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1180 (void **) &pSMBr);
1181 if (rc)
1182 return rc;
1184 pSMB->AndXCommand = 0xFF; /* none */
1186 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1187 count = 1; /* account for one byte pad to word boundary */
1188 name_len =
1189 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1190 fileName, PATH_MAX, nls_codepage, remap);
1191 name_len++; /* trailing null */
1192 name_len *= 2;
1193 } else { /* BB improve check for buffer overruns BB */
1194 count = 0; /* no pad */
1195 name_len = strnlen(fileName, PATH_MAX);
1196 name_len++; /* trailing null */
1197 strncpy(pSMB->fileName, fileName, name_len);
1199 if (*pOplock & REQ_OPLOCK)
1200 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1201 else if (*pOplock & REQ_BATCHOPLOCK)
1202 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1204 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1205 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1206 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1207 /* set file as system file if special file such
1208 as fifo and server expecting SFU style and
1209 no Unix extensions */
1211 if (create_options & CREATE_OPTION_SPECIAL)
1212 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1213 else /* BB FIXME BB */
1214 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1216 if (create_options & CREATE_OPTION_READONLY)
1217 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1219 /* BB FIXME BB */
1220 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1221 CREATE_OPTIONS_MASK); */
1222 /* BB FIXME END BB */
1224 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1225 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1226 count += name_len;
1227 inc_rfc1001_len(pSMB, count);
1229 pSMB->ByteCount = cpu_to_le16(count);
1230 /* long_op set to 1 to allow for oplock break timeouts */
1231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1232 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1233 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
1234 if (rc) {
1235 cifs_dbg(FYI, "Error in Open = %d\n", rc);
1236 } else {
1237 /* BB verify if wct == 15 */
1239 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1241 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1242 /* Let caller know file was created so we can set the mode. */
1243 /* Do we care about the CreateAction in any other cases? */
1244 /* BB FIXME BB */
1245 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1246 *pOplock |= CIFS_CREATE_ACTION; */
1247 /* BB FIXME END */
1249 if (pfile_info) {
1250 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1251 pfile_info->LastAccessTime = 0; /* BB fixme */
1252 pfile_info->LastWriteTime = 0; /* BB fixme */
1253 pfile_info->ChangeTime = 0; /* BB fixme */
1254 pfile_info->Attributes =
1255 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1256 /* the file_info buf is endian converted by caller */
1257 pfile_info->AllocationSize =
1258 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1259 pfile_info->EndOfFile = pfile_info->AllocationSize;
1260 pfile_info->NumberOfLinks = cpu_to_le32(1);
1261 pfile_info->DeletePending = 0;
1265 cifs_buf_release(pSMB);
1266 if (rc == -EAGAIN)
1267 goto OldOpenRetry;
1268 return rc;
1272 CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1273 FILE_ALL_INFO *buf)
1275 int rc = -EACCES;
1276 OPEN_REQ *req = NULL;
1277 OPEN_RSP *rsp = NULL;
1278 int bytes_returned;
1279 int name_len;
1280 __u16 count;
1281 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1282 struct cifs_tcon *tcon = oparms->tcon;
1283 int remap = cifs_remap(cifs_sb);
1284 const struct nls_table *nls = cifs_sb->local_nls;
1285 int create_options = oparms->create_options;
1286 int desired_access = oparms->desired_access;
1287 int disposition = oparms->disposition;
1288 const char *path = oparms->path;
1290 openRetry:
1291 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1292 (void **)&rsp);
1293 if (rc)
1294 return rc;
1296 /* no commands go after this */
1297 req->AndXCommand = 0xFF;
1299 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1300 /* account for one byte pad to word boundary */
1301 count = 1;
1302 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1303 path, PATH_MAX, nls, remap);
1304 /* trailing null */
1305 name_len++;
1306 name_len *= 2;
1307 req->NameLength = cpu_to_le16(name_len);
1308 } else {
1309 /* BB improve check for buffer overruns BB */
1310 /* no pad */
1311 count = 0;
1312 name_len = strnlen(path, PATH_MAX);
1313 /* trailing null */
1314 name_len++;
1315 req->NameLength = cpu_to_le16(name_len);
1316 strncpy(req->fileName, path, name_len);
1319 if (*oplock & REQ_OPLOCK)
1320 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1321 else if (*oplock & REQ_BATCHOPLOCK)
1322 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1324 req->DesiredAccess = cpu_to_le32(desired_access);
1325 req->AllocationSize = 0;
1328 * Set file as system file if special file such as fifo and server
1329 * expecting SFU style and no Unix extensions.
1331 if (create_options & CREATE_OPTION_SPECIAL)
1332 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1333 else
1334 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1337 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1338 * sensitive checks for other servers such as Samba.
1340 if (tcon->ses->capabilities & CAP_UNIX)
1341 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1343 if (create_options & CREATE_OPTION_READONLY)
1344 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1346 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1347 req->CreateDisposition = cpu_to_le32(disposition);
1348 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1350 /* BB Expirement with various impersonation levels and verify */
1351 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1352 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
1354 count += name_len;
1355 inc_rfc1001_len(req, count);
1357 req->ByteCount = cpu_to_le16(count);
1358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1359 (struct smb_hdr *)rsp, &bytes_returned, 0);
1360 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
1361 if (rc) {
1362 cifs_dbg(FYI, "Error in Open = %d\n", rc);
1363 cifs_buf_release(req);
1364 if (rc == -EAGAIN)
1365 goto openRetry;
1366 return rc;
1369 /* 1 byte no need to le_to_cpu */
1370 *oplock = rsp->OplockLevel;
1371 /* cifs fid stays in le */
1372 oparms->fid->netfid = rsp->Fid;
1374 /* Let caller know file was created so we can set the mode. */
1375 /* Do we care about the CreateAction in any other cases? */
1376 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1377 *oplock |= CIFS_CREATE_ACTION;
1379 if (buf) {
1380 /* copy from CreationTime to Attributes */
1381 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1382 /* the file_info buf is endian converted by caller */
1383 buf->AllocationSize = rsp->AllocationSize;
1384 buf->EndOfFile = rsp->EndOfFile;
1385 buf->NumberOfLinks = cpu_to_le32(1);
1386 buf->DeletePending = 0;
1389 cifs_buf_release(req);
1390 return rc;
1394 * Discard any remaining data in the current SMB. To do this, we borrow the
1395 * current bigbuf.
1397 static int
1398 discard_remaining_data(struct TCP_Server_Info *server)
1400 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
1401 int remaining = rfclen + 4 - server->total_read;
1403 while (remaining > 0) {
1404 int length;
1406 length = cifs_read_from_socket(server, server->bigbuf,
1407 min_t(unsigned int, remaining,
1408 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
1409 if (length < 0)
1410 return length;
1411 server->total_read += length;
1412 remaining -= length;
1415 return 0;
1418 static int
1419 cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1421 int length;
1422 struct cifs_readdata *rdata = mid->callback_data;
1424 length = discard_remaining_data(server);
1425 dequeue_mid(mid, rdata->result);
1426 return length;
1430 cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1432 int length, len;
1433 unsigned int data_offset, data_len;
1434 struct cifs_readdata *rdata = mid->callback_data;
1435 char *buf = server->smallbuf;
1436 unsigned int buflen = get_rfc1002_length(buf) + 4;
1438 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1439 __func__, mid->mid, rdata->offset, rdata->bytes);
1442 * read the rest of READ_RSP header (sans Data array), or whatever we
1443 * can if there's not enough data. At this point, we've read down to
1444 * the Mid.
1446 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
1447 HEADER_SIZE(server) + 1;
1449 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1450 rdata->iov.iov_len = len;
1452 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
1453 if (length < 0)
1454 return length;
1455 server->total_read += length;
1457 if (server->ops->is_status_pending &&
1458 server->ops->is_status_pending(buf, server, 0)) {
1459 discard_remaining_data(server);
1460 return -1;
1463 /* Was the SMB read successful? */
1464 rdata->result = server->ops->map_error(buf, false);
1465 if (rdata->result != 0) {
1466 cifs_dbg(FYI, "%s: server returned error %d\n",
1467 __func__, rdata->result);
1468 return cifs_readv_discard(server, mid);
1471 /* Is there enough to get to the rest of the READ_RSP header? */
1472 if (server->total_read < server->vals->read_rsp_size) {
1473 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1474 __func__, server->total_read,
1475 server->vals->read_rsp_size);
1476 rdata->result = -EIO;
1477 return cifs_readv_discard(server, mid);
1480 data_offset = server->ops->read_data_offset(buf) + 4;
1481 if (data_offset < server->total_read) {
1483 * win2k8 sometimes sends an offset of 0 when the read
1484 * is beyond the EOF. Treat it as if the data starts just after
1485 * the header.
1487 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1488 __func__, data_offset);
1489 data_offset = server->total_read;
1490 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1491 /* data_offset is beyond the end of smallbuf */
1492 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1493 __func__, data_offset);
1494 rdata->result = -EIO;
1495 return cifs_readv_discard(server, mid);
1498 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1499 __func__, server->total_read, data_offset);
1501 len = data_offset - server->total_read;
1502 if (len > 0) {
1503 /* read any junk before data into the rest of smallbuf */
1504 rdata->iov.iov_base = buf + server->total_read;
1505 rdata->iov.iov_len = len;
1506 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
1507 if (length < 0)
1508 return length;
1509 server->total_read += length;
1512 /* set up first iov for signature check */
1513 rdata->iov.iov_base = buf;
1514 rdata->iov.iov_len = server->total_read;
1515 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1516 rdata->iov.iov_base, rdata->iov.iov_len);
1518 /* how much data is in the response? */
1519 data_len = server->ops->read_data_length(buf);
1520 if (data_offset + data_len > buflen) {
1521 /* data_len is corrupt -- discard frame */
1522 rdata->result = -EIO;
1523 return cifs_readv_discard(server, mid);
1526 length = rdata->read_into_pages(server, rdata, data_len);
1527 if (length < 0)
1528 return length;
1530 server->total_read += length;
1532 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1533 server->total_read, buflen, data_len);
1535 /* discard anything left over */
1536 if (server->total_read < buflen)
1537 return cifs_readv_discard(server, mid);
1539 dequeue_mid(mid, false);
1540 return length;
1543 static void
1544 cifs_readv_callback(struct mid_q_entry *mid)
1546 struct cifs_readdata *rdata = mid->callback_data;
1547 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1548 struct TCP_Server_Info *server = tcon->ses->server;
1549 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1550 .rq_nvec = 1,
1551 .rq_pages = rdata->pages,
1552 .rq_npages = rdata->nr_pages,
1553 .rq_pagesz = rdata->pagesz,
1554 .rq_tailsz = rdata->tailsz };
1556 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1557 __func__, mid->mid, mid->mid_state, rdata->result,
1558 rdata->bytes);
1560 switch (mid->mid_state) {
1561 case MID_RESPONSE_RECEIVED:
1562 /* result already set, check signature */
1563 if (server->sign) {
1564 int rc = 0;
1566 rc = cifs_verify_signature(&rqst, server,
1567 mid->sequence_number);
1568 if (rc)
1569 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1570 rc);
1572 /* FIXME: should this be counted toward the initiating task? */
1573 task_io_account_read(rdata->got_bytes);
1574 cifs_stats_bytes_read(tcon, rdata->got_bytes);
1575 break;
1576 case MID_REQUEST_SUBMITTED:
1577 case MID_RETRY_NEEDED:
1578 rdata->result = -EAGAIN;
1579 if (server->sign && rdata->got_bytes)
1580 /* reset bytes number since we can not check a sign */
1581 rdata->got_bytes = 0;
1582 /* FIXME: should this be counted toward the initiating task? */
1583 task_io_account_read(rdata->got_bytes);
1584 cifs_stats_bytes_read(tcon, rdata->got_bytes);
1585 break;
1586 default:
1587 rdata->result = -EIO;
1590 queue_work(cifsiod_wq, &rdata->work);
1591 DeleteMidQEntry(mid);
1592 add_credits(server, 1, 0);
1595 /* cifs_async_readv - send an async write, and set up mid to handle result */
1597 cifs_async_readv(struct cifs_readdata *rdata)
1599 int rc;
1600 READ_REQ *smb = NULL;
1601 int wct;
1602 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1603 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1604 .rq_nvec = 1 };
1606 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1607 __func__, rdata->offset, rdata->bytes);
1609 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1610 wct = 12;
1611 else {
1612 wct = 10; /* old style read */
1613 if ((rdata->offset >> 32) > 0) {
1614 /* can not handle this big offset for old */
1615 return -EIO;
1619 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1620 if (rc)
1621 return rc;
1623 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1624 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1626 smb->AndXCommand = 0xFF; /* none */
1627 smb->Fid = rdata->cfile->fid.netfid;
1628 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1629 if (wct == 12)
1630 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1631 smb->Remaining = 0;
1632 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1633 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1634 if (wct == 12)
1635 smb->ByteCount = 0;
1636 else {
1637 /* old style read */
1638 struct smb_com_readx_req *smbr =
1639 (struct smb_com_readx_req *)smb;
1640 smbr->ByteCount = 0;
1643 /* 4 for RFC1001 length + 1 for BCC */
1644 rdata->iov.iov_base = smb;
1645 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1647 kref_get(&rdata->refcount);
1648 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1649 cifs_readv_callback, rdata, 0);
1651 if (rc == 0)
1652 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
1653 else
1654 kref_put(&rdata->refcount, cifs_readdata_release);
1656 cifs_small_buf_release(smb);
1657 return rc;
1661 CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1662 unsigned int *nbytes, char **buf, int *pbuf_type)
1664 int rc = -EACCES;
1665 READ_REQ *pSMB = NULL;
1666 READ_RSP *pSMBr = NULL;
1667 char *pReadData = NULL;
1668 int wct;
1669 int resp_buf_type = 0;
1670 struct kvec iov[1];
1671 __u32 pid = io_parms->pid;
1672 __u16 netfid = io_parms->netfid;
1673 __u64 offset = io_parms->offset;
1674 struct cifs_tcon *tcon = io_parms->tcon;
1675 unsigned int count = io_parms->length;
1677 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
1678 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1679 wct = 12;
1680 else {
1681 wct = 10; /* old style read */
1682 if ((offset >> 32) > 0) {
1683 /* can not handle this big offset for old */
1684 return -EIO;
1688 *nbytes = 0;
1689 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1690 if (rc)
1691 return rc;
1693 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1694 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1696 /* tcon and ses pointer are checked in smb_init */
1697 if (tcon->ses->server == NULL)
1698 return -ECONNABORTED;
1700 pSMB->AndXCommand = 0xFF; /* none */
1701 pSMB->Fid = netfid;
1702 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1703 if (wct == 12)
1704 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1706 pSMB->Remaining = 0;
1707 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1708 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1709 if (wct == 12)
1710 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1711 else {
1712 /* old style read */
1713 struct smb_com_readx_req *pSMBW =
1714 (struct smb_com_readx_req *)pSMB;
1715 pSMBW->ByteCount = 0;
1718 iov[0].iov_base = (char *)pSMB;
1719 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
1720 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1721 &resp_buf_type, CIFS_LOG_ERROR);
1722 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
1723 pSMBr = (READ_RSP *)iov[0].iov_base;
1724 if (rc) {
1725 cifs_dbg(VFS, "Send error in read = %d\n", rc);
1726 } else {
1727 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1728 data_length = data_length << 16;
1729 data_length += le16_to_cpu(pSMBr->DataLength);
1730 *nbytes = data_length;
1732 /*check that DataLength would not go beyond end of SMB */
1733 if ((data_length > CIFSMaxBufSize)
1734 || (data_length > count)) {
1735 cifs_dbg(FYI, "bad length %d for count %d\n",
1736 data_length, count);
1737 rc = -EIO;
1738 *nbytes = 0;
1739 } else {
1740 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1741 le16_to_cpu(pSMBr->DataOffset);
1742 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1743 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
1744 rc = -EFAULT;
1745 }*/ /* can not use copy_to_user when using page cache*/
1746 if (*buf)
1747 memcpy(*buf, pReadData, data_length);
1751 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1752 if (*buf) {
1753 free_rsp_buf(resp_buf_type, iov[0].iov_base);
1754 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1755 /* return buffer to caller to free */
1756 *buf = iov[0].iov_base;
1757 if (resp_buf_type == CIFS_SMALL_BUFFER)
1758 *pbuf_type = CIFS_SMALL_BUFFER;
1759 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1760 *pbuf_type = CIFS_LARGE_BUFFER;
1761 } /* else no valid buffer on return - leave as null */
1763 /* Note: On -EAGAIN error only caller can retry on handle based calls
1764 since file handle passed in no longer valid */
1765 return rc;
1770 CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
1771 unsigned int *nbytes, const char *buf,
1772 const char __user *ubuf, const int long_op)
1774 int rc = -EACCES;
1775 WRITE_REQ *pSMB = NULL;
1776 WRITE_RSP *pSMBr = NULL;
1777 int bytes_returned, wct;
1778 __u32 bytes_sent;
1779 __u16 byte_count;
1780 __u32 pid = io_parms->pid;
1781 __u16 netfid = io_parms->netfid;
1782 __u64 offset = io_parms->offset;
1783 struct cifs_tcon *tcon = io_parms->tcon;
1784 unsigned int count = io_parms->length;
1786 *nbytes = 0;
1788 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
1789 if (tcon->ses == NULL)
1790 return -ECONNABORTED;
1792 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1793 wct = 14;
1794 else {
1795 wct = 12;
1796 if ((offset >> 32) > 0) {
1797 /* can not handle big offset for old srv */
1798 return -EIO;
1802 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1803 (void **) &pSMBr);
1804 if (rc)
1805 return rc;
1807 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1808 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1810 /* tcon and ses pointer are checked in smb_init */
1811 if (tcon->ses->server == NULL)
1812 return -ECONNABORTED;
1814 pSMB->AndXCommand = 0xFF; /* none */
1815 pSMB->Fid = netfid;
1816 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1817 if (wct == 14)
1818 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1820 pSMB->Reserved = 0xFFFFFFFF;
1821 pSMB->WriteMode = 0;
1822 pSMB->Remaining = 0;
1824 /* Can increase buffer size if buffer is big enough in some cases ie we
1825 can send more if LARGE_WRITE_X capability returned by the server and if
1826 our buffer is big enough or if we convert to iovecs on socket writes
1827 and eliminate the copy to the CIFS buffer */
1828 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1829 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1830 } else {
1831 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1832 & ~0xFF;
1835 if (bytes_sent > count)
1836 bytes_sent = count;
1837 pSMB->DataOffset =
1838 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1839 if (buf)
1840 memcpy(pSMB->Data, buf, bytes_sent);
1841 else if (ubuf) {
1842 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1843 cifs_buf_release(pSMB);
1844 return -EFAULT;
1846 } else if (count != 0) {
1847 /* No buffer */
1848 cifs_buf_release(pSMB);
1849 return -EINVAL;
1850 } /* else setting file size with write of zero bytes */
1851 if (wct == 14)
1852 byte_count = bytes_sent + 1; /* pad */
1853 else /* wct == 12 */
1854 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1856 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1857 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1858 inc_rfc1001_len(pSMB, byte_count);
1860 if (wct == 14)
1861 pSMB->ByteCount = cpu_to_le16(byte_count);
1862 else { /* old style write has byte count 4 bytes earlier
1863 so 4 bytes pad */
1864 struct smb_com_writex_req *pSMBW =
1865 (struct smb_com_writex_req *)pSMB;
1866 pSMBW->ByteCount = cpu_to_le16(byte_count);
1869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1870 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1871 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
1872 if (rc) {
1873 cifs_dbg(FYI, "Send error in write = %d\n", rc);
1874 } else {
1875 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1876 *nbytes = (*nbytes) << 16;
1877 *nbytes += le16_to_cpu(pSMBr->Count);
1880 * Mask off high 16 bits when bytes written as returned by the
1881 * server is greater than bytes requested by the client. Some
1882 * OS/2 servers are known to set incorrect CountHigh values.
1884 if (*nbytes > count)
1885 *nbytes &= 0xFFFF;
1888 cifs_buf_release(pSMB);
1890 /* Note: On -EAGAIN error only caller can retry on handle based calls
1891 since file handle passed in no longer valid */
1893 return rc;
1896 void
1897 cifs_writedata_release(struct kref *refcount)
1899 struct cifs_writedata *wdata = container_of(refcount,
1900 struct cifs_writedata, refcount);
1902 if (wdata->cfile)
1903 cifsFileInfo_put(wdata->cfile);
1905 kfree(wdata);
1909 * Write failed with a retryable error. Resend the write request. It's also
1910 * possible that the page was redirtied so re-clean the page.
1912 static void
1913 cifs_writev_requeue(struct cifs_writedata *wdata)
1915 int i, rc = 0;
1916 struct inode *inode = d_inode(wdata->cfile->dentry);
1917 struct TCP_Server_Info *server;
1918 unsigned int rest_len;
1920 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1921 i = 0;
1922 rest_len = wdata->bytes;
1923 do {
1924 struct cifs_writedata *wdata2;
1925 unsigned int j, nr_pages, wsize, tailsz, cur_len;
1927 wsize = server->ops->wp_retry_size(inode);
1928 if (wsize < rest_len) {
1929 nr_pages = wsize / PAGE_CACHE_SIZE;
1930 if (!nr_pages) {
1931 rc = -ENOTSUPP;
1932 break;
1934 cur_len = nr_pages * PAGE_CACHE_SIZE;
1935 tailsz = PAGE_CACHE_SIZE;
1936 } else {
1937 nr_pages = DIV_ROUND_UP(rest_len, PAGE_CACHE_SIZE);
1938 cur_len = rest_len;
1939 tailsz = rest_len - (nr_pages - 1) * PAGE_CACHE_SIZE;
1942 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1943 if (!wdata2) {
1944 rc = -ENOMEM;
1945 break;
1948 for (j = 0; j < nr_pages; j++) {
1949 wdata2->pages[j] = wdata->pages[i + j];
1950 lock_page(wdata2->pages[j]);
1951 clear_page_dirty_for_io(wdata2->pages[j]);
1954 wdata2->sync_mode = wdata->sync_mode;
1955 wdata2->nr_pages = nr_pages;
1956 wdata2->offset = page_offset(wdata2->pages[0]);
1957 wdata2->pagesz = PAGE_CACHE_SIZE;
1958 wdata2->tailsz = tailsz;
1959 wdata2->bytes = cur_len;
1961 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
1962 if (!wdata2->cfile) {
1963 cifs_dbg(VFS, "No writable handles for inode\n");
1964 rc = -EBADF;
1965 break;
1967 wdata2->pid = wdata2->cfile->pid;
1968 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
1970 for (j = 0; j < nr_pages; j++) {
1971 unlock_page(wdata2->pages[j]);
1972 if (rc != 0 && rc != -EAGAIN) {
1973 SetPageError(wdata2->pages[j]);
1974 end_page_writeback(wdata2->pages[j]);
1975 page_cache_release(wdata2->pages[j]);
1979 if (rc) {
1980 kref_put(&wdata2->refcount, cifs_writedata_release);
1981 if (rc == -EAGAIN)
1982 continue;
1983 break;
1986 rest_len -= cur_len;
1987 i += nr_pages;
1988 } while (i < wdata->nr_pages);
1990 mapping_set_error(inode->i_mapping, rc);
1991 kref_put(&wdata->refcount, cifs_writedata_release);
1994 void
1995 cifs_writev_complete(struct work_struct *work)
1997 struct cifs_writedata *wdata = container_of(work,
1998 struct cifs_writedata, work);
1999 struct inode *inode = d_inode(wdata->cfile->dentry);
2000 int i = 0;
2002 if (wdata->result == 0) {
2003 spin_lock(&inode->i_lock);
2004 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
2005 spin_unlock(&inode->i_lock);
2006 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2007 wdata->bytes);
2008 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2009 return cifs_writev_requeue(wdata);
2011 for (i = 0; i < wdata->nr_pages; i++) {
2012 struct page *page = wdata->pages[i];
2013 if (wdata->result == -EAGAIN)
2014 __set_page_dirty_nobuffers(page);
2015 else if (wdata->result < 0)
2016 SetPageError(page);
2017 end_page_writeback(page);
2018 page_cache_release(page);
2020 if (wdata->result != -EAGAIN)
2021 mapping_set_error(inode->i_mapping, wdata->result);
2022 kref_put(&wdata->refcount, cifs_writedata_release);
2025 struct cifs_writedata *
2026 cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
2028 struct cifs_writedata *wdata;
2030 /* writedata + number of page pointers */
2031 wdata = kzalloc(sizeof(*wdata) +
2032 sizeof(struct page *) * nr_pages, GFP_NOFS);
2033 if (wdata != NULL) {
2034 kref_init(&wdata->refcount);
2035 INIT_LIST_HEAD(&wdata->list);
2036 init_completion(&wdata->done);
2037 INIT_WORK(&wdata->work, complete);
2039 return wdata;
2043 * Check the mid_state and signature on received buffer (if any), and queue the
2044 * workqueue completion task.
2046 static void
2047 cifs_writev_callback(struct mid_q_entry *mid)
2049 struct cifs_writedata *wdata = mid->callback_data;
2050 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
2051 unsigned int written;
2052 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2054 switch (mid->mid_state) {
2055 case MID_RESPONSE_RECEIVED:
2056 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2057 if (wdata->result != 0)
2058 break;
2060 written = le16_to_cpu(smb->CountHigh);
2061 written <<= 16;
2062 written += le16_to_cpu(smb->Count);
2064 * Mask off high 16 bits when bytes written as returned
2065 * by the server is greater than bytes requested by the
2066 * client. OS/2 servers are known to set incorrect
2067 * CountHigh values.
2069 if (written > wdata->bytes)
2070 written &= 0xFFFF;
2072 if (written < wdata->bytes)
2073 wdata->result = -ENOSPC;
2074 else
2075 wdata->bytes = written;
2076 break;
2077 case MID_REQUEST_SUBMITTED:
2078 case MID_RETRY_NEEDED:
2079 wdata->result = -EAGAIN;
2080 break;
2081 default:
2082 wdata->result = -EIO;
2083 break;
2086 queue_work(cifsiod_wq, &wdata->work);
2087 DeleteMidQEntry(mid);
2088 add_credits(tcon->ses->server, 1, 0);
2091 /* cifs_async_writev - send an async write, and set up mid to handle result */
2093 cifs_async_writev(struct cifs_writedata *wdata,
2094 void (*release)(struct kref *kref))
2096 int rc = -EACCES;
2097 WRITE_REQ *smb = NULL;
2098 int wct;
2099 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
2100 struct kvec iov;
2101 struct smb_rqst rqst = { };
2103 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2104 wct = 14;
2105 } else {
2106 wct = 12;
2107 if (wdata->offset >> 32 > 0) {
2108 /* can not handle big offset for old srv */
2109 return -EIO;
2113 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2114 if (rc)
2115 goto async_writev_out;
2117 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2118 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
2120 smb->AndXCommand = 0xFF; /* none */
2121 smb->Fid = wdata->cfile->fid.netfid;
2122 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2123 if (wct == 14)
2124 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2125 smb->Reserved = 0xFFFFFFFF;
2126 smb->WriteMode = 0;
2127 smb->Remaining = 0;
2129 smb->DataOffset =
2130 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2132 /* 4 for RFC1001 length + 1 for BCC */
2133 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2134 iov.iov_base = smb;
2136 rqst.rq_iov = &iov;
2137 rqst.rq_nvec = 1;
2138 rqst.rq_pages = wdata->pages;
2139 rqst.rq_npages = wdata->nr_pages;
2140 rqst.rq_pagesz = wdata->pagesz;
2141 rqst.rq_tailsz = wdata->tailsz;
2143 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2144 wdata->offset, wdata->bytes);
2146 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2147 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2149 if (wct == 14) {
2150 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2151 put_bcc(wdata->bytes + 1, &smb->hdr);
2152 } else {
2153 /* wct == 12 */
2154 struct smb_com_writex_req *smbw =
2155 (struct smb_com_writex_req *)smb;
2156 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2157 put_bcc(wdata->bytes + 5, &smbw->hdr);
2158 iov.iov_len += 4; /* pad bigger by four bytes */
2161 kref_get(&wdata->refcount);
2162 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2163 cifs_writev_callback, wdata, 0);
2165 if (rc == 0)
2166 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
2167 else
2168 kref_put(&wdata->refcount, release);
2170 async_writev_out:
2171 cifs_small_buf_release(smb);
2172 return rc;
2176 CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
2177 unsigned int *nbytes, struct kvec *iov, int n_vec)
2179 int rc = -EACCES;
2180 WRITE_REQ *pSMB = NULL;
2181 int wct;
2182 int smb_hdr_len;
2183 int resp_buf_type = 0;
2184 __u32 pid = io_parms->pid;
2185 __u16 netfid = io_parms->netfid;
2186 __u64 offset = io_parms->offset;
2187 struct cifs_tcon *tcon = io_parms->tcon;
2188 unsigned int count = io_parms->length;
2190 *nbytes = 0;
2192 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
2194 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2195 wct = 14;
2196 } else {
2197 wct = 12;
2198 if ((offset >> 32) > 0) {
2199 /* can not handle big offset for old srv */
2200 return -EIO;
2203 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
2204 if (rc)
2205 return rc;
2207 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2208 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2210 /* tcon and ses pointer are checked in smb_init */
2211 if (tcon->ses->server == NULL)
2212 return -ECONNABORTED;
2214 pSMB->AndXCommand = 0xFF; /* none */
2215 pSMB->Fid = netfid;
2216 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
2217 if (wct == 14)
2218 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
2219 pSMB->Reserved = 0xFFFFFFFF;
2220 pSMB->WriteMode = 0;
2221 pSMB->Remaining = 0;
2223 pSMB->DataOffset =
2224 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2226 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2227 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
2228 /* header + 1 byte pad */
2229 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
2230 if (wct == 14)
2231 inc_rfc1001_len(pSMB, count + 1);
2232 else /* wct == 12 */
2233 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
2234 if (wct == 14)
2235 pSMB->ByteCount = cpu_to_le16(count + 1);
2236 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
2237 struct smb_com_writex_req *pSMBW =
2238 (struct smb_com_writex_req *)pSMB;
2239 pSMBW->ByteCount = cpu_to_le16(count + 5);
2241 iov[0].iov_base = pSMB;
2242 if (wct == 14)
2243 iov[0].iov_len = smb_hdr_len + 4;
2244 else /* wct == 12 pad bigger by four bytes */
2245 iov[0].iov_len = smb_hdr_len + 8;
2248 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
2249 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
2250 if (rc) {
2251 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
2252 } else if (resp_buf_type == 0) {
2253 /* presumably this can not happen, but best to be safe */
2254 rc = -EIO;
2255 } else {
2256 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
2257 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2258 *nbytes = (*nbytes) << 16;
2259 *nbytes += le16_to_cpu(pSMBr->Count);
2262 * Mask off high 16 bits when bytes written as returned by the
2263 * server is greater than bytes requested by the client. OS/2
2264 * servers are known to set incorrect CountHigh values.
2266 if (*nbytes > count)
2267 *nbytes &= 0xFFFF;
2270 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2271 free_rsp_buf(resp_buf_type, iov[0].iov_base);
2273 /* Note: On -EAGAIN error only caller can retry on handle based calls
2274 since file handle passed in no longer valid */
2276 return rc;
2279 int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2280 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
2281 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2283 int rc = 0;
2284 LOCK_REQ *pSMB = NULL;
2285 struct kvec iov[2];
2286 int resp_buf_type;
2287 __u16 count;
2289 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2290 num_lock, num_unlock);
2292 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2293 if (rc)
2294 return rc;
2296 pSMB->Timeout = 0;
2297 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2298 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2299 pSMB->LockType = lock_type;
2300 pSMB->AndXCommand = 0xFF; /* none */
2301 pSMB->Fid = netfid; /* netfid stays le */
2303 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2304 inc_rfc1001_len(pSMB, count);
2305 pSMB->ByteCount = cpu_to_le16(count);
2307 iov[0].iov_base = (char *)pSMB;
2308 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2309 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2310 iov[1].iov_base = (char *)buf;
2311 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2313 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
2314 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2315 if (rc)
2316 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
2318 return rc;
2322 CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
2323 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
2324 const __u64 offset, const __u32 numUnlock,
2325 const __u32 numLock, const __u8 lockType,
2326 const bool waitFlag, const __u8 oplock_level)
2328 int rc = 0;
2329 LOCK_REQ *pSMB = NULL;
2330 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
2331 int bytes_returned;
2332 int flags = 0;
2333 __u16 count;
2335 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2336 (int)waitFlag, numLock);
2337 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2339 if (rc)
2340 return rc;
2342 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
2343 /* no response expected */
2344 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
2345 pSMB->Timeout = 0;
2346 } else if (waitFlag) {
2347 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2348 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2349 } else {
2350 pSMB->Timeout = 0;
2353 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2354 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2355 pSMB->LockType = lockType;
2356 pSMB->OplockLevel = oplock_level;
2357 pSMB->AndXCommand = 0xFF; /* none */
2358 pSMB->Fid = smb_file_id; /* netfid stays le */
2360 if ((numLock != 0) || (numUnlock != 0)) {
2361 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
2362 /* BB where to store pid high? */
2363 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2364 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2365 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2366 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2367 count = sizeof(LOCKING_ANDX_RANGE);
2368 } else {
2369 /* oplock break */
2370 count = 0;
2372 inc_rfc1001_len(pSMB, count);
2373 pSMB->ByteCount = cpu_to_le16(count);
2375 if (waitFlag) {
2376 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2377 (struct smb_hdr *) pSMB, &bytes_returned);
2378 cifs_small_buf_release(pSMB);
2379 } else {
2380 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
2381 /* SMB buffer freed by function above */
2383 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
2384 if (rc)
2385 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
2387 /* Note: On -EAGAIN error only caller can retry on handle based calls
2388 since file handle passed in no longer valid */
2389 return rc;
2393 CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
2394 const __u16 smb_file_id, const __u32 netpid,
2395 const loff_t start_offset, const __u64 len,
2396 struct file_lock *pLockData, const __u16 lock_type,
2397 const bool waitFlag)
2399 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2400 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2401 struct cifs_posix_lock *parm_data;
2402 int rc = 0;
2403 int timeout = 0;
2404 int bytes_returned = 0;
2405 int resp_buf_type = 0;
2406 __u16 params, param_offset, offset, byte_count, count;
2407 struct kvec iov[1];
2409 cifs_dbg(FYI, "Posix Lock\n");
2411 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2413 if (rc)
2414 return rc;
2416 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2418 params = 6;
2419 pSMB->MaxSetupCount = 0;
2420 pSMB->Reserved = 0;
2421 pSMB->Flags = 0;
2422 pSMB->Reserved2 = 0;
2423 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2424 offset = param_offset + params;
2426 count = sizeof(struct cifs_posix_lock);
2427 pSMB->MaxParameterCount = cpu_to_le16(2);
2428 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2429 pSMB->SetupCount = 1;
2430 pSMB->Reserved3 = 0;
2431 if (pLockData)
2432 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2433 else
2434 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2435 byte_count = 3 /* pad */ + params + count;
2436 pSMB->DataCount = cpu_to_le16(count);
2437 pSMB->ParameterCount = cpu_to_le16(params);
2438 pSMB->TotalDataCount = pSMB->DataCount;
2439 pSMB->TotalParameterCount = pSMB->ParameterCount;
2440 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2441 parm_data = (struct cifs_posix_lock *)
2442 (((char *) &pSMB->hdr.Protocol) + offset);
2444 parm_data->lock_type = cpu_to_le16(lock_type);
2445 if (waitFlag) {
2446 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2447 parm_data->lock_flags = cpu_to_le16(1);
2448 pSMB->Timeout = cpu_to_le32(-1);
2449 } else
2450 pSMB->Timeout = 0;
2452 parm_data->pid = cpu_to_le32(netpid);
2453 parm_data->start = cpu_to_le64(start_offset);
2454 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
2456 pSMB->DataOffset = cpu_to_le16(offset);
2457 pSMB->Fid = smb_file_id;
2458 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2459 pSMB->Reserved4 = 0;
2460 inc_rfc1001_len(pSMB, byte_count);
2461 pSMB->ByteCount = cpu_to_le16(byte_count);
2462 if (waitFlag) {
2463 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2464 (struct smb_hdr *) pSMBr, &bytes_returned);
2465 } else {
2466 iov[0].iov_base = (char *)pSMB;
2467 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
2468 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2469 &resp_buf_type, timeout);
2470 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2471 not try to free it twice below on exit */
2472 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
2475 if (rc) {
2476 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
2477 } else if (pLockData) {
2478 /* lock structure can be returned on get */
2479 __u16 data_offset;
2480 __u16 data_count;
2481 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2483 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
2484 rc = -EIO; /* bad smb */
2485 goto plk_err_exit;
2487 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2488 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2489 if (data_count < sizeof(struct cifs_posix_lock)) {
2490 rc = -EIO;
2491 goto plk_err_exit;
2493 parm_data = (struct cifs_posix_lock *)
2494 ((char *)&pSMBr->hdr.Protocol + data_offset);
2495 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
2496 pLockData->fl_type = F_UNLCK;
2497 else {
2498 if (parm_data->lock_type ==
2499 cpu_to_le16(CIFS_RDLCK))
2500 pLockData->fl_type = F_RDLCK;
2501 else if (parm_data->lock_type ==
2502 cpu_to_le16(CIFS_WRLCK))
2503 pLockData->fl_type = F_WRLCK;
2505 pLockData->fl_start = le64_to_cpu(parm_data->start);
2506 pLockData->fl_end = pLockData->fl_start +
2507 le64_to_cpu(parm_data->length) - 1;
2508 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
2512 plk_err_exit:
2513 if (pSMB)
2514 cifs_small_buf_release(pSMB);
2516 free_rsp_buf(resp_buf_type, iov[0].iov_base);
2518 /* Note: On -EAGAIN error only caller can retry on handle based calls
2519 since file handle passed in no longer valid */
2521 return rc;
2526 CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
2528 int rc = 0;
2529 CLOSE_REQ *pSMB = NULL;
2530 cifs_dbg(FYI, "In CIFSSMBClose\n");
2532 /* do not retry on dead session on close */
2533 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
2534 if (rc == -EAGAIN)
2535 return 0;
2536 if (rc)
2537 return rc;
2539 pSMB->FileID = (__u16) smb_file_id;
2540 pSMB->LastWriteTime = 0xFFFFFFFF;
2541 pSMB->ByteCount = 0;
2542 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
2543 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
2544 if (rc) {
2545 if (rc != -EINTR) {
2546 /* EINTR is expected when user ctl-c to kill app */
2547 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
2551 /* Since session is dead, file will be closed on server already */
2552 if (rc == -EAGAIN)
2553 rc = 0;
2555 return rc;
2559 CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
2561 int rc = 0;
2562 FLUSH_REQ *pSMB = NULL;
2563 cifs_dbg(FYI, "In CIFSSMBFlush\n");
2565 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2566 if (rc)
2567 return rc;
2569 pSMB->FileID = (__u16) smb_file_id;
2570 pSMB->ByteCount = 0;
2571 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
2572 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
2573 if (rc)
2574 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
2576 return rc;
2580 CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
2581 const char *from_name, const char *to_name,
2582 struct cifs_sb_info *cifs_sb)
2584 int rc = 0;
2585 RENAME_REQ *pSMB = NULL;
2586 RENAME_RSP *pSMBr = NULL;
2587 int bytes_returned;
2588 int name_len, name_len2;
2589 __u16 count;
2590 int remap = cifs_remap(cifs_sb);
2592 cifs_dbg(FYI, "In CIFSSMBRename\n");
2593 renameRetry:
2594 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2595 (void **) &pSMBr);
2596 if (rc)
2597 return rc;
2599 pSMB->BufferFormat = 0x04;
2600 pSMB->SearchAttributes =
2601 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2602 ATTR_DIRECTORY);
2604 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2605 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2606 from_name, PATH_MAX,
2607 cifs_sb->local_nls, remap);
2608 name_len++; /* trailing null */
2609 name_len *= 2;
2610 pSMB->OldFileName[name_len] = 0x04; /* pad */
2611 /* protocol requires ASCII signature byte on Unicode string */
2612 pSMB->OldFileName[name_len + 1] = 0x00;
2613 name_len2 =
2614 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2615 to_name, PATH_MAX, cifs_sb->local_nls,
2616 remap);
2617 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2618 name_len2 *= 2; /* convert to bytes */
2619 } else { /* BB improve the check for buffer overruns BB */
2620 name_len = strnlen(from_name, PATH_MAX);
2621 name_len++; /* trailing null */
2622 strncpy(pSMB->OldFileName, from_name, name_len);
2623 name_len2 = strnlen(to_name, PATH_MAX);
2624 name_len2++; /* trailing null */
2625 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2626 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
2627 name_len2++; /* trailing null */
2628 name_len2++; /* signature byte */
2631 count = 1 /* 1st signature byte */ + name_len + name_len2;
2632 inc_rfc1001_len(pSMB, count);
2633 pSMB->ByteCount = cpu_to_le16(count);
2635 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2636 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2637 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
2638 if (rc)
2639 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
2641 cifs_buf_release(pSMB);
2643 if (rc == -EAGAIN)
2644 goto renameRetry;
2646 return rc;
2649 int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
2650 int netfid, const char *target_name,
2651 const struct nls_table *nls_codepage, int remap)
2653 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2654 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2655 struct set_file_rename *rename_info;
2656 char *data_offset;
2657 char dummy_string[30];
2658 int rc = 0;
2659 int bytes_returned = 0;
2660 int len_of_str;
2661 __u16 params, param_offset, offset, count, byte_count;
2663 cifs_dbg(FYI, "Rename to File by handle\n");
2664 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2665 (void **) &pSMBr);
2666 if (rc)
2667 return rc;
2669 params = 6;
2670 pSMB->MaxSetupCount = 0;
2671 pSMB->Reserved = 0;
2672 pSMB->Flags = 0;
2673 pSMB->Timeout = 0;
2674 pSMB->Reserved2 = 0;
2675 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2676 offset = param_offset + params;
2678 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2679 rename_info = (struct set_file_rename *) data_offset;
2680 pSMB->MaxParameterCount = cpu_to_le16(2);
2681 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2682 pSMB->SetupCount = 1;
2683 pSMB->Reserved3 = 0;
2684 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2685 byte_count = 3 /* pad */ + params;
2686 pSMB->ParameterCount = cpu_to_le16(params);
2687 pSMB->TotalParameterCount = pSMB->ParameterCount;
2688 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2689 pSMB->DataOffset = cpu_to_le16(offset);
2690 /* construct random name ".cifs_tmp<inodenum><mid>" */
2691 rename_info->overwrite = cpu_to_le32(1);
2692 rename_info->root_fid = 0;
2693 /* unicode only call */
2694 if (target_name == NULL) {
2695 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2696 len_of_str =
2697 cifsConvertToUTF16((__le16 *)rename_info->target_name,
2698 dummy_string, 24, nls_codepage, remap);
2699 } else {
2700 len_of_str =
2701 cifsConvertToUTF16((__le16 *)rename_info->target_name,
2702 target_name, PATH_MAX, nls_codepage,
2703 remap);
2705 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2706 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2707 byte_count += count;
2708 pSMB->DataCount = cpu_to_le16(count);
2709 pSMB->TotalDataCount = pSMB->DataCount;
2710 pSMB->Fid = netfid;
2711 pSMB->InformationLevel =
2712 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2713 pSMB->Reserved4 = 0;
2714 inc_rfc1001_len(pSMB, byte_count);
2715 pSMB->ByteCount = cpu_to_le16(byte_count);
2716 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2717 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2718 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
2719 if (rc)
2720 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2721 rc);
2723 cifs_buf_release(pSMB);
2725 /* Note: On -EAGAIN error only caller can retry on handle based calls
2726 since file handle passed in no longer valid */
2728 return rc;
2732 CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2733 const char *fromName, const __u16 target_tid, const char *toName,
2734 const int flags, const struct nls_table *nls_codepage, int remap)
2736 int rc = 0;
2737 COPY_REQ *pSMB = NULL;
2738 COPY_RSP *pSMBr = NULL;
2739 int bytes_returned;
2740 int name_len, name_len2;
2741 __u16 count;
2743 cifs_dbg(FYI, "In CIFSSMBCopy\n");
2744 copyRetry:
2745 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2746 (void **) &pSMBr);
2747 if (rc)
2748 return rc;
2750 pSMB->BufferFormat = 0x04;
2751 pSMB->Tid2 = target_tid;
2753 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2755 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2756 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2757 fromName, PATH_MAX, nls_codepage,
2758 remap);
2759 name_len++; /* trailing null */
2760 name_len *= 2;
2761 pSMB->OldFileName[name_len] = 0x04; /* pad */
2762 /* protocol requires ASCII signature byte on Unicode string */
2763 pSMB->OldFileName[name_len + 1] = 0x00;
2764 name_len2 =
2765 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2766 toName, PATH_MAX, nls_codepage, remap);
2767 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2768 name_len2 *= 2; /* convert to bytes */
2769 } else { /* BB improve the check for buffer overruns BB */
2770 name_len = strnlen(fromName, PATH_MAX);
2771 name_len++; /* trailing null */
2772 strncpy(pSMB->OldFileName, fromName, name_len);
2773 name_len2 = strnlen(toName, PATH_MAX);
2774 name_len2++; /* trailing null */
2775 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2776 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2777 name_len2++; /* trailing null */
2778 name_len2++; /* signature byte */
2781 count = 1 /* 1st signature byte */ + name_len + name_len2;
2782 inc_rfc1001_len(pSMB, count);
2783 pSMB->ByteCount = cpu_to_le16(count);
2785 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2786 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2787 if (rc) {
2788 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2789 rc, le16_to_cpu(pSMBr->CopyCount));
2791 cifs_buf_release(pSMB);
2793 if (rc == -EAGAIN)
2794 goto copyRetry;
2796 return rc;
2800 CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
2801 const char *fromName, const char *toName,
2802 const struct nls_table *nls_codepage, int remap)
2804 TRANSACTION2_SPI_REQ *pSMB = NULL;
2805 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2806 char *data_offset;
2807 int name_len;
2808 int name_len_target;
2809 int rc = 0;
2810 int bytes_returned = 0;
2811 __u16 params, param_offset, offset, byte_count;
2813 cifs_dbg(FYI, "In Symlink Unix style\n");
2814 createSymLinkRetry:
2815 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2816 (void **) &pSMBr);
2817 if (rc)
2818 return rc;
2820 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2821 name_len =
2822 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2823 /* find define for this maxpathcomponent */
2824 PATH_MAX, nls_codepage, remap);
2825 name_len++; /* trailing null */
2826 name_len *= 2;
2828 } else { /* BB improve the check for buffer overruns BB */
2829 name_len = strnlen(fromName, PATH_MAX);
2830 name_len++; /* trailing null */
2831 strncpy(pSMB->FileName, fromName, name_len);
2833 params = 6 + name_len;
2834 pSMB->MaxSetupCount = 0;
2835 pSMB->Reserved = 0;
2836 pSMB->Flags = 0;
2837 pSMB->Timeout = 0;
2838 pSMB->Reserved2 = 0;
2839 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2840 InformationLevel) - 4;
2841 offset = param_offset + params;
2843 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2844 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2845 name_len_target =
2846 cifsConvertToUTF16((__le16 *) data_offset, toName,
2847 /* find define for this maxpathcomponent */
2848 PATH_MAX, nls_codepage, remap);
2849 name_len_target++; /* trailing null */
2850 name_len_target *= 2;
2851 } else { /* BB improve the check for buffer overruns BB */
2852 name_len_target = strnlen(toName, PATH_MAX);
2853 name_len_target++; /* trailing null */
2854 strncpy(data_offset, toName, name_len_target);
2857 pSMB->MaxParameterCount = cpu_to_le16(2);
2858 /* BB find exact max on data count below from sess */
2859 pSMB->MaxDataCount = cpu_to_le16(1000);
2860 pSMB->SetupCount = 1;
2861 pSMB->Reserved3 = 0;
2862 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2863 byte_count = 3 /* pad */ + params + name_len_target;
2864 pSMB->DataCount = cpu_to_le16(name_len_target);
2865 pSMB->ParameterCount = cpu_to_le16(params);
2866 pSMB->TotalDataCount = pSMB->DataCount;
2867 pSMB->TotalParameterCount = pSMB->ParameterCount;
2868 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2869 pSMB->DataOffset = cpu_to_le16(offset);
2870 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2871 pSMB->Reserved4 = 0;
2872 inc_rfc1001_len(pSMB, byte_count);
2873 pSMB->ByteCount = cpu_to_le16(byte_count);
2874 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2875 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2876 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
2877 if (rc)
2878 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2879 rc);
2881 cifs_buf_release(pSMB);
2883 if (rc == -EAGAIN)
2884 goto createSymLinkRetry;
2886 return rc;
2890 CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
2891 const char *fromName, const char *toName,
2892 const struct nls_table *nls_codepage, int remap)
2894 TRANSACTION2_SPI_REQ *pSMB = NULL;
2895 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2896 char *data_offset;
2897 int name_len;
2898 int name_len_target;
2899 int rc = 0;
2900 int bytes_returned = 0;
2901 __u16 params, param_offset, offset, byte_count;
2903 cifs_dbg(FYI, "In Create Hard link Unix style\n");
2904 createHardLinkRetry:
2905 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2906 (void **) &pSMBr);
2907 if (rc)
2908 return rc;
2910 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2911 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2912 PATH_MAX, nls_codepage, remap);
2913 name_len++; /* trailing null */
2914 name_len *= 2;
2916 } else { /* BB improve the check for buffer overruns BB */
2917 name_len = strnlen(toName, PATH_MAX);
2918 name_len++; /* trailing null */
2919 strncpy(pSMB->FileName, toName, name_len);
2921 params = 6 + name_len;
2922 pSMB->MaxSetupCount = 0;
2923 pSMB->Reserved = 0;
2924 pSMB->Flags = 0;
2925 pSMB->Timeout = 0;
2926 pSMB->Reserved2 = 0;
2927 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2928 InformationLevel) - 4;
2929 offset = param_offset + params;
2931 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2932 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2933 name_len_target =
2934 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2935 PATH_MAX, nls_codepage, remap);
2936 name_len_target++; /* trailing null */
2937 name_len_target *= 2;
2938 } else { /* BB improve the check for buffer overruns BB */
2939 name_len_target = strnlen(fromName, PATH_MAX);
2940 name_len_target++; /* trailing null */
2941 strncpy(data_offset, fromName, name_len_target);
2944 pSMB->MaxParameterCount = cpu_to_le16(2);
2945 /* BB find exact max on data count below from sess*/
2946 pSMB->MaxDataCount = cpu_to_le16(1000);
2947 pSMB->SetupCount = 1;
2948 pSMB->Reserved3 = 0;
2949 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2950 byte_count = 3 /* pad */ + params + name_len_target;
2951 pSMB->ParameterCount = cpu_to_le16(params);
2952 pSMB->TotalParameterCount = pSMB->ParameterCount;
2953 pSMB->DataCount = cpu_to_le16(name_len_target);
2954 pSMB->TotalDataCount = pSMB->DataCount;
2955 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2956 pSMB->DataOffset = cpu_to_le16(offset);
2957 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2958 pSMB->Reserved4 = 0;
2959 inc_rfc1001_len(pSMB, byte_count);
2960 pSMB->ByteCount = cpu_to_le16(byte_count);
2961 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2962 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2963 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
2964 if (rc)
2965 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2966 rc);
2968 cifs_buf_release(pSMB);
2969 if (rc == -EAGAIN)
2970 goto createHardLinkRetry;
2972 return rc;
2976 CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
2977 const char *from_name, const char *to_name,
2978 struct cifs_sb_info *cifs_sb)
2980 int rc = 0;
2981 NT_RENAME_REQ *pSMB = NULL;
2982 RENAME_RSP *pSMBr = NULL;
2983 int bytes_returned;
2984 int name_len, name_len2;
2985 __u16 count;
2986 int remap = cifs_remap(cifs_sb);
2988 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
2989 winCreateHardLinkRetry:
2991 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2992 (void **) &pSMBr);
2993 if (rc)
2994 return rc;
2996 pSMB->SearchAttributes =
2997 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2998 ATTR_DIRECTORY);
2999 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3000 pSMB->ClusterCount = 0;
3002 pSMB->BufferFormat = 0x04;
3004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3005 name_len =
3006 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3007 PATH_MAX, cifs_sb->local_nls, remap);
3008 name_len++; /* trailing null */
3009 name_len *= 2;
3011 /* protocol specifies ASCII buffer format (0x04) for unicode */
3012 pSMB->OldFileName[name_len] = 0x04;
3013 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
3014 name_len2 =
3015 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
3016 to_name, PATH_MAX, cifs_sb->local_nls,
3017 remap);
3018 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3019 name_len2 *= 2; /* convert to bytes */
3020 } else { /* BB improve the check for buffer overruns BB */
3021 name_len = strnlen(from_name, PATH_MAX);
3022 name_len++; /* trailing null */
3023 strncpy(pSMB->OldFileName, from_name, name_len);
3024 name_len2 = strnlen(to_name, PATH_MAX);
3025 name_len2++; /* trailing null */
3026 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
3027 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
3028 name_len2++; /* trailing null */
3029 name_len2++; /* signature byte */
3032 count = 1 /* string type byte */ + name_len + name_len2;
3033 inc_rfc1001_len(pSMB, count);
3034 pSMB->ByteCount = cpu_to_le16(count);
3036 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3037 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3038 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
3039 if (rc)
3040 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
3042 cifs_buf_release(pSMB);
3043 if (rc == -EAGAIN)
3044 goto winCreateHardLinkRetry;
3046 return rc;
3050 CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3051 const unsigned char *searchName, char **symlinkinfo,
3052 const struct nls_table *nls_codepage, int remap)
3054 /* SMB_QUERY_FILE_UNIX_LINK */
3055 TRANSACTION2_QPI_REQ *pSMB = NULL;
3056 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3057 int rc = 0;
3058 int bytes_returned;
3059 int name_len;
3060 __u16 params, byte_count;
3061 char *data_start;
3063 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
3065 querySymLinkRetry:
3066 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3067 (void **) &pSMBr);
3068 if (rc)
3069 return rc;
3071 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3072 name_len =
3073 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3074 searchName, PATH_MAX, nls_codepage,
3075 remap);
3076 name_len++; /* trailing null */
3077 name_len *= 2;
3078 } else { /* BB improve the check for buffer overruns BB */
3079 name_len = strnlen(searchName, PATH_MAX);
3080 name_len++; /* trailing null */
3081 strncpy(pSMB->FileName, searchName, name_len);
3084 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3085 pSMB->TotalDataCount = 0;
3086 pSMB->MaxParameterCount = cpu_to_le16(2);
3087 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3088 pSMB->MaxSetupCount = 0;
3089 pSMB->Reserved = 0;
3090 pSMB->Flags = 0;
3091 pSMB->Timeout = 0;
3092 pSMB->Reserved2 = 0;
3093 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3094 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3095 pSMB->DataCount = 0;
3096 pSMB->DataOffset = 0;
3097 pSMB->SetupCount = 1;
3098 pSMB->Reserved3 = 0;
3099 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3100 byte_count = params + 1 /* pad */ ;
3101 pSMB->TotalParameterCount = cpu_to_le16(params);
3102 pSMB->ParameterCount = pSMB->TotalParameterCount;
3103 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3104 pSMB->Reserved4 = 0;
3105 inc_rfc1001_len(pSMB, byte_count);
3106 pSMB->ByteCount = cpu_to_le16(byte_count);
3108 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3109 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3110 if (rc) {
3111 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
3112 } else {
3113 /* decode response */
3115 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3116 /* BB also check enough total bytes returned */
3117 if (rc || get_bcc(&pSMBr->hdr) < 2)
3118 rc = -EIO;
3119 else {
3120 bool is_unicode;
3121 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3123 data_start = ((char *) &pSMBr->hdr.Protocol) +
3124 le16_to_cpu(pSMBr->t2.DataOffset);
3126 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3127 is_unicode = true;
3128 else
3129 is_unicode = false;
3131 /* BB FIXME investigate remapping reserved chars here */
3132 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3133 count, is_unicode, nls_codepage);
3134 if (!*symlinkinfo)
3135 rc = -ENOMEM;
3138 cifs_buf_release(pSMB);
3139 if (rc == -EAGAIN)
3140 goto querySymLinkRetry;
3141 return rc;
3145 * Recent Windows versions now create symlinks more frequently
3146 * and they use the "reparse point" mechanism below. We can of course
3147 * do symlinks nicely to Samba and other servers which support the
3148 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3149 * "MF" symlinks optionally, but for recent Windows we really need to
3150 * reenable the code below and fix the cifs_symlink callers to handle this.
3151 * In the interim this code has been moved to its own config option so
3152 * it is not compiled in by default until callers fixed up and more tested.
3155 CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3156 __u16 fid, char **symlinkinfo,
3157 const struct nls_table *nls_codepage)
3159 int rc = 0;
3160 int bytes_returned;
3161 struct smb_com_transaction_ioctl_req *pSMB;
3162 struct smb_com_transaction_ioctl_rsp *pSMBr;
3163 bool is_unicode;
3164 unsigned int sub_len;
3165 char *sub_start;
3166 struct reparse_symlink_data *reparse_buf;
3167 struct reparse_posix_data *posix_buf;
3168 __u32 data_offset, data_count;
3169 char *end_of_smb;
3171 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
3172 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3173 (void **) &pSMBr);
3174 if (rc)
3175 return rc;
3177 pSMB->TotalParameterCount = 0 ;
3178 pSMB->TotalDataCount = 0;
3179 pSMB->MaxParameterCount = cpu_to_le32(2);
3180 /* BB find exact data count max from sess structure BB */
3181 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
3182 pSMB->MaxSetupCount = 4;
3183 pSMB->Reserved = 0;
3184 pSMB->ParameterOffset = 0;
3185 pSMB->DataCount = 0;
3186 pSMB->DataOffset = 0;
3187 pSMB->SetupCount = 4;
3188 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3189 pSMB->ParameterCount = pSMB->TotalParameterCount;
3190 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3191 pSMB->IsFsctl = 1; /* FSCTL */
3192 pSMB->IsRootFlag = 0;
3193 pSMB->Fid = fid; /* file handle always le */
3194 pSMB->ByteCount = 0;
3196 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3197 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3198 if (rc) {
3199 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
3200 goto qreparse_out;
3203 data_offset = le32_to_cpu(pSMBr->DataOffset);
3204 data_count = le32_to_cpu(pSMBr->DataCount);
3205 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3206 /* BB also check enough total bytes returned */
3207 rc = -EIO; /* bad smb */
3208 goto qreparse_out;
3210 if (!data_count || (data_count > 2048)) {
3211 rc = -EIO;
3212 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3213 goto qreparse_out;
3215 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
3216 reparse_buf = (struct reparse_symlink_data *)
3217 ((char *)&pSMBr->hdr.Protocol + data_offset);
3218 if ((char *)reparse_buf >= end_of_smb) {
3219 rc = -EIO;
3220 goto qreparse_out;
3222 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3223 cifs_dbg(FYI, "NFS style reparse tag\n");
3224 posix_buf = (struct reparse_posix_data *)reparse_buf;
3226 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3227 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3228 le64_to_cpu(posix_buf->InodeType));
3229 rc = -EOPNOTSUPP;
3230 goto qreparse_out;
3232 is_unicode = true;
3233 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3234 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3235 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3236 rc = -EIO;
3237 goto qreparse_out;
3239 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3240 sub_len, is_unicode, nls_codepage);
3241 goto qreparse_out;
3242 } else if (reparse_buf->ReparseTag !=
3243 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3244 rc = -EOPNOTSUPP;
3245 goto qreparse_out;
3248 /* Reparse tag is NTFS symlink */
3249 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3250 reparse_buf->PathBuffer;
3251 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3252 if (sub_start + sub_len > end_of_smb) {
3253 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3254 rc = -EIO;
3255 goto qreparse_out;
3257 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3258 is_unicode = true;
3259 else
3260 is_unicode = false;
3262 /* BB FIXME investigate remapping reserved chars here */
3263 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3264 nls_codepage);
3265 if (!*symlinkinfo)
3266 rc = -ENOMEM;
3267 qreparse_out:
3268 cifs_buf_release(pSMB);
3271 * Note: On -EAGAIN error only caller can retry on handle based calls
3272 * since file handle passed in no longer valid.
3274 return rc;
3278 CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3279 __u16 fid)
3281 int rc = 0;
3282 int bytes_returned;
3283 struct smb_com_transaction_compr_ioctl_req *pSMB;
3284 struct smb_com_transaction_ioctl_rsp *pSMBr;
3286 cifs_dbg(FYI, "Set compression for %u\n", fid);
3287 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3288 (void **) &pSMBr);
3289 if (rc)
3290 return rc;
3292 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3294 pSMB->TotalParameterCount = 0;
3295 pSMB->TotalDataCount = cpu_to_le32(2);
3296 pSMB->MaxParameterCount = 0;
3297 pSMB->MaxDataCount = 0;
3298 pSMB->MaxSetupCount = 4;
3299 pSMB->Reserved = 0;
3300 pSMB->ParameterOffset = 0;
3301 pSMB->DataCount = cpu_to_le32(2);
3302 pSMB->DataOffset =
3303 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3304 compression_state) - 4); /* 84 */
3305 pSMB->SetupCount = 4;
3306 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3307 pSMB->ParameterCount = 0;
3308 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
3309 pSMB->IsFsctl = 1; /* FSCTL */
3310 pSMB->IsRootFlag = 0;
3311 pSMB->Fid = fid; /* file handle always le */
3312 /* 3 byte pad, followed by 2 byte compress state */
3313 pSMB->ByteCount = cpu_to_le16(5);
3314 inc_rfc1001_len(pSMB, 5);
3316 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3317 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3318 if (rc)
3319 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3321 cifs_buf_release(pSMB);
3324 * Note: On -EAGAIN error only caller can retry on handle based calls
3325 * since file handle passed in no longer valid.
3327 return rc;
3331 #ifdef CONFIG_CIFS_POSIX
3333 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
3334 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3335 struct cifs_posix_ace *cifs_ace)
3337 /* u8 cifs fields do not need le conversion */
3338 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3339 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3340 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
3342 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3343 ace->e_perm, ace->e_tag, ace->e_id);
3346 return;
3349 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
3350 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3351 const int acl_type, const int size_of_data_area)
3353 int size = 0;
3354 int i;
3355 __u16 count;
3356 struct cifs_posix_ace *pACE;
3357 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3358 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
3360 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3361 return -EOPNOTSUPP;
3363 if (acl_type & ACL_TYPE_ACCESS) {
3364 count = le16_to_cpu(cifs_acl->access_entry_count);
3365 pACE = &cifs_acl->ace_array[0];
3366 size = sizeof(struct cifs_posix_acl);
3367 size += sizeof(struct cifs_posix_ace) * count;
3368 /* check if we would go beyond end of SMB */
3369 if (size_of_data_area < size) {
3370 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3371 size_of_data_area, size);
3372 return -EINVAL;
3374 } else if (acl_type & ACL_TYPE_DEFAULT) {
3375 count = le16_to_cpu(cifs_acl->access_entry_count);
3376 size = sizeof(struct cifs_posix_acl);
3377 size += sizeof(struct cifs_posix_ace) * count;
3378 /* skip past access ACEs to get to default ACEs */
3379 pACE = &cifs_acl->ace_array[count];
3380 count = le16_to_cpu(cifs_acl->default_entry_count);
3381 size += sizeof(struct cifs_posix_ace) * count;
3382 /* check if we would go beyond end of SMB */
3383 if (size_of_data_area < size)
3384 return -EINVAL;
3385 } else {
3386 /* illegal type */
3387 return -EINVAL;
3390 size = posix_acl_xattr_size(count);
3391 if ((buflen == 0) || (local_acl == NULL)) {
3392 /* used to query ACL EA size */
3393 } else if (size > buflen) {
3394 return -ERANGE;
3395 } else /* buffer big enough */ {
3396 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
3397 for (i = 0; i < count ; i++) {
3398 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3399 pACE++;
3402 return size;
3405 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3406 const posix_acl_xattr_entry *local_ace)
3408 __u16 rc = 0; /* 0 = ACL converted ok */
3410 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3411 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
3412 /* BB is there a better way to handle the large uid? */
3413 if (local_ace->e_id == cpu_to_le32(-1)) {
3414 /* Probably no need to le convert -1 on any arch but can not hurt */
3415 cifs_ace->cifs_uid = cpu_to_le64(-1);
3416 } else
3417 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
3419 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3420 ace->e_perm, ace->e_tag, ace->e_id);
3422 return rc;
3425 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
3426 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3427 const int buflen, const int acl_type)
3429 __u16 rc = 0;
3430 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3431 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
3432 int count;
3433 int i;
3435 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
3436 return 0;
3438 count = posix_acl_xattr_count((size_t)buflen);
3439 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3440 count, buflen, le32_to_cpu(local_acl->a_version));
3441 if (le32_to_cpu(local_acl->a_version) != 2) {
3442 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3443 le32_to_cpu(local_acl->a_version));
3444 return 0;
3446 cifs_acl->version = cpu_to_le16(1);
3447 if (acl_type == ACL_TYPE_ACCESS) {
3448 cifs_acl->access_entry_count = cpu_to_le16(count);
3449 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
3450 } else if (acl_type == ACL_TYPE_DEFAULT) {
3451 cifs_acl->default_entry_count = cpu_to_le16(count);
3452 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
3453 } else {
3454 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
3455 return 0;
3457 for (i = 0; i < count; i++) {
3458 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3459 &local_acl->a_entries[i]);
3460 if (rc != 0) {
3461 /* ACE not converted */
3462 break;
3465 if (rc == 0) {
3466 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3467 rc += sizeof(struct cifs_posix_acl);
3468 /* BB add check to make sure ACL does not overflow SMB */
3470 return rc;
3474 CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
3475 const unsigned char *searchName,
3476 char *acl_inf, const int buflen, const int acl_type,
3477 const struct nls_table *nls_codepage, int remap)
3479 /* SMB_QUERY_POSIX_ACL */
3480 TRANSACTION2_QPI_REQ *pSMB = NULL;
3481 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3482 int rc = 0;
3483 int bytes_returned;
3484 int name_len;
3485 __u16 params, byte_count;
3487 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
3489 queryAclRetry:
3490 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3491 (void **) &pSMBr);
3492 if (rc)
3493 return rc;
3495 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3496 name_len =
3497 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3498 searchName, PATH_MAX, nls_codepage,
3499 remap);
3500 name_len++; /* trailing null */
3501 name_len *= 2;
3502 pSMB->FileName[name_len] = 0;
3503 pSMB->FileName[name_len+1] = 0;
3504 } else { /* BB improve the check for buffer overruns BB */
3505 name_len = strnlen(searchName, PATH_MAX);
3506 name_len++; /* trailing null */
3507 strncpy(pSMB->FileName, searchName, name_len);
3510 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3511 pSMB->TotalDataCount = 0;
3512 pSMB->MaxParameterCount = cpu_to_le16(2);
3513 /* BB find exact max data count below from sess structure BB */
3514 pSMB->MaxDataCount = cpu_to_le16(4000);
3515 pSMB->MaxSetupCount = 0;
3516 pSMB->Reserved = 0;
3517 pSMB->Flags = 0;
3518 pSMB->Timeout = 0;
3519 pSMB->Reserved2 = 0;
3520 pSMB->ParameterOffset = cpu_to_le16(
3521 offsetof(struct smb_com_transaction2_qpi_req,
3522 InformationLevel) - 4);
3523 pSMB->DataCount = 0;
3524 pSMB->DataOffset = 0;
3525 pSMB->SetupCount = 1;
3526 pSMB->Reserved3 = 0;
3527 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3528 byte_count = params + 1 /* pad */ ;
3529 pSMB->TotalParameterCount = cpu_to_le16(params);
3530 pSMB->ParameterCount = pSMB->TotalParameterCount;
3531 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3532 pSMB->Reserved4 = 0;
3533 inc_rfc1001_len(pSMB, byte_count);
3534 pSMB->ByteCount = cpu_to_le16(byte_count);
3536 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3537 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3538 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
3539 if (rc) {
3540 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
3541 } else {
3542 /* decode response */
3544 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3545 /* BB also check enough total bytes returned */
3546 if (rc || get_bcc(&pSMBr->hdr) < 2)
3547 rc = -EIO; /* bad smb */
3548 else {
3549 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3550 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3551 rc = cifs_copy_posix_acl(acl_inf,
3552 (char *)&pSMBr->hdr.Protocol+data_offset,
3553 buflen, acl_type, count);
3556 cifs_buf_release(pSMB);
3557 if (rc == -EAGAIN)
3558 goto queryAclRetry;
3559 return rc;
3563 CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
3564 const unsigned char *fileName,
3565 const char *local_acl, const int buflen,
3566 const int acl_type,
3567 const struct nls_table *nls_codepage, int remap)
3569 struct smb_com_transaction2_spi_req *pSMB = NULL;
3570 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3571 char *parm_data;
3572 int name_len;
3573 int rc = 0;
3574 int bytes_returned = 0;
3575 __u16 params, byte_count, data_count, param_offset, offset;
3577 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
3578 setAclRetry:
3579 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3580 (void **) &pSMBr);
3581 if (rc)
3582 return rc;
3583 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3584 name_len =
3585 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3586 PATH_MAX, nls_codepage, remap);
3587 name_len++; /* trailing null */
3588 name_len *= 2;
3589 } else { /* BB improve the check for buffer overruns BB */
3590 name_len = strnlen(fileName, PATH_MAX);
3591 name_len++; /* trailing null */
3592 strncpy(pSMB->FileName, fileName, name_len);
3594 params = 6 + name_len;
3595 pSMB->MaxParameterCount = cpu_to_le16(2);
3596 /* BB find max SMB size from sess */
3597 pSMB->MaxDataCount = cpu_to_le16(1000);
3598 pSMB->MaxSetupCount = 0;
3599 pSMB->Reserved = 0;
3600 pSMB->Flags = 0;
3601 pSMB->Timeout = 0;
3602 pSMB->Reserved2 = 0;
3603 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3604 InformationLevel) - 4;
3605 offset = param_offset + params;
3606 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3607 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3609 /* convert to on the wire format for POSIX ACL */
3610 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
3612 if (data_count == 0) {
3613 rc = -EOPNOTSUPP;
3614 goto setACLerrorExit;
3616 pSMB->DataOffset = cpu_to_le16(offset);
3617 pSMB->SetupCount = 1;
3618 pSMB->Reserved3 = 0;
3619 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3620 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3621 byte_count = 3 /* pad */ + params + data_count;
3622 pSMB->DataCount = cpu_to_le16(data_count);
3623 pSMB->TotalDataCount = pSMB->DataCount;
3624 pSMB->ParameterCount = cpu_to_le16(params);
3625 pSMB->TotalParameterCount = pSMB->ParameterCount;
3626 pSMB->Reserved4 = 0;
3627 inc_rfc1001_len(pSMB, byte_count);
3628 pSMB->ByteCount = cpu_to_le16(byte_count);
3629 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3630 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3631 if (rc)
3632 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
3634 setACLerrorExit:
3635 cifs_buf_release(pSMB);
3636 if (rc == -EAGAIN)
3637 goto setAclRetry;
3638 return rc;
3641 /* BB fix tabs in this function FIXME BB */
3643 CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
3644 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
3646 int rc = 0;
3647 struct smb_t2_qfi_req *pSMB = NULL;
3648 struct smb_t2_qfi_rsp *pSMBr = NULL;
3649 int bytes_returned;
3650 __u16 params, byte_count;
3652 cifs_dbg(FYI, "In GetExtAttr\n");
3653 if (tcon == NULL)
3654 return -ENODEV;
3656 GetExtAttrRetry:
3657 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3658 (void **) &pSMBr);
3659 if (rc)
3660 return rc;
3662 params = 2 /* level */ + 2 /* fid */;
3663 pSMB->t2.TotalDataCount = 0;
3664 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3665 /* BB find exact max data count below from sess structure BB */
3666 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3667 pSMB->t2.MaxSetupCount = 0;
3668 pSMB->t2.Reserved = 0;
3669 pSMB->t2.Flags = 0;
3670 pSMB->t2.Timeout = 0;
3671 pSMB->t2.Reserved2 = 0;
3672 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3673 Fid) - 4);
3674 pSMB->t2.DataCount = 0;
3675 pSMB->t2.DataOffset = 0;
3676 pSMB->t2.SetupCount = 1;
3677 pSMB->t2.Reserved3 = 0;
3678 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3679 byte_count = params + 1 /* pad */ ;
3680 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3681 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3682 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3683 pSMB->Pad = 0;
3684 pSMB->Fid = netfid;
3685 inc_rfc1001_len(pSMB, byte_count);
3686 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3688 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3689 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3690 if (rc) {
3691 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
3692 } else {
3693 /* decode response */
3694 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3695 /* BB also check enough total bytes returned */
3696 if (rc || get_bcc(&pSMBr->hdr) < 2)
3697 /* If rc should we check for EOPNOSUPP and
3698 disable the srvino flag? or in caller? */
3699 rc = -EIO; /* bad smb */
3700 else {
3701 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3702 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3703 struct file_chattr_info *pfinfo;
3704 /* BB Do we need a cast or hash here ? */
3705 if (count != 16) {
3706 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
3707 rc = -EIO;
3708 goto GetExtAttrOut;
3710 pfinfo = (struct file_chattr_info *)
3711 (data_offset + (char *) &pSMBr->hdr.Protocol);
3712 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3713 *pMask = le64_to_cpu(pfinfo->mask);
3716 GetExtAttrOut:
3717 cifs_buf_release(pSMB);
3718 if (rc == -EAGAIN)
3719 goto GetExtAttrRetry;
3720 return rc;
3723 #endif /* CONFIG_POSIX */
3725 #ifdef CONFIG_CIFS_ACL
3727 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3728 * all NT TRANSACTS that we init here have total parm and data under about 400
3729 * bytes (to fit in small cifs buffer size), which is the case so far, it
3730 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3731 * returned setup area) and MaxParameterCount (returned parms size) must be set
3732 * by caller
3734 static int
3735 smb_init_nttransact(const __u16 sub_command, const int setup_count,
3736 const int parm_len, struct cifs_tcon *tcon,
3737 void **ret_buf)
3739 int rc;
3740 __u32 temp_offset;
3741 struct smb_com_ntransact_req *pSMB;
3743 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3744 (void **)&pSMB);
3745 if (rc)
3746 return rc;
3747 *ret_buf = (void *)pSMB;
3748 pSMB->Reserved = 0;
3749 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3750 pSMB->TotalDataCount = 0;
3751 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
3752 pSMB->ParameterCount = pSMB->TotalParameterCount;
3753 pSMB->DataCount = pSMB->TotalDataCount;
3754 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3755 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3756 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3757 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3758 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3759 pSMB->SubCommand = cpu_to_le16(sub_command);
3760 return 0;
3763 static int
3764 validate_ntransact(char *buf, char **ppparm, char **ppdata,
3765 __u32 *pparmlen, __u32 *pdatalen)
3767 char *end_of_smb;
3768 __u32 data_count, data_offset, parm_count, parm_offset;
3769 struct smb_com_ntransact_rsp *pSMBr;
3770 u16 bcc;
3772 *pdatalen = 0;
3773 *pparmlen = 0;
3775 if (buf == NULL)
3776 return -EINVAL;
3778 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3780 bcc = get_bcc(&pSMBr->hdr);
3781 end_of_smb = 2 /* sizeof byte count */ + bcc +
3782 (char *)&pSMBr->ByteCount;
3784 data_offset = le32_to_cpu(pSMBr->DataOffset);
3785 data_count = le32_to_cpu(pSMBr->DataCount);
3786 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3787 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3789 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3790 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3792 /* should we also check that parm and data areas do not overlap? */
3793 if (*ppparm > end_of_smb) {
3794 cifs_dbg(FYI, "parms start after end of smb\n");
3795 return -EINVAL;
3796 } else if (parm_count + *ppparm > end_of_smb) {
3797 cifs_dbg(FYI, "parm end after end of smb\n");
3798 return -EINVAL;
3799 } else if (*ppdata > end_of_smb) {
3800 cifs_dbg(FYI, "data starts after end of smb\n");
3801 return -EINVAL;
3802 } else if (data_count + *ppdata > end_of_smb) {
3803 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3804 *ppdata, data_count, (data_count + *ppdata),
3805 end_of_smb, pSMBr);
3806 return -EINVAL;
3807 } else if (parm_count + data_count > bcc) {
3808 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
3809 return -EINVAL;
3811 *pdatalen = data_count;
3812 *pparmlen = parm_count;
3813 return 0;
3816 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3818 CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
3819 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3821 int rc = 0;
3822 int buf_type = 0;
3823 QUERY_SEC_DESC_REQ *pSMB;
3824 struct kvec iov[1];
3826 cifs_dbg(FYI, "GetCifsACL\n");
3828 *pbuflen = 0;
3829 *acl_inf = NULL;
3831 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3832 8 /* parm len */, tcon, (void **) &pSMB);
3833 if (rc)
3834 return rc;
3836 pSMB->MaxParameterCount = cpu_to_le32(4);
3837 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3838 pSMB->MaxSetupCount = 0;
3839 pSMB->Fid = fid; /* file handle always le */
3840 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3841 CIFS_ACL_DACL);
3842 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3843 inc_rfc1001_len(pSMB, 11);
3844 iov[0].iov_base = (char *)pSMB;
3845 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
3847 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3849 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
3850 if (rc) {
3851 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
3852 } else { /* decode response */
3853 __le32 *parm;
3854 __u32 parm_len;
3855 __u32 acl_len;
3856 struct smb_com_ntransact_rsp *pSMBr;
3857 char *pdata;
3859 /* validate_nttransact */
3860 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3861 &pdata, &parm_len, pbuflen);
3862 if (rc)
3863 goto qsec_out;
3864 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3866 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3867 pSMBr, parm, *acl_inf);
3869 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3870 rc = -EIO; /* bad smb */
3871 *pbuflen = 0;
3872 goto qsec_out;
3875 /* BB check that data area is minimum length and as big as acl_len */
3877 acl_len = le32_to_cpu(*parm);
3878 if (acl_len != *pbuflen) {
3879 cifs_dbg(VFS, "acl length %d does not match %d\n",
3880 acl_len, *pbuflen);
3881 if (*pbuflen > acl_len)
3882 *pbuflen = acl_len;
3885 /* check if buffer is big enough for the acl
3886 header followed by the smallest SID */
3887 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3888 (*pbuflen >= 64 * 1024)) {
3889 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
3890 rc = -EINVAL;
3891 *pbuflen = 0;
3892 } else {
3893 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
3894 if (*acl_inf == NULL) {
3895 *pbuflen = 0;
3896 rc = -ENOMEM;
3900 qsec_out:
3901 free_rsp_buf(buf_type, iov[0].iov_base);
3902 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3903 return rc;
3907 CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
3908 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
3910 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3911 int rc = 0;
3912 int bytes_returned = 0;
3913 SET_SEC_DESC_REQ *pSMB = NULL;
3914 void *pSMBr;
3916 setCifsAclRetry:
3917 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
3918 if (rc)
3919 return rc;
3921 pSMB->MaxSetupCount = 0;
3922 pSMB->Reserved = 0;
3924 param_count = 8;
3925 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3926 data_count = acllen;
3927 data_offset = param_offset + param_count;
3928 byte_count = 3 /* pad */ + param_count;
3930 pSMB->DataCount = cpu_to_le32(data_count);
3931 pSMB->TotalDataCount = pSMB->DataCount;
3932 pSMB->MaxParameterCount = cpu_to_le32(4);
3933 pSMB->MaxDataCount = cpu_to_le32(16384);
3934 pSMB->ParameterCount = cpu_to_le32(param_count);
3935 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3936 pSMB->TotalParameterCount = pSMB->ParameterCount;
3937 pSMB->DataOffset = cpu_to_le32(data_offset);
3938 pSMB->SetupCount = 0;
3939 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3940 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3942 pSMB->Fid = fid; /* file handle always le */
3943 pSMB->Reserved2 = 0;
3944 pSMB->AclFlags = cpu_to_le32(aclflag);
3946 if (pntsd && acllen) {
3947 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3948 data_offset, pntsd, acllen);
3949 inc_rfc1001_len(pSMB, byte_count + data_count);
3950 } else
3951 inc_rfc1001_len(pSMB, byte_count);
3953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3956 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3957 bytes_returned, rc);
3958 if (rc)
3959 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
3960 cifs_buf_release(pSMB);
3962 if (rc == -EAGAIN)
3963 goto setCifsAclRetry;
3965 return (rc);
3968 #endif /* CONFIG_CIFS_ACL */
3970 /* Legacy Query Path Information call for lookup to old servers such
3971 as Win9x/WinME */
3973 SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3974 const char *search_name, FILE_ALL_INFO *data,
3975 const struct nls_table *nls_codepage, int remap)
3977 QUERY_INFORMATION_REQ *pSMB;
3978 QUERY_INFORMATION_RSP *pSMBr;
3979 int rc = 0;
3980 int bytes_returned;
3981 int name_len;
3983 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
3984 QInfRetry:
3985 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3986 (void **) &pSMBr);
3987 if (rc)
3988 return rc;
3990 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3991 name_len =
3992 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3993 search_name, PATH_MAX, nls_codepage,
3994 remap);
3995 name_len++; /* trailing null */
3996 name_len *= 2;
3997 } else {
3998 name_len = strnlen(search_name, PATH_MAX);
3999 name_len++; /* trailing null */
4000 strncpy(pSMB->FileName, search_name, name_len);
4002 pSMB->BufferFormat = 0x04;
4003 name_len++; /* account for buffer type byte */
4004 inc_rfc1001_len(pSMB, (__u16)name_len);
4005 pSMB->ByteCount = cpu_to_le16(name_len);
4007 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4008 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4009 if (rc) {
4010 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
4011 } else if (data) {
4012 struct timespec ts;
4013 __u32 time = le32_to_cpu(pSMBr->last_write_time);
4015 /* decode response */
4016 /* BB FIXME - add time zone adjustment BB */
4017 memset(data, 0, sizeof(FILE_ALL_INFO));
4018 ts.tv_nsec = 0;
4019 ts.tv_sec = time;
4020 /* decode time fields */
4021 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4022 data->LastWriteTime = data->ChangeTime;
4023 data->LastAccessTime = 0;
4024 data->AllocationSize =
4025 cpu_to_le64(le32_to_cpu(pSMBr->size));
4026 data->EndOfFile = data->AllocationSize;
4027 data->Attributes =
4028 cpu_to_le32(le16_to_cpu(pSMBr->attr));
4029 } else
4030 rc = -EIO; /* bad buffer passed in */
4032 cifs_buf_release(pSMB);
4034 if (rc == -EAGAIN)
4035 goto QInfRetry;
4037 return rc;
4041 CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
4042 u16 netfid, FILE_ALL_INFO *pFindData)
4044 struct smb_t2_qfi_req *pSMB = NULL;
4045 struct smb_t2_qfi_rsp *pSMBr = NULL;
4046 int rc = 0;
4047 int bytes_returned;
4048 __u16 params, byte_count;
4050 QFileInfoRetry:
4051 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4052 (void **) &pSMBr);
4053 if (rc)
4054 return rc;
4056 params = 2 /* level */ + 2 /* fid */;
4057 pSMB->t2.TotalDataCount = 0;
4058 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4059 /* BB find exact max data count below from sess structure BB */
4060 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4061 pSMB->t2.MaxSetupCount = 0;
4062 pSMB->t2.Reserved = 0;
4063 pSMB->t2.Flags = 0;
4064 pSMB->t2.Timeout = 0;
4065 pSMB->t2.Reserved2 = 0;
4066 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4067 Fid) - 4);
4068 pSMB->t2.DataCount = 0;
4069 pSMB->t2.DataOffset = 0;
4070 pSMB->t2.SetupCount = 1;
4071 pSMB->t2.Reserved3 = 0;
4072 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4073 byte_count = params + 1 /* pad */ ;
4074 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4075 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4076 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4077 pSMB->Pad = 0;
4078 pSMB->Fid = netfid;
4079 inc_rfc1001_len(pSMB, byte_count);
4080 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
4082 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4084 if (rc) {
4085 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
4086 } else { /* decode response */
4087 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4089 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4090 rc = -EIO;
4091 else if (get_bcc(&pSMBr->hdr) < 40)
4092 rc = -EIO; /* bad smb */
4093 else if (pFindData) {
4094 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4095 memcpy((char *) pFindData,
4096 (char *) &pSMBr->hdr.Protocol +
4097 data_offset, sizeof(FILE_ALL_INFO));
4098 } else
4099 rc = -ENOMEM;
4101 cifs_buf_release(pSMB);
4102 if (rc == -EAGAIN)
4103 goto QFileInfoRetry;
4105 return rc;
4109 CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
4110 const char *search_name, FILE_ALL_INFO *data,
4111 int legacy /* old style infolevel */,
4112 const struct nls_table *nls_codepage, int remap)
4114 /* level 263 SMB_QUERY_FILE_ALL_INFO */
4115 TRANSACTION2_QPI_REQ *pSMB = NULL;
4116 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4117 int rc = 0;
4118 int bytes_returned;
4119 int name_len;
4120 __u16 params, byte_count;
4122 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
4123 QPathInfoRetry:
4124 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4125 (void **) &pSMBr);
4126 if (rc)
4127 return rc;
4129 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4130 name_len =
4131 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
4132 PATH_MAX, nls_codepage, remap);
4133 name_len++; /* trailing null */
4134 name_len *= 2;
4135 } else { /* BB improve the check for buffer overruns BB */
4136 name_len = strnlen(search_name, PATH_MAX);
4137 name_len++; /* trailing null */
4138 strncpy(pSMB->FileName, search_name, name_len);
4141 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
4142 pSMB->TotalDataCount = 0;
4143 pSMB->MaxParameterCount = cpu_to_le16(2);
4144 /* BB find exact max SMB PDU from sess structure BB */
4145 pSMB->MaxDataCount = cpu_to_le16(4000);
4146 pSMB->MaxSetupCount = 0;
4147 pSMB->Reserved = 0;
4148 pSMB->Flags = 0;
4149 pSMB->Timeout = 0;
4150 pSMB->Reserved2 = 0;
4151 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4152 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4153 pSMB->DataCount = 0;
4154 pSMB->DataOffset = 0;
4155 pSMB->SetupCount = 1;
4156 pSMB->Reserved3 = 0;
4157 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4158 byte_count = params + 1 /* pad */ ;
4159 pSMB->TotalParameterCount = cpu_to_le16(params);
4160 pSMB->ParameterCount = pSMB->TotalParameterCount;
4161 if (legacy)
4162 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4163 else
4164 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4165 pSMB->Reserved4 = 0;
4166 inc_rfc1001_len(pSMB, byte_count);
4167 pSMB->ByteCount = cpu_to_le16(byte_count);
4169 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4170 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4171 if (rc) {
4172 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
4173 } else { /* decode response */
4174 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4176 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4177 rc = -EIO;
4178 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
4179 rc = -EIO; /* bad smb */
4180 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
4181 rc = -EIO; /* 24 or 26 expected but we do not read
4182 last field */
4183 else if (data) {
4184 int size;
4185 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4188 * On legacy responses we do not read the last field,
4189 * EAsize, fortunately since it varies by subdialect and
4190 * also note it differs on Set vs Get, ie two bytes or 4
4191 * bytes depending but we don't care here.
4193 if (legacy)
4194 size = sizeof(FILE_INFO_STANDARD);
4195 else
4196 size = sizeof(FILE_ALL_INFO);
4197 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
4198 data_offset, size);
4199 } else
4200 rc = -ENOMEM;
4202 cifs_buf_release(pSMB);
4203 if (rc == -EAGAIN)
4204 goto QPathInfoRetry;
4206 return rc;
4210 CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
4211 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4213 struct smb_t2_qfi_req *pSMB = NULL;
4214 struct smb_t2_qfi_rsp *pSMBr = NULL;
4215 int rc = 0;
4216 int bytes_returned;
4217 __u16 params, byte_count;
4219 UnixQFileInfoRetry:
4220 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4221 (void **) &pSMBr);
4222 if (rc)
4223 return rc;
4225 params = 2 /* level */ + 2 /* fid */;
4226 pSMB->t2.TotalDataCount = 0;
4227 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4228 /* BB find exact max data count below from sess structure BB */
4229 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4230 pSMB->t2.MaxSetupCount = 0;
4231 pSMB->t2.Reserved = 0;
4232 pSMB->t2.Flags = 0;
4233 pSMB->t2.Timeout = 0;
4234 pSMB->t2.Reserved2 = 0;
4235 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4236 Fid) - 4);
4237 pSMB->t2.DataCount = 0;
4238 pSMB->t2.DataOffset = 0;
4239 pSMB->t2.SetupCount = 1;
4240 pSMB->t2.Reserved3 = 0;
4241 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4242 byte_count = params + 1 /* pad */ ;
4243 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4244 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4245 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4246 pSMB->Pad = 0;
4247 pSMB->Fid = netfid;
4248 inc_rfc1001_len(pSMB, byte_count);
4249 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
4251 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4252 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4253 if (rc) {
4254 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
4255 } else { /* decode response */
4256 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4258 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4259 cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
4260 rc = -EIO; /* bad smb */
4261 } else {
4262 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4263 memcpy((char *) pFindData,
4264 (char *) &pSMBr->hdr.Protocol +
4265 data_offset,
4266 sizeof(FILE_UNIX_BASIC_INFO));
4270 cifs_buf_release(pSMB);
4271 if (rc == -EAGAIN)
4272 goto UnixQFileInfoRetry;
4274 return rc;
4278 CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
4279 const unsigned char *searchName,
4280 FILE_UNIX_BASIC_INFO *pFindData,
4281 const struct nls_table *nls_codepage, int remap)
4283 /* SMB_QUERY_FILE_UNIX_BASIC */
4284 TRANSACTION2_QPI_REQ *pSMB = NULL;
4285 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4286 int rc = 0;
4287 int bytes_returned = 0;
4288 int name_len;
4289 __u16 params, byte_count;
4291 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
4292 UnixQPathInfoRetry:
4293 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4294 (void **) &pSMBr);
4295 if (rc)
4296 return rc;
4298 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4299 name_len =
4300 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4301 PATH_MAX, nls_codepage, remap);
4302 name_len++; /* trailing null */
4303 name_len *= 2;
4304 } else { /* BB improve the check for buffer overruns BB */
4305 name_len = strnlen(searchName, PATH_MAX);
4306 name_len++; /* trailing null */
4307 strncpy(pSMB->FileName, searchName, name_len);
4310 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
4311 pSMB->TotalDataCount = 0;
4312 pSMB->MaxParameterCount = cpu_to_le16(2);
4313 /* BB find exact max SMB PDU from sess structure BB */
4314 pSMB->MaxDataCount = cpu_to_le16(4000);
4315 pSMB->MaxSetupCount = 0;
4316 pSMB->Reserved = 0;
4317 pSMB->Flags = 0;
4318 pSMB->Timeout = 0;
4319 pSMB->Reserved2 = 0;
4320 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4321 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4322 pSMB->DataCount = 0;
4323 pSMB->DataOffset = 0;
4324 pSMB->SetupCount = 1;
4325 pSMB->Reserved3 = 0;
4326 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4327 byte_count = params + 1 /* pad */ ;
4328 pSMB->TotalParameterCount = cpu_to_le16(params);
4329 pSMB->ParameterCount = pSMB->TotalParameterCount;
4330 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4331 pSMB->Reserved4 = 0;
4332 inc_rfc1001_len(pSMB, byte_count);
4333 pSMB->ByteCount = cpu_to_le16(byte_count);
4335 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4336 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4337 if (rc) {
4338 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
4339 } else { /* decode response */
4340 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4342 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4343 cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
4344 rc = -EIO; /* bad smb */
4345 } else {
4346 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4347 memcpy((char *) pFindData,
4348 (char *) &pSMBr->hdr.Protocol +
4349 data_offset,
4350 sizeof(FILE_UNIX_BASIC_INFO));
4353 cifs_buf_release(pSMB);
4354 if (rc == -EAGAIN)
4355 goto UnixQPathInfoRetry;
4357 return rc;
4360 /* xid, tcon, searchName and codepage are input parms, rest are returned */
4362 CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
4363 const char *searchName, struct cifs_sb_info *cifs_sb,
4364 __u16 *pnetfid, __u16 search_flags,
4365 struct cifs_search_info *psrch_inf, bool msearch)
4367 /* level 257 SMB_ */
4368 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4369 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
4370 T2_FFIRST_RSP_PARMS *parms;
4371 int rc = 0;
4372 int bytes_returned = 0;
4373 int name_len, remap;
4374 __u16 params, byte_count;
4375 struct nls_table *nls_codepage;
4377 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
4379 findFirstRetry:
4380 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4381 (void **) &pSMBr);
4382 if (rc)
4383 return rc;
4385 nls_codepage = cifs_sb->local_nls;
4386 remap = cifs_remap(cifs_sb);
4388 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4389 name_len =
4390 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4391 PATH_MAX, nls_codepage, remap);
4392 /* We can not add the asterik earlier in case
4393 it got remapped to 0xF03A as if it were part of the
4394 directory name instead of a wildcard */
4395 name_len *= 2;
4396 if (msearch) {
4397 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4398 pSMB->FileName[name_len+1] = 0;
4399 pSMB->FileName[name_len+2] = '*';
4400 pSMB->FileName[name_len+3] = 0;
4401 name_len += 4; /* now the trailing null */
4402 /* null terminate just in case */
4403 pSMB->FileName[name_len] = 0;
4404 pSMB->FileName[name_len+1] = 0;
4405 name_len += 2;
4407 } else { /* BB add check for overrun of SMB buf BB */
4408 name_len = strnlen(searchName, PATH_MAX);
4409 /* BB fix here and in unicode clause above ie
4410 if (name_len > buffersize-header)
4411 free buffer exit; BB */
4412 strncpy(pSMB->FileName, searchName, name_len);
4413 if (msearch) {
4414 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4415 pSMB->FileName[name_len+1] = '*';
4416 pSMB->FileName[name_len+2] = 0;
4417 name_len += 3;
4421 params = 12 + name_len /* includes null */ ;
4422 pSMB->TotalDataCount = 0; /* no EAs */
4423 pSMB->MaxParameterCount = cpu_to_le16(10);
4424 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
4425 pSMB->MaxSetupCount = 0;
4426 pSMB->Reserved = 0;
4427 pSMB->Flags = 0;
4428 pSMB->Timeout = 0;
4429 pSMB->Reserved2 = 0;
4430 byte_count = params + 1 /* pad */ ;
4431 pSMB->TotalParameterCount = cpu_to_le16(params);
4432 pSMB->ParameterCount = pSMB->TotalParameterCount;
4433 pSMB->ParameterOffset = cpu_to_le16(
4434 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4435 - 4);
4436 pSMB->DataCount = 0;
4437 pSMB->DataOffset = 0;
4438 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4439 pSMB->Reserved3 = 0;
4440 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4441 pSMB->SearchAttributes =
4442 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4443 ATTR_DIRECTORY);
4444 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4445 pSMB->SearchFlags = cpu_to_le16(search_flags);
4446 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4448 /* BB what should we set StorageType to? Does it matter? BB */
4449 pSMB->SearchStorageType = 0;
4450 inc_rfc1001_len(pSMB, byte_count);
4451 pSMB->ByteCount = cpu_to_le16(byte_count);
4453 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4454 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4455 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
4457 if (rc) {/* BB add logic to retry regular search if Unix search
4458 rejected unexpectedly by server */
4459 /* BB Add code to handle unsupported level rc */
4460 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
4462 cifs_buf_release(pSMB);
4464 /* BB eventually could optimize out free and realloc of buf */
4465 /* for this case */
4466 if (rc == -EAGAIN)
4467 goto findFirstRetry;
4468 } else { /* decode response */
4469 /* BB remember to free buffer if error BB */
4470 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4471 if (rc == 0) {
4472 unsigned int lnoff;
4474 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4475 psrch_inf->unicode = true;
4476 else
4477 psrch_inf->unicode = false;
4479 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
4480 psrch_inf->smallBuf = 0;
4481 psrch_inf->srch_entries_start =
4482 (char *) &pSMBr->hdr.Protocol +
4483 le16_to_cpu(pSMBr->t2.DataOffset);
4484 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4485 le16_to_cpu(pSMBr->t2.ParameterOffset));
4487 if (parms->EndofSearch)
4488 psrch_inf->endOfSearch = true;
4489 else
4490 psrch_inf->endOfSearch = false;
4492 psrch_inf->entries_in_buffer =
4493 le16_to_cpu(parms->SearchCount);
4494 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
4495 psrch_inf->entries_in_buffer;
4496 lnoff = le16_to_cpu(parms->LastNameOffset);
4497 if (CIFSMaxBufSize < lnoff) {
4498 cifs_dbg(VFS, "ignoring corrupt resume name\n");
4499 psrch_inf->last_entry = NULL;
4500 return rc;
4503 psrch_inf->last_entry = psrch_inf->srch_entries_start +
4504 lnoff;
4506 if (pnetfid)
4507 *pnetfid = parms->SearchHandle;
4508 } else {
4509 cifs_buf_release(pSMB);
4513 return rc;
4516 int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4517 __u16 searchHandle, __u16 search_flags,
4518 struct cifs_search_info *psrch_inf)
4520 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4521 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
4522 T2_FNEXT_RSP_PARMS *parms;
4523 char *response_data;
4524 int rc = 0;
4525 int bytes_returned;
4526 unsigned int name_len;
4527 __u16 params, byte_count;
4529 cifs_dbg(FYI, "In FindNext\n");
4531 if (psrch_inf->endOfSearch)
4532 return -ENOENT;
4534 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4535 (void **) &pSMBr);
4536 if (rc)
4537 return rc;
4539 params = 14; /* includes 2 bytes of null string, converted to LE below*/
4540 byte_count = 0;
4541 pSMB->TotalDataCount = 0; /* no EAs */
4542 pSMB->MaxParameterCount = cpu_to_le16(8);
4543 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
4544 pSMB->MaxSetupCount = 0;
4545 pSMB->Reserved = 0;
4546 pSMB->Flags = 0;
4547 pSMB->Timeout = 0;
4548 pSMB->Reserved2 = 0;
4549 pSMB->ParameterOffset = cpu_to_le16(
4550 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4551 pSMB->DataCount = 0;
4552 pSMB->DataOffset = 0;
4553 pSMB->SetupCount = 1;
4554 pSMB->Reserved3 = 0;
4555 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4556 pSMB->SearchHandle = searchHandle; /* always kept as le */
4557 pSMB->SearchCount =
4558 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
4559 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4560 pSMB->ResumeKey = psrch_inf->resume_key;
4561 pSMB->SearchFlags = cpu_to_le16(search_flags);
4563 name_len = psrch_inf->resume_name_len;
4564 params += name_len;
4565 if (name_len < PATH_MAX) {
4566 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4567 byte_count += name_len;
4568 /* 14 byte parm len above enough for 2 byte null terminator */
4569 pSMB->ResumeFileName[name_len] = 0;
4570 pSMB->ResumeFileName[name_len+1] = 0;
4571 } else {
4572 rc = -EINVAL;
4573 goto FNext2_err_exit;
4575 byte_count = params + 1 /* pad */ ;
4576 pSMB->TotalParameterCount = cpu_to_le16(params);
4577 pSMB->ParameterCount = pSMB->TotalParameterCount;
4578 inc_rfc1001_len(pSMB, byte_count);
4579 pSMB->ByteCount = cpu_to_le16(byte_count);
4581 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4582 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4583 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
4584 if (rc) {
4585 if (rc == -EBADF) {
4586 psrch_inf->endOfSearch = true;
4587 cifs_buf_release(pSMB);
4588 rc = 0; /* search probably was closed at end of search*/
4589 } else
4590 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
4591 } else { /* decode response */
4592 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4594 if (rc == 0) {
4595 unsigned int lnoff;
4597 /* BB fixme add lock for file (srch_info) struct here */
4598 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4599 psrch_inf->unicode = true;
4600 else
4601 psrch_inf->unicode = false;
4602 response_data = (char *) &pSMBr->hdr.Protocol +
4603 le16_to_cpu(pSMBr->t2.ParameterOffset);
4604 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4605 response_data = (char *)&pSMBr->hdr.Protocol +
4606 le16_to_cpu(pSMBr->t2.DataOffset);
4607 if (psrch_inf->smallBuf)
4608 cifs_small_buf_release(
4609 psrch_inf->ntwrk_buf_start);
4610 else
4611 cifs_buf_release(psrch_inf->ntwrk_buf_start);
4612 psrch_inf->srch_entries_start = response_data;
4613 psrch_inf->ntwrk_buf_start = (char *)pSMB;
4614 psrch_inf->smallBuf = 0;
4615 if (parms->EndofSearch)
4616 psrch_inf->endOfSearch = true;
4617 else
4618 psrch_inf->endOfSearch = false;
4619 psrch_inf->entries_in_buffer =
4620 le16_to_cpu(parms->SearchCount);
4621 psrch_inf->index_of_last_entry +=
4622 psrch_inf->entries_in_buffer;
4623 lnoff = le16_to_cpu(parms->LastNameOffset);
4624 if (CIFSMaxBufSize < lnoff) {
4625 cifs_dbg(VFS, "ignoring corrupt resume name\n");
4626 psrch_inf->last_entry = NULL;
4627 return rc;
4628 } else
4629 psrch_inf->last_entry =
4630 psrch_inf->srch_entries_start + lnoff;
4632 /* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4633 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
4635 /* BB fixme add unlock here */
4640 /* BB On error, should we leave previous search buf (and count and
4641 last entry fields) intact or free the previous one? */
4643 /* Note: On -EAGAIN error only caller can retry on handle based calls
4644 since file handle passed in no longer valid */
4645 FNext2_err_exit:
4646 if (rc != 0)
4647 cifs_buf_release(pSMB);
4648 return rc;
4652 CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
4653 const __u16 searchHandle)
4655 int rc = 0;
4656 FINDCLOSE_REQ *pSMB = NULL;
4658 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
4659 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4661 /* no sense returning error if session restarted
4662 as file handle has been closed */
4663 if (rc == -EAGAIN)
4664 return 0;
4665 if (rc)
4666 return rc;
4668 pSMB->FileID = searchHandle;
4669 pSMB->ByteCount = 0;
4670 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
4671 if (rc)
4672 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
4674 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
4676 /* Since session is dead, search handle closed on server already */
4677 if (rc == -EAGAIN)
4678 rc = 0;
4680 return rc;
4684 CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
4685 const char *search_name, __u64 *inode_number,
4686 const struct nls_table *nls_codepage, int remap)
4688 int rc = 0;
4689 TRANSACTION2_QPI_REQ *pSMB = NULL;
4690 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4691 int name_len, bytes_returned;
4692 __u16 params, byte_count;
4694 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
4695 if (tcon == NULL)
4696 return -ENODEV;
4698 GetInodeNumberRetry:
4699 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4700 (void **) &pSMBr);
4701 if (rc)
4702 return rc;
4704 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4705 name_len =
4706 cifsConvertToUTF16((__le16 *) pSMB->FileName,
4707 search_name, PATH_MAX, nls_codepage,
4708 remap);
4709 name_len++; /* trailing null */
4710 name_len *= 2;
4711 } else { /* BB improve the check for buffer overruns BB */
4712 name_len = strnlen(search_name, PATH_MAX);
4713 name_len++; /* trailing null */
4714 strncpy(pSMB->FileName, search_name, name_len);
4717 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4718 pSMB->TotalDataCount = 0;
4719 pSMB->MaxParameterCount = cpu_to_le16(2);
4720 /* BB find exact max data count below from sess structure BB */
4721 pSMB->MaxDataCount = cpu_to_le16(4000);
4722 pSMB->MaxSetupCount = 0;
4723 pSMB->Reserved = 0;
4724 pSMB->Flags = 0;
4725 pSMB->Timeout = 0;
4726 pSMB->Reserved2 = 0;
4727 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4728 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4729 pSMB->DataCount = 0;
4730 pSMB->DataOffset = 0;
4731 pSMB->SetupCount = 1;
4732 pSMB->Reserved3 = 0;
4733 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4734 byte_count = params + 1 /* pad */ ;
4735 pSMB->TotalParameterCount = cpu_to_le16(params);
4736 pSMB->ParameterCount = pSMB->TotalParameterCount;
4737 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4738 pSMB->Reserved4 = 0;
4739 inc_rfc1001_len(pSMB, byte_count);
4740 pSMB->ByteCount = cpu_to_le16(byte_count);
4742 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4743 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4744 if (rc) {
4745 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
4746 } else {
4747 /* decode response */
4748 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4749 /* BB also check enough total bytes returned */
4750 if (rc || get_bcc(&pSMBr->hdr) < 2)
4751 /* If rc should we check for EOPNOSUPP and
4752 disable the srvino flag? or in caller? */
4753 rc = -EIO; /* bad smb */
4754 else {
4755 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4756 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
4757 struct file_internal_info *pfinfo;
4758 /* BB Do we need a cast or hash here ? */
4759 if (count < 8) {
4760 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
4761 rc = -EIO;
4762 goto GetInodeNumOut;
4764 pfinfo = (struct file_internal_info *)
4765 (data_offset + (char *) &pSMBr->hdr.Protocol);
4766 *inode_number = le64_to_cpu(pfinfo->UniqueId);
4769 GetInodeNumOut:
4770 cifs_buf_release(pSMB);
4771 if (rc == -EAGAIN)
4772 goto GetInodeNumberRetry;
4773 return rc;
4776 /* parses DFS refferal V3 structure
4777 * caller is responsible for freeing target_nodes
4778 * returns:
4779 * on success - 0
4780 * on failure - errno
4782 static int
4783 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
4784 unsigned int *num_of_nodes,
4785 struct dfs_info3_param **target_nodes,
4786 const struct nls_table *nls_codepage, int remap,
4787 const char *searchName)
4789 int i, rc = 0;
4790 char *data_end;
4791 bool is_unicode;
4792 struct dfs_referral_level_3 *ref;
4794 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4795 is_unicode = true;
4796 else
4797 is_unicode = false;
4798 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4800 if (*num_of_nodes < 1) {
4801 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4802 *num_of_nodes);
4803 rc = -EINVAL;
4804 goto parse_DFS_referrals_exit;
4807 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
4808 if (ref->VersionNumber != cpu_to_le16(3)) {
4809 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4810 le16_to_cpu(ref->VersionNumber));
4811 rc = -EINVAL;
4812 goto parse_DFS_referrals_exit;
4815 /* get the upper boundary of the resp buffer */
4816 data_end = (char *)(&(pSMBr->PathConsumed)) +
4817 le16_to_cpu(pSMBr->t2.DataCount);
4819 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4820 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
4822 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4823 GFP_KERNEL);
4824 if (*target_nodes == NULL) {
4825 rc = -ENOMEM;
4826 goto parse_DFS_referrals_exit;
4829 /* collect necessary data from referrals */
4830 for (i = 0; i < *num_of_nodes; i++) {
4831 char *temp;
4832 int max_len;
4833 struct dfs_info3_param *node = (*target_nodes)+i;
4835 node->flags = le32_to_cpu(pSMBr->DFSFlags);
4836 if (is_unicode) {
4837 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4838 GFP_KERNEL);
4839 if (tmp == NULL) {
4840 rc = -ENOMEM;
4841 goto parse_DFS_referrals_exit;
4843 cifsConvertToUTF16((__le16 *) tmp, searchName,
4844 PATH_MAX, nls_codepage, remap);
4845 node->path_consumed = cifs_utf16_bytes(tmp,
4846 le16_to_cpu(pSMBr->PathConsumed),
4847 nls_codepage);
4848 kfree(tmp);
4849 } else
4850 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4852 node->server_type = le16_to_cpu(ref->ServerType);
4853 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4855 /* copy DfsPath */
4856 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4857 max_len = data_end - temp;
4858 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4859 is_unicode, nls_codepage);
4860 if (!node->path_name) {
4861 rc = -ENOMEM;
4862 goto parse_DFS_referrals_exit;
4865 /* copy link target UNC */
4866 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4867 max_len = data_end - temp;
4868 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4869 is_unicode, nls_codepage);
4870 if (!node->node_name) {
4871 rc = -ENOMEM;
4872 goto parse_DFS_referrals_exit;
4875 ref++;
4878 parse_DFS_referrals_exit:
4879 if (rc) {
4880 free_dfs_info_array(*target_nodes, *num_of_nodes);
4881 *target_nodes = NULL;
4882 *num_of_nodes = 0;
4884 return rc;
4888 CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
4889 const char *search_name, struct dfs_info3_param **target_nodes,
4890 unsigned int *num_of_nodes,
4891 const struct nls_table *nls_codepage, int remap)
4893 /* TRANS2_GET_DFS_REFERRAL */
4894 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4895 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4896 int rc = 0;
4897 int bytes_returned;
4898 int name_len;
4899 __u16 params, byte_count;
4900 *num_of_nodes = 0;
4901 *target_nodes = NULL;
4903 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
4904 if (ses == NULL)
4905 return -ENODEV;
4906 getDFSRetry:
4907 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4908 (void **) &pSMBr);
4909 if (rc)
4910 return rc;
4912 /* server pointer checked in called function,
4913 but should never be null here anyway */
4914 pSMB->hdr.Mid = get_next_mid(ses->server);
4915 pSMB->hdr.Tid = ses->ipc_tid;
4916 pSMB->hdr.Uid = ses->Suid;
4917 if (ses->capabilities & CAP_STATUS32)
4918 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4919 if (ses->capabilities & CAP_DFS)
4920 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4922 if (ses->capabilities & CAP_UNICODE) {
4923 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4924 name_len =
4925 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4926 search_name, PATH_MAX, nls_codepage,
4927 remap);
4928 name_len++; /* trailing null */
4929 name_len *= 2;
4930 } else { /* BB improve the check for buffer overruns BB */
4931 name_len = strnlen(search_name, PATH_MAX);
4932 name_len++; /* trailing null */
4933 strncpy(pSMB->RequestFileName, search_name, name_len);
4936 if (ses->server->sign)
4937 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4939 pSMB->hdr.Uid = ses->Suid;
4941 params = 2 /* level */ + name_len /*includes null */ ;
4942 pSMB->TotalDataCount = 0;
4943 pSMB->DataCount = 0;
4944 pSMB->DataOffset = 0;
4945 pSMB->MaxParameterCount = 0;
4946 /* BB find exact max SMB PDU from sess structure BB */
4947 pSMB->MaxDataCount = cpu_to_le16(4000);
4948 pSMB->MaxSetupCount = 0;
4949 pSMB->Reserved = 0;
4950 pSMB->Flags = 0;
4951 pSMB->Timeout = 0;
4952 pSMB->Reserved2 = 0;
4953 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4954 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4955 pSMB->SetupCount = 1;
4956 pSMB->Reserved3 = 0;
4957 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4958 byte_count = params + 3 /* pad */ ;
4959 pSMB->ParameterCount = cpu_to_le16(params);
4960 pSMB->TotalParameterCount = pSMB->ParameterCount;
4961 pSMB->MaxReferralLevel = cpu_to_le16(3);
4962 inc_rfc1001_len(pSMB, byte_count);
4963 pSMB->ByteCount = cpu_to_le16(byte_count);
4965 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4967 if (rc) {
4968 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
4969 goto GetDFSRefExit;
4971 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4973 /* BB Also check if enough total bytes returned? */
4974 if (rc || get_bcc(&pSMBr->hdr) < 17) {
4975 rc = -EIO; /* bad smb */
4976 goto GetDFSRefExit;
4979 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4980 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
4982 /* parse returned result into more usable form */
4983 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4984 target_nodes, nls_codepage, remap,
4985 search_name);
4987 GetDFSRefExit:
4988 cifs_buf_release(pSMB);
4990 if (rc == -EAGAIN)
4991 goto getDFSRetry;
4993 return rc;
4996 /* Query File System Info such as free space to old servers such as Win 9x */
4998 SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4999 struct kstatfs *FSData)
5001 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
5002 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5003 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5004 FILE_SYSTEM_ALLOC_INFO *response_data;
5005 int rc = 0;
5006 int bytes_returned = 0;
5007 __u16 params, byte_count;
5009 cifs_dbg(FYI, "OldQFSInfo\n");
5010 oldQFSInfoRetry:
5011 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5012 (void **) &pSMBr);
5013 if (rc)
5014 return rc;
5016 params = 2; /* level */
5017 pSMB->TotalDataCount = 0;
5018 pSMB->MaxParameterCount = cpu_to_le16(2);
5019 pSMB->MaxDataCount = cpu_to_le16(1000);
5020 pSMB->MaxSetupCount = 0;
5021 pSMB->Reserved = 0;
5022 pSMB->Flags = 0;
5023 pSMB->Timeout = 0;
5024 pSMB->Reserved2 = 0;
5025 byte_count = params + 1 /* pad */ ;
5026 pSMB->TotalParameterCount = cpu_to_le16(params);
5027 pSMB->ParameterCount = pSMB->TotalParameterCount;
5028 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5029 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5030 pSMB->DataCount = 0;
5031 pSMB->DataOffset = 0;
5032 pSMB->SetupCount = 1;
5033 pSMB->Reserved3 = 0;
5034 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5035 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
5036 inc_rfc1001_len(pSMB, byte_count);
5037 pSMB->ByteCount = cpu_to_le16(byte_count);
5039 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5040 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5041 if (rc) {
5042 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
5043 } else { /* decode response */
5044 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5046 if (rc || get_bcc(&pSMBr->hdr) < 18)
5047 rc = -EIO; /* bad smb */
5048 else {
5049 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5050 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
5051 get_bcc(&pSMBr->hdr), data_offset);
5053 response_data = (FILE_SYSTEM_ALLOC_INFO *)
5054 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5055 FSData->f_bsize =
5056 le16_to_cpu(response_data->BytesPerSector) *
5057 le32_to_cpu(response_data->
5058 SectorsPerAllocationUnit);
5059 FSData->f_blocks =
5060 le32_to_cpu(response_data->TotalAllocationUnits);
5061 FSData->f_bfree = FSData->f_bavail =
5062 le32_to_cpu(response_data->FreeAllocationUnits);
5063 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5064 (unsigned long long)FSData->f_blocks,
5065 (unsigned long long)FSData->f_bfree,
5066 FSData->f_bsize);
5069 cifs_buf_release(pSMB);
5071 if (rc == -EAGAIN)
5072 goto oldQFSInfoRetry;
5074 return rc;
5078 CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5079 struct kstatfs *FSData)
5081 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5082 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5083 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5084 FILE_SYSTEM_INFO *response_data;
5085 int rc = 0;
5086 int bytes_returned = 0;
5087 __u16 params, byte_count;
5089 cifs_dbg(FYI, "In QFSInfo\n");
5090 QFSInfoRetry:
5091 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5092 (void **) &pSMBr);
5093 if (rc)
5094 return rc;
5096 params = 2; /* level */
5097 pSMB->TotalDataCount = 0;
5098 pSMB->MaxParameterCount = cpu_to_le16(2);
5099 pSMB->MaxDataCount = cpu_to_le16(1000);
5100 pSMB->MaxSetupCount = 0;
5101 pSMB->Reserved = 0;
5102 pSMB->Flags = 0;
5103 pSMB->Timeout = 0;
5104 pSMB->Reserved2 = 0;
5105 byte_count = params + 1 /* pad */ ;
5106 pSMB->TotalParameterCount = cpu_to_le16(params);
5107 pSMB->ParameterCount = pSMB->TotalParameterCount;
5108 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5109 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5110 pSMB->DataCount = 0;
5111 pSMB->DataOffset = 0;
5112 pSMB->SetupCount = 1;
5113 pSMB->Reserved3 = 0;
5114 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5115 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
5116 inc_rfc1001_len(pSMB, byte_count);
5117 pSMB->ByteCount = cpu_to_le16(byte_count);
5119 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5120 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5121 if (rc) {
5122 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
5123 } else { /* decode response */
5124 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5126 if (rc || get_bcc(&pSMBr->hdr) < 24)
5127 rc = -EIO; /* bad smb */
5128 else {
5129 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5131 response_data =
5132 (FILE_SYSTEM_INFO
5133 *) (((char *) &pSMBr->hdr.Protocol) +
5134 data_offset);
5135 FSData->f_bsize =
5136 le32_to_cpu(response_data->BytesPerSector) *
5137 le32_to_cpu(response_data->
5138 SectorsPerAllocationUnit);
5139 FSData->f_blocks =
5140 le64_to_cpu(response_data->TotalAllocationUnits);
5141 FSData->f_bfree = FSData->f_bavail =
5142 le64_to_cpu(response_data->FreeAllocationUnits);
5143 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5144 (unsigned long long)FSData->f_blocks,
5145 (unsigned long long)FSData->f_bfree,
5146 FSData->f_bsize);
5149 cifs_buf_release(pSMB);
5151 if (rc == -EAGAIN)
5152 goto QFSInfoRetry;
5154 return rc;
5158 CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
5160 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5161 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5162 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5163 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5164 int rc = 0;
5165 int bytes_returned = 0;
5166 __u16 params, byte_count;
5168 cifs_dbg(FYI, "In QFSAttributeInfo\n");
5169 QFSAttributeRetry:
5170 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5171 (void **) &pSMBr);
5172 if (rc)
5173 return rc;
5175 params = 2; /* level */
5176 pSMB->TotalDataCount = 0;
5177 pSMB->MaxParameterCount = cpu_to_le16(2);
5178 /* BB find exact max SMB PDU from sess structure BB */
5179 pSMB->MaxDataCount = cpu_to_le16(1000);
5180 pSMB->MaxSetupCount = 0;
5181 pSMB->Reserved = 0;
5182 pSMB->Flags = 0;
5183 pSMB->Timeout = 0;
5184 pSMB->Reserved2 = 0;
5185 byte_count = params + 1 /* pad */ ;
5186 pSMB->TotalParameterCount = cpu_to_le16(params);
5187 pSMB->ParameterCount = pSMB->TotalParameterCount;
5188 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5189 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5190 pSMB->DataCount = 0;
5191 pSMB->DataOffset = 0;
5192 pSMB->SetupCount = 1;
5193 pSMB->Reserved3 = 0;
5194 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5195 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
5196 inc_rfc1001_len(pSMB, byte_count);
5197 pSMB->ByteCount = cpu_to_le16(byte_count);
5199 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5200 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5201 if (rc) {
5202 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
5203 } else { /* decode response */
5204 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5206 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5207 /* BB also check if enough bytes returned */
5208 rc = -EIO; /* bad smb */
5209 } else {
5210 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5211 response_data =
5212 (FILE_SYSTEM_ATTRIBUTE_INFO
5213 *) (((char *) &pSMBr->hdr.Protocol) +
5214 data_offset);
5215 memcpy(&tcon->fsAttrInfo, response_data,
5216 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
5219 cifs_buf_release(pSMB);
5221 if (rc == -EAGAIN)
5222 goto QFSAttributeRetry;
5224 return rc;
5228 CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
5230 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5231 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5232 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5233 FILE_SYSTEM_DEVICE_INFO *response_data;
5234 int rc = 0;
5235 int bytes_returned = 0;
5236 __u16 params, byte_count;
5238 cifs_dbg(FYI, "In QFSDeviceInfo\n");
5239 QFSDeviceRetry:
5240 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5241 (void **) &pSMBr);
5242 if (rc)
5243 return rc;
5245 params = 2; /* level */
5246 pSMB->TotalDataCount = 0;
5247 pSMB->MaxParameterCount = cpu_to_le16(2);
5248 /* BB find exact max SMB PDU from sess structure BB */
5249 pSMB->MaxDataCount = cpu_to_le16(1000);
5250 pSMB->MaxSetupCount = 0;
5251 pSMB->Reserved = 0;
5252 pSMB->Flags = 0;
5253 pSMB->Timeout = 0;
5254 pSMB->Reserved2 = 0;
5255 byte_count = params + 1 /* pad */ ;
5256 pSMB->TotalParameterCount = cpu_to_le16(params);
5257 pSMB->ParameterCount = pSMB->TotalParameterCount;
5258 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5259 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5261 pSMB->DataCount = 0;
5262 pSMB->DataOffset = 0;
5263 pSMB->SetupCount = 1;
5264 pSMB->Reserved3 = 0;
5265 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5266 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
5267 inc_rfc1001_len(pSMB, byte_count);
5268 pSMB->ByteCount = cpu_to_le16(byte_count);
5270 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5271 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5272 if (rc) {
5273 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
5274 } else { /* decode response */
5275 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5277 if (rc || get_bcc(&pSMBr->hdr) <
5278 sizeof(FILE_SYSTEM_DEVICE_INFO))
5279 rc = -EIO; /* bad smb */
5280 else {
5281 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5282 response_data =
5283 (FILE_SYSTEM_DEVICE_INFO *)
5284 (((char *) &pSMBr->hdr.Protocol) +
5285 data_offset);
5286 memcpy(&tcon->fsDevInfo, response_data,
5287 sizeof(FILE_SYSTEM_DEVICE_INFO));
5290 cifs_buf_release(pSMB);
5292 if (rc == -EAGAIN)
5293 goto QFSDeviceRetry;
5295 return rc;
5299 CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
5301 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5302 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5303 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5304 FILE_SYSTEM_UNIX_INFO *response_data;
5305 int rc = 0;
5306 int bytes_returned = 0;
5307 __u16 params, byte_count;
5309 cifs_dbg(FYI, "In QFSUnixInfo\n");
5310 QFSUnixRetry:
5311 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5312 (void **) &pSMB, (void **) &pSMBr);
5313 if (rc)
5314 return rc;
5316 params = 2; /* level */
5317 pSMB->TotalDataCount = 0;
5318 pSMB->DataCount = 0;
5319 pSMB->DataOffset = 0;
5320 pSMB->MaxParameterCount = cpu_to_le16(2);
5321 /* BB find exact max SMB PDU from sess structure BB */
5322 pSMB->MaxDataCount = cpu_to_le16(100);
5323 pSMB->MaxSetupCount = 0;
5324 pSMB->Reserved = 0;
5325 pSMB->Flags = 0;
5326 pSMB->Timeout = 0;
5327 pSMB->Reserved2 = 0;
5328 byte_count = params + 1 /* pad */ ;
5329 pSMB->ParameterCount = cpu_to_le16(params);
5330 pSMB->TotalParameterCount = pSMB->ParameterCount;
5331 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5332 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5333 pSMB->SetupCount = 1;
5334 pSMB->Reserved3 = 0;
5335 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5336 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
5337 inc_rfc1001_len(pSMB, byte_count);
5338 pSMB->ByteCount = cpu_to_le16(byte_count);
5340 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5341 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5342 if (rc) {
5343 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
5344 } else { /* decode response */
5345 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5347 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5348 rc = -EIO; /* bad smb */
5349 } else {
5350 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5351 response_data =
5352 (FILE_SYSTEM_UNIX_INFO
5353 *) (((char *) &pSMBr->hdr.Protocol) +
5354 data_offset);
5355 memcpy(&tcon->fsUnixInfo, response_data,
5356 sizeof(FILE_SYSTEM_UNIX_INFO));
5359 cifs_buf_release(pSMB);
5361 if (rc == -EAGAIN)
5362 goto QFSUnixRetry;
5365 return rc;
5369 CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
5371 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5372 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5373 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5374 int rc = 0;
5375 int bytes_returned = 0;
5376 __u16 params, param_offset, offset, byte_count;
5378 cifs_dbg(FYI, "In SETFSUnixInfo\n");
5379 SETFSUnixRetry:
5380 /* BB switch to small buf init to save memory */
5381 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5382 (void **) &pSMB, (void **) &pSMBr);
5383 if (rc)
5384 return rc;
5386 params = 4; /* 2 bytes zero followed by info level. */
5387 pSMB->MaxSetupCount = 0;
5388 pSMB->Reserved = 0;
5389 pSMB->Flags = 0;
5390 pSMB->Timeout = 0;
5391 pSMB->Reserved2 = 0;
5392 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5393 - 4;
5394 offset = param_offset + params;
5396 pSMB->MaxParameterCount = cpu_to_le16(4);
5397 /* BB find exact max SMB PDU from sess structure BB */
5398 pSMB->MaxDataCount = cpu_to_le16(100);
5399 pSMB->SetupCount = 1;
5400 pSMB->Reserved3 = 0;
5401 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5402 byte_count = 1 /* pad */ + params + 12;
5404 pSMB->DataCount = cpu_to_le16(12);
5405 pSMB->ParameterCount = cpu_to_le16(params);
5406 pSMB->TotalDataCount = pSMB->DataCount;
5407 pSMB->TotalParameterCount = pSMB->ParameterCount;
5408 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5409 pSMB->DataOffset = cpu_to_le16(offset);
5411 /* Params. */
5412 pSMB->FileNum = 0;
5413 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5415 /* Data. */
5416 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5417 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5418 pSMB->ClientUnixCap = cpu_to_le64(cap);
5420 inc_rfc1001_len(pSMB, byte_count);
5421 pSMB->ByteCount = cpu_to_le16(byte_count);
5423 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5424 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5425 if (rc) {
5426 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
5427 } else { /* decode response */
5428 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5429 if (rc)
5430 rc = -EIO; /* bad smb */
5432 cifs_buf_release(pSMB);
5434 if (rc == -EAGAIN)
5435 goto SETFSUnixRetry;
5437 return rc;
5443 CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
5444 struct kstatfs *FSData)
5446 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5447 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5448 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5449 FILE_SYSTEM_POSIX_INFO *response_data;
5450 int rc = 0;
5451 int bytes_returned = 0;
5452 __u16 params, byte_count;
5454 cifs_dbg(FYI, "In QFSPosixInfo\n");
5455 QFSPosixRetry:
5456 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5457 (void **) &pSMBr);
5458 if (rc)
5459 return rc;
5461 params = 2; /* level */
5462 pSMB->TotalDataCount = 0;
5463 pSMB->DataCount = 0;
5464 pSMB->DataOffset = 0;
5465 pSMB->MaxParameterCount = cpu_to_le16(2);
5466 /* BB find exact max SMB PDU from sess structure BB */
5467 pSMB->MaxDataCount = cpu_to_le16(100);
5468 pSMB->MaxSetupCount = 0;
5469 pSMB->Reserved = 0;
5470 pSMB->Flags = 0;
5471 pSMB->Timeout = 0;
5472 pSMB->Reserved2 = 0;
5473 byte_count = params + 1 /* pad */ ;
5474 pSMB->ParameterCount = cpu_to_le16(params);
5475 pSMB->TotalParameterCount = pSMB->ParameterCount;
5476 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5477 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5478 pSMB->SetupCount = 1;
5479 pSMB->Reserved3 = 0;
5480 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5481 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
5482 inc_rfc1001_len(pSMB, byte_count);
5483 pSMB->ByteCount = cpu_to_le16(byte_count);
5485 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5486 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5487 if (rc) {
5488 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
5489 } else { /* decode response */
5490 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5492 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5493 rc = -EIO; /* bad smb */
5494 } else {
5495 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5496 response_data =
5497 (FILE_SYSTEM_POSIX_INFO
5498 *) (((char *) &pSMBr->hdr.Protocol) +
5499 data_offset);
5500 FSData->f_bsize =
5501 le32_to_cpu(response_data->BlockSize);
5502 FSData->f_blocks =
5503 le64_to_cpu(response_data->TotalBlocks);
5504 FSData->f_bfree =
5505 le64_to_cpu(response_data->BlocksAvail);
5506 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
5507 FSData->f_bavail = FSData->f_bfree;
5508 } else {
5509 FSData->f_bavail =
5510 le64_to_cpu(response_data->UserBlocksAvail);
5512 if (response_data->TotalFileNodes != cpu_to_le64(-1))
5513 FSData->f_files =
5514 le64_to_cpu(response_data->TotalFileNodes);
5515 if (response_data->FreeFileNodes != cpu_to_le64(-1))
5516 FSData->f_ffree =
5517 le64_to_cpu(response_data->FreeFileNodes);
5520 cifs_buf_release(pSMB);
5522 if (rc == -EAGAIN)
5523 goto QFSPosixRetry;
5525 return rc;
5530 * We can not use write of zero bytes trick to set file size due to need for
5531 * large file support. Also note that this SetPathInfo is preferred to
5532 * SetFileInfo based method in next routine which is only needed to work around
5533 * a sharing violation bugin Samba which this routine can run into.
5536 CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5537 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5538 bool set_allocation)
5540 struct smb_com_transaction2_spi_req *pSMB = NULL;
5541 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5542 struct file_end_of_file_info *parm_data;
5543 int name_len;
5544 int rc = 0;
5545 int bytes_returned = 0;
5546 int remap = cifs_remap(cifs_sb);
5548 __u16 params, byte_count, data_count, param_offset, offset;
5550 cifs_dbg(FYI, "In SetEOF\n");
5551 SetEOFRetry:
5552 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5553 (void **) &pSMBr);
5554 if (rc)
5555 return rc;
5557 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5558 name_len =
5559 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5560 PATH_MAX, cifs_sb->local_nls, remap);
5561 name_len++; /* trailing null */
5562 name_len *= 2;
5563 } else { /* BB improve the check for buffer overruns BB */
5564 name_len = strnlen(file_name, PATH_MAX);
5565 name_len++; /* trailing null */
5566 strncpy(pSMB->FileName, file_name, name_len);
5568 params = 6 + name_len;
5569 data_count = sizeof(struct file_end_of_file_info);
5570 pSMB->MaxParameterCount = cpu_to_le16(2);
5571 pSMB->MaxDataCount = cpu_to_le16(4100);
5572 pSMB->MaxSetupCount = 0;
5573 pSMB->Reserved = 0;
5574 pSMB->Flags = 0;
5575 pSMB->Timeout = 0;
5576 pSMB->Reserved2 = 0;
5577 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5578 InformationLevel) - 4;
5579 offset = param_offset + params;
5580 if (set_allocation) {
5581 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5582 pSMB->InformationLevel =
5583 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5584 else
5585 pSMB->InformationLevel =
5586 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5587 } else /* Set File Size */ {
5588 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5589 pSMB->InformationLevel =
5590 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
5591 else
5592 pSMB->InformationLevel =
5593 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
5596 parm_data =
5597 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5598 offset);
5599 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5600 pSMB->DataOffset = cpu_to_le16(offset);
5601 pSMB->SetupCount = 1;
5602 pSMB->Reserved3 = 0;
5603 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5604 byte_count = 3 /* pad */ + params + data_count;
5605 pSMB->DataCount = cpu_to_le16(data_count);
5606 pSMB->TotalDataCount = pSMB->DataCount;
5607 pSMB->ParameterCount = cpu_to_le16(params);
5608 pSMB->TotalParameterCount = pSMB->ParameterCount;
5609 pSMB->Reserved4 = 0;
5610 inc_rfc1001_len(pSMB, byte_count);
5611 parm_data->FileSize = cpu_to_le64(size);
5612 pSMB->ByteCount = cpu_to_le16(byte_count);
5613 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5614 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5615 if (rc)
5616 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
5618 cifs_buf_release(pSMB);
5620 if (rc == -EAGAIN)
5621 goto SetEOFRetry;
5623 return rc;
5627 CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5628 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
5630 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5631 struct file_end_of_file_info *parm_data;
5632 int rc = 0;
5633 __u16 params, param_offset, offset, byte_count, count;
5635 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5636 (long long)size);
5637 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5639 if (rc)
5640 return rc;
5642 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5643 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
5645 params = 6;
5646 pSMB->MaxSetupCount = 0;
5647 pSMB->Reserved = 0;
5648 pSMB->Flags = 0;
5649 pSMB->Timeout = 0;
5650 pSMB->Reserved2 = 0;
5651 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5652 offset = param_offset + params;
5654 count = sizeof(struct file_end_of_file_info);
5655 pSMB->MaxParameterCount = cpu_to_le16(2);
5656 /* BB find exact max SMB PDU from sess structure BB */
5657 pSMB->MaxDataCount = cpu_to_le16(1000);
5658 pSMB->SetupCount = 1;
5659 pSMB->Reserved3 = 0;
5660 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5661 byte_count = 3 /* pad */ + params + count;
5662 pSMB->DataCount = cpu_to_le16(count);
5663 pSMB->ParameterCount = cpu_to_le16(params);
5664 pSMB->TotalDataCount = pSMB->DataCount;
5665 pSMB->TotalParameterCount = pSMB->ParameterCount;
5666 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5667 parm_data =
5668 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5669 + offset);
5670 pSMB->DataOffset = cpu_to_le16(offset);
5671 parm_data->FileSize = cpu_to_le64(size);
5672 pSMB->Fid = cfile->fid.netfid;
5673 if (set_allocation) {
5674 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5675 pSMB->InformationLevel =
5676 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5677 else
5678 pSMB->InformationLevel =
5679 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5680 } else /* Set File Size */ {
5681 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5682 pSMB->InformationLevel =
5683 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
5684 else
5685 pSMB->InformationLevel =
5686 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
5688 pSMB->Reserved4 = 0;
5689 inc_rfc1001_len(pSMB, byte_count);
5690 pSMB->ByteCount = cpu_to_le16(byte_count);
5691 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5692 if (rc) {
5693 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5694 rc);
5697 /* Note: On -EAGAIN error only caller can retry on handle based calls
5698 since file handle passed in no longer valid */
5700 return rc;
5703 /* Some legacy servers such as NT4 require that the file times be set on
5704 an open handle, rather than by pathname - this is awkward due to
5705 potential access conflicts on the open, but it is unavoidable for these
5706 old servers since the only other choice is to go from 100 nanosecond DCE
5707 time and resort to the original setpathinfo level which takes the ancient
5708 DOS time format with 2 second granularity */
5710 CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
5711 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
5713 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5714 char *data_offset;
5715 int rc = 0;
5716 __u16 params, param_offset, offset, byte_count, count;
5718 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
5719 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5721 if (rc)
5722 return rc;
5724 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5725 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5727 params = 6;
5728 pSMB->MaxSetupCount = 0;
5729 pSMB->Reserved = 0;
5730 pSMB->Flags = 0;
5731 pSMB->Timeout = 0;
5732 pSMB->Reserved2 = 0;
5733 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5734 offset = param_offset + params;
5736 data_offset = (char *)pSMB +
5737 offsetof(struct smb_hdr, Protocol) + offset;
5739 count = sizeof(FILE_BASIC_INFO);
5740 pSMB->MaxParameterCount = cpu_to_le16(2);
5741 /* BB find max SMB PDU from sess */
5742 pSMB->MaxDataCount = cpu_to_le16(1000);
5743 pSMB->SetupCount = 1;
5744 pSMB->Reserved3 = 0;
5745 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5746 byte_count = 3 /* pad */ + params + count;
5747 pSMB->DataCount = cpu_to_le16(count);
5748 pSMB->ParameterCount = cpu_to_le16(params);
5749 pSMB->TotalDataCount = pSMB->DataCount;
5750 pSMB->TotalParameterCount = pSMB->ParameterCount;
5751 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5752 pSMB->DataOffset = cpu_to_le16(offset);
5753 pSMB->Fid = fid;
5754 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5755 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5756 else
5757 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5758 pSMB->Reserved4 = 0;
5759 inc_rfc1001_len(pSMB, byte_count);
5760 pSMB->ByteCount = cpu_to_le16(byte_count);
5761 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5762 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5763 if (rc)
5764 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5765 rc);
5767 /* Note: On -EAGAIN error only caller can retry on handle based calls
5768 since file handle passed in no longer valid */
5770 return rc;
5774 CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
5775 bool delete_file, __u16 fid, __u32 pid_of_opener)
5777 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5778 char *data_offset;
5779 int rc = 0;
5780 __u16 params, param_offset, offset, byte_count, count;
5782 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
5783 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5785 if (rc)
5786 return rc;
5788 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5789 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5791 params = 6;
5792 pSMB->MaxSetupCount = 0;
5793 pSMB->Reserved = 0;
5794 pSMB->Flags = 0;
5795 pSMB->Timeout = 0;
5796 pSMB->Reserved2 = 0;
5797 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5798 offset = param_offset + params;
5800 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5802 count = 1;
5803 pSMB->MaxParameterCount = cpu_to_le16(2);
5804 /* BB find max SMB PDU from sess */
5805 pSMB->MaxDataCount = cpu_to_le16(1000);
5806 pSMB->SetupCount = 1;
5807 pSMB->Reserved3 = 0;
5808 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5809 byte_count = 3 /* pad */ + params + count;
5810 pSMB->DataCount = cpu_to_le16(count);
5811 pSMB->ParameterCount = cpu_to_le16(params);
5812 pSMB->TotalDataCount = pSMB->DataCount;
5813 pSMB->TotalParameterCount = pSMB->ParameterCount;
5814 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5815 pSMB->DataOffset = cpu_to_le16(offset);
5816 pSMB->Fid = fid;
5817 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5818 pSMB->Reserved4 = 0;
5819 inc_rfc1001_len(pSMB, byte_count);
5820 pSMB->ByteCount = cpu_to_le16(byte_count);
5821 *data_offset = delete_file ? 1 : 0;
5822 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5823 if (rc)
5824 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
5826 return rc;
5830 CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
5831 const char *fileName, const FILE_BASIC_INFO *data,
5832 const struct nls_table *nls_codepage, int remap)
5834 TRANSACTION2_SPI_REQ *pSMB = NULL;
5835 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5836 int name_len;
5837 int rc = 0;
5838 int bytes_returned = 0;
5839 char *data_offset;
5840 __u16 params, param_offset, offset, byte_count, count;
5842 cifs_dbg(FYI, "In SetTimes\n");
5844 SetTimesRetry:
5845 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5846 (void **) &pSMBr);
5847 if (rc)
5848 return rc;
5850 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5851 name_len =
5852 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5853 PATH_MAX, nls_codepage, remap);
5854 name_len++; /* trailing null */
5855 name_len *= 2;
5856 } else { /* BB improve the check for buffer overruns BB */
5857 name_len = strnlen(fileName, PATH_MAX);
5858 name_len++; /* trailing null */
5859 strncpy(pSMB->FileName, fileName, name_len);
5862 params = 6 + name_len;
5863 count = sizeof(FILE_BASIC_INFO);
5864 pSMB->MaxParameterCount = cpu_to_le16(2);
5865 /* BB find max SMB PDU from sess structure BB */
5866 pSMB->MaxDataCount = cpu_to_le16(1000);
5867 pSMB->MaxSetupCount = 0;
5868 pSMB->Reserved = 0;
5869 pSMB->Flags = 0;
5870 pSMB->Timeout = 0;
5871 pSMB->Reserved2 = 0;
5872 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5873 InformationLevel) - 4;
5874 offset = param_offset + params;
5875 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5876 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5877 pSMB->DataOffset = cpu_to_le16(offset);
5878 pSMB->SetupCount = 1;
5879 pSMB->Reserved3 = 0;
5880 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5881 byte_count = 3 /* pad */ + params + count;
5883 pSMB->DataCount = cpu_to_le16(count);
5884 pSMB->ParameterCount = cpu_to_le16(params);
5885 pSMB->TotalDataCount = pSMB->DataCount;
5886 pSMB->TotalParameterCount = pSMB->ParameterCount;
5887 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5888 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5889 else
5890 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5891 pSMB->Reserved4 = 0;
5892 inc_rfc1001_len(pSMB, byte_count);
5893 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5894 pSMB->ByteCount = cpu_to_le16(byte_count);
5895 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5896 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5897 if (rc)
5898 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
5900 cifs_buf_release(pSMB);
5902 if (rc == -EAGAIN)
5903 goto SetTimesRetry;
5905 return rc;
5908 /* Can not be used to set time stamps yet (due to old DOS time format) */
5909 /* Can be used to set attributes */
5910 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5911 handling it anyway and NT4 was what we thought it would be needed for
5912 Do not delete it until we prove whether needed for Win9x though */
5914 CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
5915 __u16 dos_attrs, const struct nls_table *nls_codepage)
5917 SETATTR_REQ *pSMB = NULL;
5918 SETATTR_RSP *pSMBr = NULL;
5919 int rc = 0;
5920 int bytes_returned;
5921 int name_len;
5923 cifs_dbg(FYI, "In SetAttrLegacy\n");
5925 SetAttrLgcyRetry:
5926 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5927 (void **) &pSMBr);
5928 if (rc)
5929 return rc;
5931 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5932 name_len =
5933 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5934 PATH_MAX, nls_codepage);
5935 name_len++; /* trailing null */
5936 name_len *= 2;
5937 } else { /* BB improve the check for buffer overruns BB */
5938 name_len = strnlen(fileName, PATH_MAX);
5939 name_len++; /* trailing null */
5940 strncpy(pSMB->fileName, fileName, name_len);
5942 pSMB->attr = cpu_to_le16(dos_attrs);
5943 pSMB->BufferFormat = 0x04;
5944 inc_rfc1001_len(pSMB, name_len + 1);
5945 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5946 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5947 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5948 if (rc)
5949 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
5951 cifs_buf_release(pSMB);
5953 if (rc == -EAGAIN)
5954 goto SetAttrLgcyRetry;
5956 return rc;
5958 #endif /* temporarily unneeded SetAttr legacy function */
5960 static void
5961 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5962 const struct cifs_unix_set_info_args *args)
5964 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
5965 u64 mode = args->mode;
5967 if (uid_valid(args->uid))
5968 uid = from_kuid(&init_user_ns, args->uid);
5969 if (gid_valid(args->gid))
5970 gid = from_kgid(&init_user_ns, args->gid);
5973 * Samba server ignores set of file size to zero due to bugs in some
5974 * older clients, but we should be precise - we use SetFileSize to
5975 * set file size and do not want to truncate file size to zero
5976 * accidentally as happened on one Samba server beta by putting
5977 * zero instead of -1 here
5979 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5980 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5981 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5982 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5983 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5984 data_offset->Uid = cpu_to_le64(uid);
5985 data_offset->Gid = cpu_to_le64(gid);
5986 /* better to leave device as zero when it is */
5987 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5988 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5989 data_offset->Permissions = cpu_to_le64(mode);
5991 if (S_ISREG(mode))
5992 data_offset->Type = cpu_to_le32(UNIX_FILE);
5993 else if (S_ISDIR(mode))
5994 data_offset->Type = cpu_to_le32(UNIX_DIR);
5995 else if (S_ISLNK(mode))
5996 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5997 else if (S_ISCHR(mode))
5998 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5999 else if (S_ISBLK(mode))
6000 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
6001 else if (S_ISFIFO(mode))
6002 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6003 else if (S_ISSOCK(mode))
6004 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6008 CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
6009 const struct cifs_unix_set_info_args *args,
6010 u16 fid, u32 pid_of_opener)
6012 struct smb_com_transaction2_sfi_req *pSMB = NULL;
6013 char *data_offset;
6014 int rc = 0;
6015 u16 params, param_offset, offset, byte_count, count;
6017 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
6018 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6020 if (rc)
6021 return rc;
6023 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6024 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6026 params = 6;
6027 pSMB->MaxSetupCount = 0;
6028 pSMB->Reserved = 0;
6029 pSMB->Flags = 0;
6030 pSMB->Timeout = 0;
6031 pSMB->Reserved2 = 0;
6032 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6033 offset = param_offset + params;
6035 data_offset = (char *)pSMB +
6036 offsetof(struct smb_hdr, Protocol) + offset;
6038 count = sizeof(FILE_UNIX_BASIC_INFO);
6040 pSMB->MaxParameterCount = cpu_to_le16(2);
6041 /* BB find max SMB PDU from sess */
6042 pSMB->MaxDataCount = cpu_to_le16(1000);
6043 pSMB->SetupCount = 1;
6044 pSMB->Reserved3 = 0;
6045 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6046 byte_count = 3 /* pad */ + params + count;
6047 pSMB->DataCount = cpu_to_le16(count);
6048 pSMB->ParameterCount = cpu_to_le16(params);
6049 pSMB->TotalDataCount = pSMB->DataCount;
6050 pSMB->TotalParameterCount = pSMB->ParameterCount;
6051 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6052 pSMB->DataOffset = cpu_to_le16(offset);
6053 pSMB->Fid = fid;
6054 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6055 pSMB->Reserved4 = 0;
6056 inc_rfc1001_len(pSMB, byte_count);
6057 pSMB->ByteCount = cpu_to_le16(byte_count);
6059 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
6061 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
6062 if (rc)
6063 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6064 rc);
6066 /* Note: On -EAGAIN error only caller can retry on handle based calls
6067 since file handle passed in no longer valid */
6069 return rc;
6073 CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
6074 const char *file_name,
6075 const struct cifs_unix_set_info_args *args,
6076 const struct nls_table *nls_codepage, int remap)
6078 TRANSACTION2_SPI_REQ *pSMB = NULL;
6079 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6080 int name_len;
6081 int rc = 0;
6082 int bytes_returned = 0;
6083 FILE_UNIX_BASIC_INFO *data_offset;
6084 __u16 params, param_offset, offset, count, byte_count;
6086 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
6087 setPermsRetry:
6088 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6089 (void **) &pSMBr);
6090 if (rc)
6091 return rc;
6093 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6094 name_len =
6095 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
6096 PATH_MAX, nls_codepage, remap);
6097 name_len++; /* trailing null */
6098 name_len *= 2;
6099 } else { /* BB improve the check for buffer overruns BB */
6100 name_len = strnlen(file_name, PATH_MAX);
6101 name_len++; /* trailing null */
6102 strncpy(pSMB->FileName, file_name, name_len);
6105 params = 6 + name_len;
6106 count = sizeof(FILE_UNIX_BASIC_INFO);
6107 pSMB->MaxParameterCount = cpu_to_le16(2);
6108 /* BB find max SMB PDU from sess structure BB */
6109 pSMB->MaxDataCount = cpu_to_le16(1000);
6110 pSMB->MaxSetupCount = 0;
6111 pSMB->Reserved = 0;
6112 pSMB->Flags = 0;
6113 pSMB->Timeout = 0;
6114 pSMB->Reserved2 = 0;
6115 param_offset = offsetof(struct smb_com_transaction2_spi_req,
6116 InformationLevel) - 4;
6117 offset = param_offset + params;
6118 data_offset =
6119 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6120 offset);
6121 memset(data_offset, 0, count);
6122 pSMB->DataOffset = cpu_to_le16(offset);
6123 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6124 pSMB->SetupCount = 1;
6125 pSMB->Reserved3 = 0;
6126 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6127 byte_count = 3 /* pad */ + params + count;
6128 pSMB->ParameterCount = cpu_to_le16(params);
6129 pSMB->DataCount = cpu_to_le16(count);
6130 pSMB->TotalParameterCount = pSMB->ParameterCount;
6131 pSMB->TotalDataCount = pSMB->DataCount;
6132 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6133 pSMB->Reserved4 = 0;
6134 inc_rfc1001_len(pSMB, byte_count);
6136 cifs_fill_unix_set_info(data_offset, args);
6138 pSMB->ByteCount = cpu_to_le16(byte_count);
6139 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6140 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6141 if (rc)
6142 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
6144 cifs_buf_release(pSMB);
6145 if (rc == -EAGAIN)
6146 goto setPermsRetry;
6147 return rc;
6150 #ifdef CONFIG_CIFS_XATTR
6152 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6153 * function used by listxattr and getxattr type calls. When ea_name is set,
6154 * it looks for that attribute name and stuffs that value into the EAData
6155 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6156 * buffer. In both cases, the return value is either the length of the
6157 * resulting data or a negative error code. If EAData is a NULL pointer then
6158 * the data isn't copied to it, but the length is returned.
6160 ssize_t
6161 CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
6162 const unsigned char *searchName, const unsigned char *ea_name,
6163 char *EAData, size_t buf_size,
6164 const struct nls_table *nls_codepage, int remap)
6166 /* BB assumes one setup word */
6167 TRANSACTION2_QPI_REQ *pSMB = NULL;
6168 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6169 int rc = 0;
6170 int bytes_returned;
6171 int list_len;
6172 struct fealist *ea_response_data;
6173 struct fea *temp_fea;
6174 char *temp_ptr;
6175 char *end_of_smb;
6176 __u16 params, byte_count, data_offset;
6177 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
6179 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
6180 QAllEAsRetry:
6181 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6182 (void **) &pSMBr);
6183 if (rc)
6184 return rc;
6186 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6187 list_len =
6188 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6189 PATH_MAX, nls_codepage, remap);
6190 list_len++; /* trailing null */
6191 list_len *= 2;
6192 } else { /* BB improve the check for buffer overruns BB */
6193 list_len = strnlen(searchName, PATH_MAX);
6194 list_len++; /* trailing null */
6195 strncpy(pSMB->FileName, searchName, list_len);
6198 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
6199 pSMB->TotalDataCount = 0;
6200 pSMB->MaxParameterCount = cpu_to_le16(2);
6201 /* BB find exact max SMB PDU from sess structure BB */
6202 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
6203 pSMB->MaxSetupCount = 0;
6204 pSMB->Reserved = 0;
6205 pSMB->Flags = 0;
6206 pSMB->Timeout = 0;
6207 pSMB->Reserved2 = 0;
6208 pSMB->ParameterOffset = cpu_to_le16(offsetof(
6209 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
6210 pSMB->DataCount = 0;
6211 pSMB->DataOffset = 0;
6212 pSMB->SetupCount = 1;
6213 pSMB->Reserved3 = 0;
6214 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6215 byte_count = params + 1 /* pad */ ;
6216 pSMB->TotalParameterCount = cpu_to_le16(params);
6217 pSMB->ParameterCount = pSMB->TotalParameterCount;
6218 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6219 pSMB->Reserved4 = 0;
6220 inc_rfc1001_len(pSMB, byte_count);
6221 pSMB->ByteCount = cpu_to_le16(byte_count);
6223 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6224 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6225 if (rc) {
6226 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
6227 goto QAllEAsOut;
6231 /* BB also check enough total bytes returned */
6232 /* BB we need to improve the validity checking
6233 of these trans2 responses */
6235 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
6236 if (rc || get_bcc(&pSMBr->hdr) < 4) {
6237 rc = -EIO; /* bad smb */
6238 goto QAllEAsOut;
6241 /* check that length of list is not more than bcc */
6242 /* check that each entry does not go beyond length
6243 of list */
6244 /* check that each element of each entry does not
6245 go beyond end of list */
6246 /* validate_trans2_offsets() */
6247 /* BB check if start of smb + data_offset > &bcc+ bcc */
6249 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6250 ea_response_data = (struct fealist *)
6251 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6253 list_len = le32_to_cpu(ea_response_data->list_len);
6254 cifs_dbg(FYI, "ea length %d\n", list_len);
6255 if (list_len <= 8) {
6256 cifs_dbg(FYI, "empty EA list returned from server\n");
6257 /* didn't find the named attribute */
6258 if (ea_name)
6259 rc = -ENODATA;
6260 goto QAllEAsOut;
6263 /* make sure list_len doesn't go past end of SMB */
6264 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
6265 if ((char *)ea_response_data + list_len > end_of_smb) {
6266 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
6267 rc = -EIO;
6268 goto QAllEAsOut;
6271 /* account for ea list len */
6272 list_len -= 4;
6273 temp_fea = ea_response_data->list;
6274 temp_ptr = (char *)temp_fea;
6275 while (list_len > 0) {
6276 unsigned int name_len;
6277 __u16 value_len;
6279 list_len -= 4;
6280 temp_ptr += 4;
6281 /* make sure we can read name_len and value_len */
6282 if (list_len < 0) {
6283 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
6284 rc = -EIO;
6285 goto QAllEAsOut;
6288 name_len = temp_fea->name_len;
6289 value_len = le16_to_cpu(temp_fea->value_len);
6290 list_len -= name_len + 1 + value_len;
6291 if (list_len < 0) {
6292 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
6293 rc = -EIO;
6294 goto QAllEAsOut;
6297 if (ea_name) {
6298 if (ea_name_len == name_len &&
6299 memcmp(ea_name, temp_ptr, name_len) == 0) {
6300 temp_ptr += name_len + 1;
6301 rc = value_len;
6302 if (buf_size == 0)
6303 goto QAllEAsOut;
6304 if ((size_t)value_len > buf_size) {
6305 rc = -ERANGE;
6306 goto QAllEAsOut;
6308 memcpy(EAData, temp_ptr, value_len);
6309 goto QAllEAsOut;
6311 } else {
6312 /* account for prefix user. and trailing null */
6313 rc += (5 + 1 + name_len);
6314 if (rc < (int) buf_size) {
6315 memcpy(EAData, "user.", 5);
6316 EAData += 5;
6317 memcpy(EAData, temp_ptr, name_len);
6318 EAData += name_len;
6319 /* null terminate name */
6320 *EAData = 0;
6321 ++EAData;
6322 } else if (buf_size == 0) {
6323 /* skip copy - calc size only */
6324 } else {
6325 /* stop before overrun buffer */
6326 rc = -ERANGE;
6327 break;
6330 temp_ptr += name_len + 1 + value_len;
6331 temp_fea = (struct fea *)temp_ptr;
6334 /* didn't find the named attribute */
6335 if (ea_name)
6336 rc = -ENODATA;
6338 QAllEAsOut:
6339 cifs_buf_release(pSMB);
6340 if (rc == -EAGAIN)
6341 goto QAllEAsRetry;
6343 return (ssize_t)rc;
6347 CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6348 const char *fileName, const char *ea_name, const void *ea_value,
6349 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6350 int remap)
6352 struct smb_com_transaction2_spi_req *pSMB = NULL;
6353 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6354 struct fealist *parm_data;
6355 int name_len;
6356 int rc = 0;
6357 int bytes_returned = 0;
6358 __u16 params, param_offset, byte_count, offset, count;
6360 cifs_dbg(FYI, "In SetEA\n");
6361 SetEARetry:
6362 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6363 (void **) &pSMBr);
6364 if (rc)
6365 return rc;
6367 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6368 name_len =
6369 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6370 PATH_MAX, nls_codepage, remap);
6371 name_len++; /* trailing null */
6372 name_len *= 2;
6373 } else { /* BB improve the check for buffer overruns BB */
6374 name_len = strnlen(fileName, PATH_MAX);
6375 name_len++; /* trailing null */
6376 strncpy(pSMB->FileName, fileName, name_len);
6379 params = 6 + name_len;
6381 /* done calculating parms using name_len of file name,
6382 now use name_len to calculate length of ea name
6383 we are going to create in the inode xattrs */
6384 if (ea_name == NULL)
6385 name_len = 0;
6386 else
6387 name_len = strnlen(ea_name, 255);
6389 count = sizeof(*parm_data) + ea_value_len + name_len;
6390 pSMB->MaxParameterCount = cpu_to_le16(2);
6391 /* BB find max SMB PDU from sess */
6392 pSMB->MaxDataCount = cpu_to_le16(1000);
6393 pSMB->MaxSetupCount = 0;
6394 pSMB->Reserved = 0;
6395 pSMB->Flags = 0;
6396 pSMB->Timeout = 0;
6397 pSMB->Reserved2 = 0;
6398 param_offset = offsetof(struct smb_com_transaction2_spi_req,
6399 InformationLevel) - 4;
6400 offset = param_offset + params;
6401 pSMB->InformationLevel =
6402 cpu_to_le16(SMB_SET_FILE_EA);
6404 parm_data =
6405 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6406 offset);
6407 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6408 pSMB->DataOffset = cpu_to_le16(offset);
6409 pSMB->SetupCount = 1;
6410 pSMB->Reserved3 = 0;
6411 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6412 byte_count = 3 /* pad */ + params + count;
6413 pSMB->DataCount = cpu_to_le16(count);
6414 parm_data->list_len = cpu_to_le32(count);
6415 parm_data->list[0].EA_flags = 0;
6416 /* we checked above that name len is less than 255 */
6417 parm_data->list[0].name_len = (__u8)name_len;
6418 /* EA names are always ASCII */
6419 if (ea_name)
6420 strncpy(parm_data->list[0].name, ea_name, name_len);
6421 parm_data->list[0].name[name_len] = 0;
6422 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6423 /* caller ensures that ea_value_len is less than 64K but
6424 we need to ensure that it fits within the smb */
6426 /*BB add length check to see if it would fit in
6427 negotiated SMB buffer size BB */
6428 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6429 if (ea_value_len)
6430 memcpy(parm_data->list[0].name+name_len+1,
6431 ea_value, ea_value_len);
6433 pSMB->TotalDataCount = pSMB->DataCount;
6434 pSMB->ParameterCount = cpu_to_le16(params);
6435 pSMB->TotalParameterCount = pSMB->ParameterCount;
6436 pSMB->Reserved4 = 0;
6437 inc_rfc1001_len(pSMB, byte_count);
6438 pSMB->ByteCount = cpu_to_le16(byte_count);
6439 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6440 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6441 if (rc)
6442 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
6444 cifs_buf_release(pSMB);
6446 if (rc == -EAGAIN)
6447 goto SetEARetry;
6449 return rc;
6451 #endif
6453 #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6455 * Years ago the kernel added a "dnotify" function for Samba server,
6456 * to allow network clients (such as Windows) to display updated
6457 * lists of files in directory listings automatically when
6458 * files are added by one user when another user has the
6459 * same directory open on their desktop. The Linux cifs kernel
6460 * client hooked into the kernel side of this interface for
6461 * the same reason, but ironically when the VFS moved from
6462 * "dnotify" to "inotify" it became harder to plug in Linux
6463 * network file system clients (the most obvious use case
6464 * for notify interfaces is when multiple users can update
6465 * the contents of the same directory - exactly what network
6466 * file systems can do) although the server (Samba) could
6467 * still use it. For the short term we leave the worker
6468 * function ifdeffed out (below) until inotify is fixed
6469 * in the VFS to make it easier to plug in network file
6470 * system clients. If inotify turns out to be permanently
6471 * incompatible for network fs clients, we could instead simply
6472 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6474 int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
6475 const int notify_subdirs, const __u16 netfid,
6476 __u32 filter, struct file *pfile, int multishot,
6477 const struct nls_table *nls_codepage)
6479 int rc = 0;
6480 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6481 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6482 struct dir_notify_req *dnotify_req;
6483 int bytes_returned;
6485 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
6486 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6487 (void **) &pSMBr);
6488 if (rc)
6489 return rc;
6491 pSMB->TotalParameterCount = 0 ;
6492 pSMB->TotalDataCount = 0;
6493 pSMB->MaxParameterCount = cpu_to_le32(2);
6494 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
6495 pSMB->MaxSetupCount = 4;
6496 pSMB->Reserved = 0;
6497 pSMB->ParameterOffset = 0;
6498 pSMB->DataCount = 0;
6499 pSMB->DataOffset = 0;
6500 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6501 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6502 pSMB->ParameterCount = pSMB->TotalParameterCount;
6503 if (notify_subdirs)
6504 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6505 pSMB->Reserved2 = 0;
6506 pSMB->CompletionFilter = cpu_to_le32(filter);
6507 pSMB->Fid = netfid; /* file handle always le */
6508 pSMB->ByteCount = 0;
6510 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6511 (struct smb_hdr *)pSMBr, &bytes_returned,
6512 CIFS_ASYNC_OP);
6513 if (rc) {
6514 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
6515 } else {
6516 /* Add file to outstanding requests */
6517 /* BB change to kmem cache alloc */
6518 dnotify_req = kmalloc(
6519 sizeof(struct dir_notify_req),
6520 GFP_KERNEL);
6521 if (dnotify_req) {
6522 dnotify_req->Pid = pSMB->hdr.Pid;
6523 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6524 dnotify_req->Mid = pSMB->hdr.Mid;
6525 dnotify_req->Tid = pSMB->hdr.Tid;
6526 dnotify_req->Uid = pSMB->hdr.Uid;
6527 dnotify_req->netfid = netfid;
6528 dnotify_req->pfile = pfile;
6529 dnotify_req->filter = filter;
6530 dnotify_req->multishot = multishot;
6531 spin_lock(&GlobalMid_Lock);
6532 list_add_tail(&dnotify_req->lhead,
6533 &GlobalDnotifyReqList);
6534 spin_unlock(&GlobalMid_Lock);
6535 } else
6536 rc = -ENOMEM;
6538 cifs_buf_release(pSMB);
6539 return rc;
6541 #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */