USB: cp210x: fix up set_termios variables
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / cifs / cifssmb.c
blob6600aa2d2ef38a38c228a1cd26cbeae2ea2b6b06
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 */
89 /* Forward declarations */
90 static void cifs_readv_complete(struct work_struct *work);
92 /* Mark as invalid, all open files on tree connections since they
93 were closed when session to server was lost */
94 static void mark_open_files_invalid(struct cifs_tcon *pTcon)
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, &pTcon->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);
108 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
109 to this tcon */
112 /* reconnect the socket, tcon, and smb session if needed */
113 static int
114 cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
116 int rc;
117 struct cifs_ses *ses;
118 struct TCP_Server_Info *server;
119 struct nls_table *nls_codepage;
122 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
123 * tcp and smb session status done differently for those three - in the
124 * calling routine
126 if (!tcon)
127 return 0;
129 ses = tcon->ses;
130 server = ses->server;
133 * only tree disconnect, open, and write, (and ulogoff which does not
134 * have tcon) are allowed as we start force umount
136 if (tcon->tidStatus == CifsExiting) {
137 if (smb_command != SMB_COM_WRITE_ANDX &&
138 smb_command != SMB_COM_OPEN_ANDX &&
139 smb_command != SMB_COM_TREE_DISCONNECT) {
140 cFYI(1, "can not send cmd %d while umounting",
141 smb_command);
142 return -ENODEV;
147 * Give demultiplex thread up to 10 seconds to reconnect, should be
148 * greater than cifs socket timeout which is 7 seconds
150 while (server->tcpStatus == CifsNeedReconnect) {
151 wait_event_interruptible_timeout(server->response_q,
152 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
154 /* are we still trying to reconnect? */
155 if (server->tcpStatus != CifsNeedReconnect)
156 break;
159 * on "soft" mounts we wait once. Hard mounts keep
160 * retrying until process is killed or server comes
161 * back on-line
163 if (!tcon->retry) {
164 cFYI(1, "gave up waiting on reconnect in smb_init");
165 return -EHOSTDOWN;
169 if (!ses->need_reconnect && !tcon->need_reconnect)
170 return 0;
172 nls_codepage = load_nls_default();
175 * need to prevent multiple threads trying to simultaneously
176 * reconnect the same SMB session
178 mutex_lock(&ses->session_mutex);
179 rc = cifs_negotiate_protocol(0, ses);
180 if (rc == 0 && ses->need_reconnect)
181 rc = cifs_setup_session(0, ses, nls_codepage);
183 /* do we need to reconnect tcon? */
184 if (rc || !tcon->need_reconnect) {
185 mutex_unlock(&ses->session_mutex);
186 goto out;
189 mark_open_files_invalid(tcon);
190 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
191 mutex_unlock(&ses->session_mutex);
192 cFYI(1, "reconnect tcon rc = %d", rc);
194 if (rc)
195 goto out;
198 * FIXME: check if wsize needs updated due to negotiated smb buffer
199 * size shrinking
201 atomic_inc(&tconInfoReconnectCount);
203 /* tell server Unix caps we support */
204 if (ses->capabilities & CAP_UNIX)
205 reset_cifs_unix_caps(0, tcon, NULL, NULL);
208 * Removed call to reopen open files here. It is safer (and faster) to
209 * reopen files one at a time as needed in read and write.
211 * FIXME: what about file locks? don't we need to reclaim them ASAP?
214 out:
216 * Check if handle based operation so we know whether we can continue
217 * or not without returning to caller to reset file handle
219 switch (smb_command) {
220 case SMB_COM_READ_ANDX:
221 case SMB_COM_WRITE_ANDX:
222 case SMB_COM_CLOSE:
223 case SMB_COM_FIND_CLOSE2:
224 case SMB_COM_LOCKING_ANDX:
225 rc = -EAGAIN;
228 unload_nls(nls_codepage);
229 return rc;
232 /* Allocate and return pointer to an SMB request buffer, and set basic
233 SMB information in the SMB header. If the return code is zero, this
234 function must have filled in request_buf pointer */
235 static int
236 small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
237 void **request_buf)
239 int rc;
241 rc = cifs_reconnect_tcon(tcon, smb_command);
242 if (rc)
243 return rc;
245 *request_buf = cifs_small_buf_get();
246 if (*request_buf == NULL) {
247 /* BB should we add a retry in here if not a writepage? */
248 return -ENOMEM;
251 header_assemble((struct smb_hdr *) *request_buf, smb_command,
252 tcon, wct);
254 if (tcon != NULL)
255 cifs_stats_inc(&tcon->num_smbs_sent);
257 return 0;
261 small_smb_init_no_tc(const int smb_command, const int wct,
262 struct cifs_ses *ses, void **request_buf)
264 int rc;
265 struct smb_hdr *buffer;
267 rc = small_smb_init(smb_command, wct, NULL, request_buf);
268 if (rc)
269 return rc;
271 buffer = (struct smb_hdr *)*request_buf;
272 buffer->Mid = GetNextMid(ses->server);
273 if (ses->capabilities & CAP_UNICODE)
274 buffer->Flags2 |= SMBFLG2_UNICODE;
275 if (ses->capabilities & CAP_STATUS32)
276 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
278 /* uid, tid can stay at zero as set in header assemble */
280 /* BB add support for turning on the signing when
281 this function is used after 1st of session setup requests */
283 return rc;
286 /* If the return code is zero, this function must fill in request_buf pointer */
287 static int
288 __smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
289 void **request_buf, void **response_buf)
291 *request_buf = cifs_buf_get();
292 if (*request_buf == NULL) {
293 /* BB should we add a retry in here if not a writepage? */
294 return -ENOMEM;
296 /* Although the original thought was we needed the response buf for */
297 /* potential retries of smb operations it turns out we can determine */
298 /* from the mid flags when the request buffer can be resent without */
299 /* having to use a second distinct buffer for the response */
300 if (response_buf)
301 *response_buf = *request_buf;
303 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
304 wct);
306 if (tcon != NULL)
307 cifs_stats_inc(&tcon->num_smbs_sent);
309 return 0;
312 /* If the return code is zero, this function must fill in request_buf pointer */
313 static int
314 smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
315 void **request_buf, void **response_buf)
317 int rc;
319 rc = cifs_reconnect_tcon(tcon, smb_command);
320 if (rc)
321 return rc;
323 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
326 static int
327 smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
328 void **request_buf, void **response_buf)
330 if (tcon->ses->need_reconnect || tcon->need_reconnect)
331 return -EHOSTDOWN;
333 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
336 static int validate_t2(struct smb_t2_rsp *pSMB)
338 unsigned int total_size;
340 /* check for plausible wct */
341 if (pSMB->hdr.WordCount < 10)
342 goto vt2_err;
344 /* check for parm and data offset going beyond end of smb */
345 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
346 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
347 goto vt2_err;
349 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
350 if (total_size >= 512)
351 goto vt2_err;
353 /* check that bcc is at least as big as parms + data, and that it is
354 * less than negotiated smb buffer
356 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
357 if (total_size > get_bcc(&pSMB->hdr) ||
358 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
359 goto vt2_err;
361 return 0;
362 vt2_err:
363 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
364 sizeof(struct smb_t2_rsp) + 16);
365 return -EINVAL;
368 static inline void inc_rfc1001_len(void *pSMB, int count)
370 struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
372 be32_add_cpu(&hdr->smb_buf_length, count);
376 CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
378 NEGOTIATE_REQ *pSMB;
379 NEGOTIATE_RSP *pSMBr;
380 int rc = 0;
381 int bytes_returned;
382 int i;
383 struct TCP_Server_Info *server;
384 u16 count;
385 unsigned int secFlags;
387 if (ses->server)
388 server = ses->server;
389 else {
390 rc = -EIO;
391 return rc;
393 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
394 (void **) &pSMB, (void **) &pSMBr);
395 if (rc)
396 return rc;
398 /* if any of auth flags (ie not sign or seal) are overriden use them */
399 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
400 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
401 else /* if override flags set only sign/seal OR them with global auth */
402 secFlags = global_secflags | ses->overrideSecFlg;
404 cFYI(1, "secFlags 0x%x", secFlags);
406 pSMB->hdr.Mid = GetNextMid(server);
407 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
409 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
410 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
411 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
412 cFYI(1, "Kerberos only mechanism, enable extended security");
413 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
414 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
415 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
416 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
417 cFYI(1, "NTLMSSP only mechanism, enable extended security");
418 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
421 count = 0;
422 for (i = 0; i < CIFS_NUM_PROT; i++) {
423 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
424 count += strlen(protocols[i].name) + 1;
425 /* null at end of source and target buffers anyway */
427 inc_rfc1001_len(pSMB, count);
428 pSMB->ByteCount = cpu_to_le16(count);
430 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
431 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
432 if (rc != 0)
433 goto neg_err_exit;
435 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
436 cFYI(1, "Dialect: %d", server->dialect);
437 /* Check wct = 1 error case */
438 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
439 /* core returns wct = 1, but we do not ask for core - otherwise
440 small wct just comes when dialect index is -1 indicating we
441 could not negotiate a common dialect */
442 rc = -EOPNOTSUPP;
443 goto neg_err_exit;
444 #ifdef CONFIG_CIFS_WEAK_PW_HASH
445 } else if ((pSMBr->hdr.WordCount == 13)
446 && ((server->dialect == LANMAN_PROT)
447 || (server->dialect == LANMAN2_PROT))) {
448 __s16 tmp;
449 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
451 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
452 (secFlags & CIFSSEC_MAY_PLNTXT))
453 server->secType = LANMAN;
454 else {
455 cERROR(1, "mount failed weak security disabled"
456 " in /proc/fs/cifs/SecurityFlags");
457 rc = -EOPNOTSUPP;
458 goto neg_err_exit;
460 server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
461 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
462 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
463 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
464 /* even though we do not use raw we might as well set this
465 accurately, in case we ever find a need for it */
466 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
467 server->max_rw = 0xFF00;
468 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
469 } else {
470 server->max_rw = 0;/* do not need to use raw anyway */
471 server->capabilities = CAP_MPX_MODE;
473 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
474 if (tmp == -1) {
475 /* OS/2 often does not set timezone therefore
476 * we must use server time to calc time zone.
477 * Could deviate slightly from the right zone.
478 * Smallest defined timezone difference is 15 minutes
479 * (i.e. Nepal). Rounding up/down is done to match
480 * this requirement.
482 int val, seconds, remain, result;
483 struct timespec ts, utc;
484 utc = CURRENT_TIME;
485 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
486 rsp->SrvTime.Time, 0);
487 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
488 (int)ts.tv_sec, (int)utc.tv_sec,
489 (int)(utc.tv_sec - ts.tv_sec));
490 val = (int)(utc.tv_sec - ts.tv_sec);
491 seconds = abs(val);
492 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
493 remain = seconds % MIN_TZ_ADJ;
494 if (remain >= (MIN_TZ_ADJ / 2))
495 result += MIN_TZ_ADJ;
496 if (val < 0)
497 result = -result;
498 server->timeAdj = result;
499 } else {
500 server->timeAdj = (int)tmp;
501 server->timeAdj *= 60; /* also in seconds */
503 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
506 /* BB get server time for time conversions and add
507 code to use it and timezone since this is not UTC */
509 if (rsp->EncryptionKeyLength ==
510 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
511 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
512 CIFS_CRYPTO_KEY_SIZE);
513 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
514 rc = -EIO; /* need cryptkey unless plain text */
515 goto neg_err_exit;
518 cFYI(1, "LANMAN negotiated");
519 /* we will not end up setting signing flags - as no signing
520 was in LANMAN and server did not return the flags on */
521 goto signing_check;
522 #else /* weak security disabled */
523 } else if (pSMBr->hdr.WordCount == 13) {
524 cERROR(1, "mount failed, cifs module not built "
525 "with CIFS_WEAK_PW_HASH support");
526 rc = -EOPNOTSUPP;
527 #endif /* WEAK_PW_HASH */
528 goto neg_err_exit;
529 } else if (pSMBr->hdr.WordCount != 17) {
530 /* unknown wct */
531 rc = -EOPNOTSUPP;
532 goto neg_err_exit;
534 /* else wct == 17 NTLM */
535 server->sec_mode = pSMBr->SecurityMode;
536 if ((server->sec_mode & SECMODE_USER) == 0)
537 cFYI(1, "share mode security");
539 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
540 #ifdef CONFIG_CIFS_WEAK_PW_HASH
541 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
542 #endif /* CIFS_WEAK_PW_HASH */
543 cERROR(1, "Server requests plain text password"
544 " but client support disabled");
546 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
547 server->secType = NTLMv2;
548 else if (secFlags & CIFSSEC_MAY_NTLM)
549 server->secType = NTLM;
550 else if (secFlags & CIFSSEC_MAY_NTLMV2)
551 server->secType = NTLMv2;
552 else if (secFlags & CIFSSEC_MAY_KRB5)
553 server->secType = Kerberos;
554 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
555 server->secType = RawNTLMSSP;
556 else if (secFlags & CIFSSEC_MAY_LANMAN)
557 server->secType = LANMAN;
558 else {
559 rc = -EOPNOTSUPP;
560 cERROR(1, "Invalid security type");
561 goto neg_err_exit;
563 /* else ... any others ...? */
565 /* one byte, so no need to convert this or EncryptionKeyLen from
566 little endian */
567 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
568 /* probably no need to store and check maxvcs */
569 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
570 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
571 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
572 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
573 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
574 server->timeAdj *= 60;
575 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
576 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
577 CIFS_CRYPTO_KEY_SIZE);
578 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
579 server->capabilities & CAP_EXTENDED_SECURITY) &&
580 (pSMBr->EncryptionKeyLength == 0)) {
581 /* decode security blob */
582 count = get_bcc(&pSMBr->hdr);
583 if (count < 16) {
584 rc = -EIO;
585 goto neg_err_exit;
587 spin_lock(&cifs_tcp_ses_lock);
588 if (server->srv_count > 1) {
589 spin_unlock(&cifs_tcp_ses_lock);
590 if (memcmp(server->server_GUID,
591 pSMBr->u.extended_response.
592 GUID, 16) != 0) {
593 cFYI(1, "server UID changed");
594 memcpy(server->server_GUID,
595 pSMBr->u.extended_response.GUID,
596 16);
598 } else {
599 spin_unlock(&cifs_tcp_ses_lock);
600 memcpy(server->server_GUID,
601 pSMBr->u.extended_response.GUID, 16);
604 if (count == 16) {
605 server->secType = RawNTLMSSP;
606 } else {
607 rc = decode_negTokenInit(pSMBr->u.extended_response.
608 SecurityBlob, count - 16,
609 server);
610 if (rc == 1)
611 rc = 0;
612 else
613 rc = -EINVAL;
614 if (server->secType == Kerberos) {
615 if (!server->sec_kerberos &&
616 !server->sec_mskerberos)
617 rc = -EOPNOTSUPP;
618 } else if (server->secType == RawNTLMSSP) {
619 if (!server->sec_ntlmssp)
620 rc = -EOPNOTSUPP;
621 } else
622 rc = -EOPNOTSUPP;
624 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
625 rc = -EIO; /* no crypt key only if plain text pwd */
626 goto neg_err_exit;
627 } else
628 server->capabilities &= ~CAP_EXTENDED_SECURITY;
630 #ifdef CONFIG_CIFS_WEAK_PW_HASH
631 signing_check:
632 #endif
633 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
634 /* MUST_SIGN already includes the MAY_SIGN FLAG
635 so if this is zero it means that signing is disabled */
636 cFYI(1, "Signing disabled");
637 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
638 cERROR(1, "Server requires "
639 "packet signing to be enabled in "
640 "/proc/fs/cifs/SecurityFlags.");
641 rc = -EOPNOTSUPP;
643 server->sec_mode &=
644 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
645 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
646 /* signing required */
647 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
648 if ((server->sec_mode &
649 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
650 cERROR(1, "signing required but server lacks support");
651 rc = -EOPNOTSUPP;
652 } else
653 server->sec_mode |= SECMODE_SIGN_REQUIRED;
654 } else {
655 /* signing optional ie CIFSSEC_MAY_SIGN */
656 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
657 server->sec_mode &=
658 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
661 neg_err_exit:
662 cifs_buf_release(pSMB);
664 cFYI(1, "negprot rc %d", rc);
665 return rc;
669 CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
671 struct smb_hdr *smb_buffer;
672 int rc = 0;
674 cFYI(1, "In tree disconnect");
676 /* BB: do we need to check this? These should never be NULL. */
677 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
678 return -EIO;
681 * No need to return error on this operation if tid invalidated and
682 * closed on server already e.g. due to tcp session crashing. Also,
683 * the tcon is no longer on the list, so no need to take lock before
684 * checking this.
686 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
687 return 0;
689 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
690 (void **)&smb_buffer);
691 if (rc)
692 return rc;
694 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
695 if (rc)
696 cFYI(1, "Tree disconnect failed %d", rc);
698 /* No need to return error on this operation if tid invalidated and
699 closed on server already e.g. due to tcp session crashing */
700 if (rc == -EAGAIN)
701 rc = 0;
703 return rc;
707 * This is a no-op for now. We're not really interested in the reply, but
708 * rather in the fact that the server sent one and that server->lstrp
709 * gets updated.
711 * FIXME: maybe we should consider checking that the reply matches request?
713 static void
714 cifs_echo_callback(struct mid_q_entry *mid)
716 struct TCP_Server_Info *server = mid->callback_data;
718 DeleteMidQEntry(mid);
719 atomic_dec(&server->inFlight);
720 wake_up(&server->request_q);
724 CIFSSMBEcho(struct TCP_Server_Info *server)
726 ECHO_REQ *smb;
727 int rc = 0;
728 struct kvec iov;
730 cFYI(1, "In echo request");
732 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
733 if (rc)
734 return rc;
736 /* set up echo request */
737 smb->hdr.Tid = 0xffff;
738 smb->hdr.WordCount = 1;
739 put_unaligned_le16(1, &smb->EchoCount);
740 put_bcc(1, &smb->hdr);
741 smb->Data[0] = 'a';
742 inc_rfc1001_len(smb, 3);
743 iov.iov_base = smb;
744 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
746 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
747 server, true);
748 if (rc)
749 cFYI(1, "Echo request failed: %d", rc);
751 cifs_small_buf_release(smb);
753 return rc;
757 CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
759 LOGOFF_ANDX_REQ *pSMB;
760 int rc = 0;
762 cFYI(1, "In SMBLogoff for session disconnect");
765 * BB: do we need to check validity of ses and server? They should
766 * always be valid since we have an active reference. If not, that
767 * should probably be a BUG()
769 if (!ses || !ses->server)
770 return -EIO;
772 mutex_lock(&ses->session_mutex);
773 if (ses->need_reconnect)
774 goto session_already_dead; /* no need to send SMBlogoff if uid
775 already closed due to reconnect */
776 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
777 if (rc) {
778 mutex_unlock(&ses->session_mutex);
779 return rc;
782 pSMB->hdr.Mid = GetNextMid(ses->server);
784 if (ses->server->sec_mode &
785 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
786 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
788 pSMB->hdr.Uid = ses->Suid;
790 pSMB->AndXCommand = 0xFF;
791 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
792 session_already_dead:
793 mutex_unlock(&ses->session_mutex);
795 /* if session dead then we do not need to do ulogoff,
796 since server closed smb session, no sense reporting
797 error */
798 if (rc == -EAGAIN)
799 rc = 0;
800 return rc;
804 CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
805 __u16 type, const struct nls_table *nls_codepage, int remap)
807 TRANSACTION2_SPI_REQ *pSMB = NULL;
808 TRANSACTION2_SPI_RSP *pSMBr = NULL;
809 struct unlink_psx_rq *pRqD;
810 int name_len;
811 int rc = 0;
812 int bytes_returned = 0;
813 __u16 params, param_offset, offset, byte_count;
815 cFYI(1, "In POSIX delete");
816 PsxDelete:
817 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
818 (void **) &pSMBr);
819 if (rc)
820 return rc;
822 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
823 name_len =
824 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
825 PATH_MAX, nls_codepage, remap);
826 name_len++; /* trailing null */
827 name_len *= 2;
828 } else { /* BB add path length overrun check */
829 name_len = strnlen(fileName, PATH_MAX);
830 name_len++; /* trailing null */
831 strncpy(pSMB->FileName, fileName, name_len);
834 params = 6 + name_len;
835 pSMB->MaxParameterCount = cpu_to_le16(2);
836 pSMB->MaxDataCount = 0; /* BB double check this with jra */
837 pSMB->MaxSetupCount = 0;
838 pSMB->Reserved = 0;
839 pSMB->Flags = 0;
840 pSMB->Timeout = 0;
841 pSMB->Reserved2 = 0;
842 param_offset = offsetof(struct smb_com_transaction2_spi_req,
843 InformationLevel) - 4;
844 offset = param_offset + params;
846 /* Setup pointer to Request Data (inode type) */
847 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
848 pRqD->type = cpu_to_le16(type);
849 pSMB->ParameterOffset = cpu_to_le16(param_offset);
850 pSMB->DataOffset = cpu_to_le16(offset);
851 pSMB->SetupCount = 1;
852 pSMB->Reserved3 = 0;
853 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
854 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
856 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
857 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
858 pSMB->ParameterCount = cpu_to_le16(params);
859 pSMB->TotalParameterCount = pSMB->ParameterCount;
860 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
861 pSMB->Reserved4 = 0;
862 inc_rfc1001_len(pSMB, byte_count);
863 pSMB->ByteCount = cpu_to_le16(byte_count);
864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
866 if (rc)
867 cFYI(1, "Posix delete returned %d", rc);
868 cifs_buf_release(pSMB);
870 cifs_stats_inc(&tcon->num_deletes);
872 if (rc == -EAGAIN)
873 goto PsxDelete;
875 return rc;
879 CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
880 const struct nls_table *nls_codepage, int remap)
882 DELETE_FILE_REQ *pSMB = NULL;
883 DELETE_FILE_RSP *pSMBr = NULL;
884 int rc = 0;
885 int bytes_returned;
886 int name_len;
888 DelFileRetry:
889 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
890 (void **) &pSMBr);
891 if (rc)
892 return rc;
894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
895 name_len =
896 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
897 PATH_MAX, nls_codepage, remap);
898 name_len++; /* trailing null */
899 name_len *= 2;
900 } else { /* BB improve check for buffer overruns BB */
901 name_len = strnlen(fileName, PATH_MAX);
902 name_len++; /* trailing null */
903 strncpy(pSMB->fileName, fileName, name_len);
905 pSMB->SearchAttributes =
906 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
907 pSMB->BufferFormat = 0x04;
908 inc_rfc1001_len(pSMB, name_len + 1);
909 pSMB->ByteCount = cpu_to_le16(name_len + 1);
910 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
911 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
912 cifs_stats_inc(&tcon->num_deletes);
913 if (rc)
914 cFYI(1, "Error in RMFile = %d", rc);
916 cifs_buf_release(pSMB);
917 if (rc == -EAGAIN)
918 goto DelFileRetry;
920 return rc;
924 CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
925 const struct nls_table *nls_codepage, int remap)
927 DELETE_DIRECTORY_REQ *pSMB = NULL;
928 DELETE_DIRECTORY_RSP *pSMBr = NULL;
929 int rc = 0;
930 int bytes_returned;
931 int name_len;
933 cFYI(1, "In CIFSSMBRmDir");
934 RmDirRetry:
935 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
936 (void **) &pSMBr);
937 if (rc)
938 return rc;
940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
941 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
942 PATH_MAX, nls_codepage, remap);
943 name_len++; /* trailing null */
944 name_len *= 2;
945 } else { /* BB improve check for buffer overruns BB */
946 name_len = strnlen(dirName, PATH_MAX);
947 name_len++; /* trailing null */
948 strncpy(pSMB->DirName, dirName, name_len);
951 pSMB->BufferFormat = 0x04;
952 inc_rfc1001_len(pSMB, name_len + 1);
953 pSMB->ByteCount = cpu_to_le16(name_len + 1);
954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
956 cifs_stats_inc(&tcon->num_rmdirs);
957 if (rc)
958 cFYI(1, "Error in RMDir = %d", rc);
960 cifs_buf_release(pSMB);
961 if (rc == -EAGAIN)
962 goto RmDirRetry;
963 return rc;
967 CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
968 const char *name, const struct nls_table *nls_codepage, int remap)
970 int rc = 0;
971 CREATE_DIRECTORY_REQ *pSMB = NULL;
972 CREATE_DIRECTORY_RSP *pSMBr = NULL;
973 int bytes_returned;
974 int name_len;
976 cFYI(1, "In CIFSSMBMkDir");
977 MkDirRetry:
978 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
979 (void **) &pSMBr);
980 if (rc)
981 return rc;
983 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
984 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
985 PATH_MAX, nls_codepage, remap);
986 name_len++; /* trailing null */
987 name_len *= 2;
988 } else { /* BB improve check for buffer overruns BB */
989 name_len = strnlen(name, PATH_MAX);
990 name_len++; /* trailing null */
991 strncpy(pSMB->DirName, name, name_len);
994 pSMB->BufferFormat = 0x04;
995 inc_rfc1001_len(pSMB, name_len + 1);
996 pSMB->ByteCount = cpu_to_le16(name_len + 1);
997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
999 cifs_stats_inc(&tcon->num_mkdirs);
1000 if (rc)
1001 cFYI(1, "Error in Mkdir = %d", rc);
1003 cifs_buf_release(pSMB);
1004 if (rc == -EAGAIN)
1005 goto MkDirRetry;
1006 return rc;
1010 CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
1011 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
1012 __u32 *pOplock, const char *name,
1013 const struct nls_table *nls_codepage, int remap)
1015 TRANSACTION2_SPI_REQ *pSMB = NULL;
1016 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1017 int name_len;
1018 int rc = 0;
1019 int bytes_returned = 0;
1020 __u16 params, param_offset, offset, byte_count, count;
1021 OPEN_PSX_REQ *pdata;
1022 OPEN_PSX_RSP *psx_rsp;
1024 cFYI(1, "In POSIX Create");
1025 PsxCreat:
1026 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1027 (void **) &pSMBr);
1028 if (rc)
1029 return rc;
1031 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1032 name_len =
1033 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1034 PATH_MAX, nls_codepage, remap);
1035 name_len++; /* trailing null */
1036 name_len *= 2;
1037 } else { /* BB improve the check for buffer overruns BB */
1038 name_len = strnlen(name, PATH_MAX);
1039 name_len++; /* trailing null */
1040 strncpy(pSMB->FileName, name, name_len);
1043 params = 6 + name_len;
1044 count = sizeof(OPEN_PSX_REQ);
1045 pSMB->MaxParameterCount = cpu_to_le16(2);
1046 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1047 pSMB->MaxSetupCount = 0;
1048 pSMB->Reserved = 0;
1049 pSMB->Flags = 0;
1050 pSMB->Timeout = 0;
1051 pSMB->Reserved2 = 0;
1052 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1053 InformationLevel) - 4;
1054 offset = param_offset + params;
1055 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1056 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1057 pdata->Permissions = cpu_to_le64(mode);
1058 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1059 pdata->OpenFlags = cpu_to_le32(*pOplock);
1060 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1061 pSMB->DataOffset = cpu_to_le16(offset);
1062 pSMB->SetupCount = 1;
1063 pSMB->Reserved3 = 0;
1064 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1065 byte_count = 3 /* pad */ + params + count;
1067 pSMB->DataCount = cpu_to_le16(count);
1068 pSMB->ParameterCount = cpu_to_le16(params);
1069 pSMB->TotalDataCount = pSMB->DataCount;
1070 pSMB->TotalParameterCount = pSMB->ParameterCount;
1071 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1072 pSMB->Reserved4 = 0;
1073 inc_rfc1001_len(pSMB, byte_count);
1074 pSMB->ByteCount = cpu_to_le16(byte_count);
1075 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1076 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1077 if (rc) {
1078 cFYI(1, "Posix create returned %d", rc);
1079 goto psx_create_err;
1082 cFYI(1, "copying inode info");
1083 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1085 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
1086 rc = -EIO; /* bad smb */
1087 goto psx_create_err;
1090 /* copy return information to pRetData */
1091 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1092 + le16_to_cpu(pSMBr->t2.DataOffset));
1094 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1095 if (netfid)
1096 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1097 /* Let caller know file was created so we can set the mode. */
1098 /* Do we care about the CreateAction in any other cases? */
1099 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1100 *pOplock |= CIFS_CREATE_ACTION;
1101 /* check to make sure response data is there */
1102 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1103 pRetData->Type = cpu_to_le32(-1); /* unknown */
1104 cFYI(DBG2, "unknown type");
1105 } else {
1106 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
1107 + sizeof(FILE_UNIX_BASIC_INFO)) {
1108 cERROR(1, "Open response data too small");
1109 pRetData->Type = cpu_to_le32(-1);
1110 goto psx_create_err;
1112 memcpy((char *) pRetData,
1113 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1114 sizeof(FILE_UNIX_BASIC_INFO));
1117 psx_create_err:
1118 cifs_buf_release(pSMB);
1120 if (posix_flags & SMB_O_DIRECTORY)
1121 cifs_stats_inc(&tcon->num_posixmkdirs);
1122 else
1123 cifs_stats_inc(&tcon->num_posixopens);
1125 if (rc == -EAGAIN)
1126 goto PsxCreat;
1128 return rc;
1131 static __u16 convert_disposition(int disposition)
1133 __u16 ofun = 0;
1135 switch (disposition) {
1136 case FILE_SUPERSEDE:
1137 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1138 break;
1139 case FILE_OPEN:
1140 ofun = SMBOPEN_OAPPEND;
1141 break;
1142 case FILE_CREATE:
1143 ofun = SMBOPEN_OCREATE;
1144 break;
1145 case FILE_OPEN_IF:
1146 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1147 break;
1148 case FILE_OVERWRITE:
1149 ofun = SMBOPEN_OTRUNC;
1150 break;
1151 case FILE_OVERWRITE_IF:
1152 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1153 break;
1154 default:
1155 cFYI(1, "unknown disposition %d", disposition);
1156 ofun = SMBOPEN_OAPPEND; /* regular open */
1158 return ofun;
1161 static int
1162 access_flags_to_smbopen_mode(const int access_flags)
1164 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1166 if (masked_flags == GENERIC_READ)
1167 return SMBOPEN_READ;
1168 else if (masked_flags == GENERIC_WRITE)
1169 return SMBOPEN_WRITE;
1171 /* just go for read/write */
1172 return SMBOPEN_READWRITE;
1176 SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
1177 const char *fileName, const int openDisposition,
1178 const int access_flags, const int create_options, __u16 *netfid,
1179 int *pOplock, FILE_ALL_INFO *pfile_info,
1180 const struct nls_table *nls_codepage, int remap)
1182 int rc = -EACCES;
1183 OPENX_REQ *pSMB = NULL;
1184 OPENX_RSP *pSMBr = NULL;
1185 int bytes_returned;
1186 int name_len;
1187 __u16 count;
1189 OldOpenRetry:
1190 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1191 (void **) &pSMBr);
1192 if (rc)
1193 return rc;
1195 pSMB->AndXCommand = 0xFF; /* none */
1197 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1198 count = 1; /* account for one byte pad to word boundary */
1199 name_len =
1200 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1201 fileName, PATH_MAX, nls_codepage, remap);
1202 name_len++; /* trailing null */
1203 name_len *= 2;
1204 } else { /* BB improve check for buffer overruns BB */
1205 count = 0; /* no pad */
1206 name_len = strnlen(fileName, PATH_MAX);
1207 name_len++; /* trailing null */
1208 strncpy(pSMB->fileName, fileName, name_len);
1210 if (*pOplock & REQ_OPLOCK)
1211 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1212 else if (*pOplock & REQ_BATCHOPLOCK)
1213 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1215 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1216 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1217 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1218 /* set file as system file if special file such
1219 as fifo and server expecting SFU style and
1220 no Unix extensions */
1222 if (create_options & CREATE_OPTION_SPECIAL)
1223 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1224 else /* BB FIXME BB */
1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1227 if (create_options & CREATE_OPTION_READONLY)
1228 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1230 /* BB FIXME BB */
1231 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1232 CREATE_OPTIONS_MASK); */
1233 /* BB FIXME END BB */
1235 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1236 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1237 count += name_len;
1238 inc_rfc1001_len(pSMB, count);
1240 pSMB->ByteCount = cpu_to_le16(count);
1241 /* long_op set to 1 to allow for oplock break timeouts */
1242 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1243 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1244 cifs_stats_inc(&tcon->num_opens);
1245 if (rc) {
1246 cFYI(1, "Error in Open = %d", rc);
1247 } else {
1248 /* BB verify if wct == 15 */
1250 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1252 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1253 /* Let caller know file was created so we can set the mode. */
1254 /* Do we care about the CreateAction in any other cases? */
1255 /* BB FIXME BB */
1256 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1257 *pOplock |= CIFS_CREATE_ACTION; */
1258 /* BB FIXME END */
1260 if (pfile_info) {
1261 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1262 pfile_info->LastAccessTime = 0; /* BB fixme */
1263 pfile_info->LastWriteTime = 0; /* BB fixme */
1264 pfile_info->ChangeTime = 0; /* BB fixme */
1265 pfile_info->Attributes =
1266 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1267 /* the file_info buf is endian converted by caller */
1268 pfile_info->AllocationSize =
1269 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1270 pfile_info->EndOfFile = pfile_info->AllocationSize;
1271 pfile_info->NumberOfLinks = cpu_to_le32(1);
1272 pfile_info->DeletePending = 0;
1276 cifs_buf_release(pSMB);
1277 if (rc == -EAGAIN)
1278 goto OldOpenRetry;
1279 return rc;
1283 CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
1284 const char *fileName, const int openDisposition,
1285 const int access_flags, const int create_options, __u16 *netfid,
1286 int *pOplock, FILE_ALL_INFO *pfile_info,
1287 const struct nls_table *nls_codepage, int remap)
1289 int rc = -EACCES;
1290 OPEN_REQ *pSMB = NULL;
1291 OPEN_RSP *pSMBr = NULL;
1292 int bytes_returned;
1293 int name_len;
1294 __u16 count;
1296 openRetry:
1297 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1298 (void **) &pSMBr);
1299 if (rc)
1300 return rc;
1302 pSMB->AndXCommand = 0xFF; /* none */
1304 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1305 count = 1; /* account for one byte pad to word boundary */
1306 name_len =
1307 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1308 fileName, PATH_MAX, nls_codepage, remap);
1309 name_len++; /* trailing null */
1310 name_len *= 2;
1311 pSMB->NameLength = cpu_to_le16(name_len);
1312 } else { /* BB improve check for buffer overruns BB */
1313 count = 0; /* no pad */
1314 name_len = strnlen(fileName, PATH_MAX);
1315 name_len++; /* trailing null */
1316 pSMB->NameLength = cpu_to_le16(name_len);
1317 strncpy(pSMB->fileName, fileName, name_len);
1319 if (*pOplock & REQ_OPLOCK)
1320 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1321 else if (*pOplock & REQ_BATCHOPLOCK)
1322 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1323 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1324 pSMB->AllocationSize = 0;
1325 /* set file as system file if special file such
1326 as fifo and server expecting SFU style and
1327 no Unix extensions */
1328 if (create_options & CREATE_OPTION_SPECIAL)
1329 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1330 else
1331 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1333 /* XP does not handle ATTR_POSIX_SEMANTICS */
1334 /* but it helps speed up case sensitive checks for other
1335 servers such as Samba */
1336 if (tcon->ses->capabilities & CAP_UNIX)
1337 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1339 if (create_options & CREATE_OPTION_READONLY)
1340 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1342 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1343 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1344 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1345 /* BB Expirement with various impersonation levels and verify */
1346 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1347 pSMB->SecurityFlags =
1348 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1350 count += name_len;
1351 inc_rfc1001_len(pSMB, count);
1353 pSMB->ByteCount = cpu_to_le16(count);
1354 /* long_op set to 1 to allow for oplock break timeouts */
1355 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1356 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1357 cifs_stats_inc(&tcon->num_opens);
1358 if (rc) {
1359 cFYI(1, "Error in Open = %d", rc);
1360 } else {
1361 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1362 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1363 /* Let caller know file was created so we can set the mode. */
1364 /* Do we care about the CreateAction in any other cases? */
1365 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1366 *pOplock |= CIFS_CREATE_ACTION;
1367 if (pfile_info) {
1368 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1369 36 /* CreationTime to Attributes */);
1370 /* the file_info buf is endian converted by caller */
1371 pfile_info->AllocationSize = pSMBr->AllocationSize;
1372 pfile_info->EndOfFile = pSMBr->EndOfFile;
1373 pfile_info->NumberOfLinks = cpu_to_le32(1);
1374 pfile_info->DeletePending = 0;
1378 cifs_buf_release(pSMB);
1379 if (rc == -EAGAIN)
1380 goto openRetry;
1381 return rc;
1384 struct cifs_readdata *
1385 cifs_readdata_alloc(unsigned int nr_pages)
1387 struct cifs_readdata *rdata;
1389 /* readdata + 1 kvec for each page */
1390 rdata = kzalloc(sizeof(*rdata) +
1391 sizeof(struct kvec) * nr_pages, GFP_KERNEL);
1392 if (rdata != NULL) {
1393 INIT_WORK(&rdata->work, cifs_readv_complete);
1394 INIT_LIST_HEAD(&rdata->pages);
1396 return rdata;
1399 void
1400 cifs_readdata_free(struct cifs_readdata *rdata)
1402 cifsFileInfo_put(rdata->cfile);
1403 kfree(rdata);
1407 * Discard any remaining data in the current SMB. To do this, we borrow the
1408 * current bigbuf.
1410 static int
1411 cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1413 READ_RSP *rsp = (READ_RSP *)server->smallbuf;
1414 unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length);
1415 int remaining = rfclen + 4 - server->total_read;
1416 struct cifs_readdata *rdata = mid->callback_data;
1418 while (remaining > 0) {
1419 int length;
1421 length = cifs_read_from_socket(server, server->bigbuf,
1422 min_t(unsigned int, remaining,
1423 CIFSMaxBufSize + MAX_CIFS_HDR_SIZE));
1424 if (length < 0)
1425 return length;
1426 server->total_read += length;
1427 remaining -= length;
1430 dequeue_mid(mid, rdata->result);
1431 return 0;
1434 static int
1435 cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1437 int length, len;
1438 unsigned int data_offset, remaining, data_len;
1439 struct cifs_readdata *rdata = mid->callback_data;
1440 READ_RSP *rsp = (READ_RSP *)server->smallbuf;
1441 unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length) + 4;
1442 u64 eof;
1443 pgoff_t eof_index;
1444 struct page *page, *tpage;
1446 cFYI(1, "%s: mid=%u offset=%llu bytes=%u", __func__,
1447 mid->mid, rdata->offset, rdata->bytes);
1450 * read the rest of READ_RSP header (sans Data array), or whatever we
1451 * can if there's not enough data. At this point, we've read down to
1452 * the Mid.
1454 len = min_t(unsigned int, rfclen, sizeof(*rsp)) -
1455 sizeof(struct smb_hdr) + 1;
1457 rdata->iov[0].iov_base = server->smallbuf + sizeof(struct smb_hdr) - 1;
1458 rdata->iov[0].iov_len = len;
1460 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1461 if (length < 0)
1462 return length;
1463 server->total_read += length;
1465 /* Was the SMB read successful? */
1466 rdata->result = map_smb_to_linux_error(&rsp->hdr, false);
1467 if (rdata->result != 0) {
1468 cFYI(1, "%s: server returned error %d", __func__,
1469 rdata->result);
1470 return cifs_readv_discard(server, mid);
1473 /* Is there enough to get to the rest of the READ_RSP header? */
1474 if (server->total_read < sizeof(READ_RSP)) {
1475 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
1476 __func__, server->total_read, sizeof(READ_RSP));
1477 rdata->result = -EIO;
1478 return cifs_readv_discard(server, mid);
1481 data_offset = le16_to_cpu(rsp->DataOffset) + 4;
1482 if (data_offset < server->total_read) {
1484 * win2k8 sometimes sends an offset of 0 when the read
1485 * is beyond the EOF. Treat it as if the data starts just after
1486 * the header.
1488 cFYI(1, "%s: data offset (%u) inside read response header",
1489 __func__, data_offset);
1490 data_offset = server->total_read;
1491 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1492 /* data_offset is beyond the end of smallbuf */
1493 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1494 __func__, data_offset);
1495 rdata->result = -EIO;
1496 return cifs_readv_discard(server, mid);
1499 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1500 server->total_read, data_offset);
1502 len = data_offset - server->total_read;
1503 if (len > 0) {
1504 /* read any junk before data into the rest of smallbuf */
1505 rdata->iov[0].iov_base = server->smallbuf + server->total_read;
1506 rdata->iov[0].iov_len = len;
1507 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1508 if (length < 0)
1509 return length;
1510 server->total_read += length;
1513 /* set up first iov for signature check */
1514 rdata->iov[0].iov_base = server->smallbuf;
1515 rdata->iov[0].iov_len = server->total_read;
1516 cFYI(1, "0: iov_base=%p iov_len=%zu",
1517 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1519 /* how much data is in the response? */
1520 data_len = le16_to_cpu(rsp->DataLengthHigh) << 16;
1521 data_len += le16_to_cpu(rsp->DataLength);
1522 if (data_offset + data_len > rfclen) {
1523 /* data_len is corrupt -- discard frame */
1524 rdata->result = -EIO;
1525 return cifs_readv_discard(server, mid);
1528 /* marshal up the page array */
1529 len = 0;
1530 remaining = data_len;
1531 rdata->nr_iov = 1;
1533 /* determine the eof that the server (probably) has */
1534 eof = CIFS_I(rdata->mapping->host)->server_eof;
1535 eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
1536 cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
1538 list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
1539 if (remaining >= PAGE_CACHE_SIZE) {
1540 /* enough data to fill the page */
1541 rdata->iov[rdata->nr_iov].iov_base = kmap(page);
1542 rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE;
1543 cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
1544 rdata->nr_iov, page->index,
1545 rdata->iov[rdata->nr_iov].iov_base,
1546 rdata->iov[rdata->nr_iov].iov_len);
1547 ++rdata->nr_iov;
1548 len += PAGE_CACHE_SIZE;
1549 remaining -= PAGE_CACHE_SIZE;
1550 } else if (remaining > 0) {
1551 /* enough for partial page, fill and zero the rest */
1552 rdata->iov[rdata->nr_iov].iov_base = kmap(page);
1553 rdata->iov[rdata->nr_iov].iov_len = remaining;
1554 cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
1555 rdata->nr_iov, page->index,
1556 rdata->iov[rdata->nr_iov].iov_base,
1557 rdata->iov[rdata->nr_iov].iov_len);
1558 memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
1559 '\0', PAGE_CACHE_SIZE - remaining);
1560 ++rdata->nr_iov;
1561 len += remaining;
1562 remaining = 0;
1563 } else if (page->index > eof_index) {
1565 * The VFS will not try to do readahead past the
1566 * i_size, but it's possible that we have outstanding
1567 * writes with gaps in the middle and the i_size hasn't
1568 * caught up yet. Populate those with zeroed out pages
1569 * to prevent the VFS from repeatedly attempting to
1570 * fill them until the writes are flushed.
1572 zero_user(page, 0, PAGE_CACHE_SIZE);
1573 list_del(&page->lru);
1574 lru_cache_add_file(page);
1575 flush_dcache_page(page);
1576 SetPageUptodate(page);
1577 unlock_page(page);
1578 page_cache_release(page);
1579 } else {
1580 /* no need to hold page hostage */
1581 list_del(&page->lru);
1582 lru_cache_add_file(page);
1583 unlock_page(page);
1584 page_cache_release(page);
1588 /* issue the read if we have any iovecs left to fill */
1589 if (rdata->nr_iov > 1) {
1590 length = cifs_readv_from_socket(server, &rdata->iov[1],
1591 rdata->nr_iov - 1, len);
1592 if (length < 0)
1593 return length;
1594 server->total_read += length;
1595 } else {
1596 length = 0;
1599 rdata->bytes = length;
1601 cFYI(1, "total_read=%u rfclen=%u remaining=%u", server->total_read,
1602 rfclen, remaining);
1604 /* discard anything left over */
1605 if (server->total_read < rfclen)
1606 return cifs_readv_discard(server, mid);
1608 dequeue_mid(mid, false);
1609 return length;
1612 static void
1613 cifs_readv_complete(struct work_struct *work)
1615 struct cifs_readdata *rdata = container_of(work,
1616 struct cifs_readdata, work);
1617 struct page *page, *tpage;
1619 list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
1620 list_del(&page->lru);
1621 lru_cache_add_file(page);
1623 if (rdata->result == 0) {
1624 kunmap(page);
1625 flush_dcache_page(page);
1626 SetPageUptodate(page);
1629 unlock_page(page);
1631 if (rdata->result == 0)
1632 cifs_readpage_to_fscache(rdata->mapping->host, page);
1634 page_cache_release(page);
1636 cifs_readdata_free(rdata);
1639 static void
1640 cifs_readv_callback(struct mid_q_entry *mid)
1642 struct cifs_readdata *rdata = mid->callback_data;
1643 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1644 struct TCP_Server_Info *server = tcon->ses->server;
1646 cFYI(1, "%s: mid=%u state=%d result=%d bytes=%u", __func__,
1647 mid->mid, mid->midState, rdata->result, rdata->bytes);
1649 switch (mid->midState) {
1650 case MID_RESPONSE_RECEIVED:
1651 /* result already set, check signature */
1652 if (server->sec_mode &
1653 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1654 if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
1655 server, mid->sequence_number + 1))
1656 cERROR(1, "Unexpected SMB signature");
1658 /* FIXME: should this be counted toward the initiating task? */
1659 task_io_account_read(rdata->bytes);
1660 cifs_stats_bytes_read(tcon, rdata->bytes);
1661 break;
1662 case MID_REQUEST_SUBMITTED:
1663 case MID_RETRY_NEEDED:
1664 rdata->result = -EAGAIN;
1665 break;
1666 default:
1667 rdata->result = -EIO;
1670 queue_work(system_nrt_wq, &rdata->work);
1671 DeleteMidQEntry(mid);
1672 atomic_dec(&server->inFlight);
1673 wake_up(&server->request_q);
1676 /* cifs_async_readv - send an async write, and set up mid to handle result */
1678 cifs_async_readv(struct cifs_readdata *rdata)
1680 int rc;
1681 READ_REQ *smb = NULL;
1682 int wct;
1683 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1685 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1686 rdata->offset, rdata->bytes);
1688 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1689 wct = 12;
1690 else {
1691 wct = 10; /* old style read */
1692 if ((rdata->offset >> 32) > 0) {
1693 /* can not handle this big offset for old */
1694 return -EIO;
1698 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1699 if (rc)
1700 return rc;
1702 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1703 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1705 smb->AndXCommand = 0xFF; /* none */
1706 smb->Fid = rdata->cfile->netfid;
1707 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1708 if (wct == 12)
1709 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1710 smb->Remaining = 0;
1711 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1712 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1713 if (wct == 12)
1714 smb->ByteCount = 0;
1715 else {
1716 /* old style read */
1717 struct smb_com_readx_req *smbr =
1718 (struct smb_com_readx_req *)smb;
1719 smbr->ByteCount = 0;
1722 /* 4 for RFC1001 length + 1 for BCC */
1723 rdata->iov[0].iov_base = smb;
1724 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1726 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1727 cifs_readv_receive, cifs_readv_callback,
1728 rdata, false);
1730 if (rc == 0)
1731 cifs_stats_inc(&tcon->num_reads);
1733 cifs_small_buf_release(smb);
1734 return rc;
1738 CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
1739 char **buf, int *pbuf_type)
1741 int rc = -EACCES;
1742 READ_REQ *pSMB = NULL;
1743 READ_RSP *pSMBr = NULL;
1744 char *pReadData = NULL;
1745 int wct;
1746 int resp_buf_type = 0;
1747 struct kvec iov[1];
1748 __u32 pid = io_parms->pid;
1749 __u16 netfid = io_parms->netfid;
1750 __u64 offset = io_parms->offset;
1751 struct cifs_tcon *tcon = io_parms->tcon;
1752 unsigned int count = io_parms->length;
1754 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
1755 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1756 wct = 12;
1757 else {
1758 wct = 10; /* old style read */
1759 if ((offset >> 32) > 0) {
1760 /* can not handle this big offset for old */
1761 return -EIO;
1765 *nbytes = 0;
1766 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1767 if (rc)
1768 return rc;
1770 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1771 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1773 /* tcon and ses pointer are checked in smb_init */
1774 if (tcon->ses->server == NULL)
1775 return -ECONNABORTED;
1777 pSMB->AndXCommand = 0xFF; /* none */
1778 pSMB->Fid = netfid;
1779 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1780 if (wct == 12)
1781 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1783 pSMB->Remaining = 0;
1784 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1785 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1786 if (wct == 12)
1787 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1788 else {
1789 /* old style read */
1790 struct smb_com_readx_req *pSMBW =
1791 (struct smb_com_readx_req *)pSMB;
1792 pSMBW->ByteCount = 0;
1795 iov[0].iov_base = (char *)pSMB;
1796 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
1797 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1798 &resp_buf_type, CIFS_LOG_ERROR);
1799 cifs_stats_inc(&tcon->num_reads);
1800 pSMBr = (READ_RSP *)iov[0].iov_base;
1801 if (rc) {
1802 cERROR(1, "Send error in read = %d", rc);
1803 } else {
1804 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1805 data_length = data_length << 16;
1806 data_length += le16_to_cpu(pSMBr->DataLength);
1807 *nbytes = data_length;
1809 /*check that DataLength would not go beyond end of SMB */
1810 if ((data_length > CIFSMaxBufSize)
1811 || (data_length > count)) {
1812 cFYI(1, "bad length %d for count %d",
1813 data_length, count);
1814 rc = -EIO;
1815 *nbytes = 0;
1816 } else {
1817 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1818 le16_to_cpu(pSMBr->DataOffset);
1819 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1820 cERROR(1, "Faulting on read rc = %d",rc);
1821 rc = -EFAULT;
1822 }*/ /* can not use copy_to_user when using page cache*/
1823 if (*buf)
1824 memcpy(*buf, pReadData, data_length);
1828 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1829 if (*buf) {
1830 if (resp_buf_type == CIFS_SMALL_BUFFER)
1831 cifs_small_buf_release(iov[0].iov_base);
1832 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1833 cifs_buf_release(iov[0].iov_base);
1834 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1835 /* return buffer to caller to free */
1836 *buf = iov[0].iov_base;
1837 if (resp_buf_type == CIFS_SMALL_BUFFER)
1838 *pbuf_type = CIFS_SMALL_BUFFER;
1839 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1840 *pbuf_type = CIFS_LARGE_BUFFER;
1841 } /* else no valid buffer on return - leave as null */
1843 /* Note: On -EAGAIN error only caller can retry on handle based calls
1844 since file handle passed in no longer valid */
1845 return rc;
1850 CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1851 unsigned int *nbytes, const char *buf,
1852 const char __user *ubuf, const int long_op)
1854 int rc = -EACCES;
1855 WRITE_REQ *pSMB = NULL;
1856 WRITE_RSP *pSMBr = NULL;
1857 int bytes_returned, wct;
1858 __u32 bytes_sent;
1859 __u16 byte_count;
1860 __u32 pid = io_parms->pid;
1861 __u16 netfid = io_parms->netfid;
1862 __u64 offset = io_parms->offset;
1863 struct cifs_tcon *tcon = io_parms->tcon;
1864 unsigned int count = io_parms->length;
1866 *nbytes = 0;
1868 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
1869 if (tcon->ses == NULL)
1870 return -ECONNABORTED;
1872 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1873 wct = 14;
1874 else {
1875 wct = 12;
1876 if ((offset >> 32) > 0) {
1877 /* can not handle big offset for old srv */
1878 return -EIO;
1882 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1883 (void **) &pSMBr);
1884 if (rc)
1885 return rc;
1887 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1888 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1890 /* tcon and ses pointer are checked in smb_init */
1891 if (tcon->ses->server == NULL)
1892 return -ECONNABORTED;
1894 pSMB->AndXCommand = 0xFF; /* none */
1895 pSMB->Fid = netfid;
1896 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1897 if (wct == 14)
1898 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1900 pSMB->Reserved = 0xFFFFFFFF;
1901 pSMB->WriteMode = 0;
1902 pSMB->Remaining = 0;
1904 /* Can increase buffer size if buffer is big enough in some cases ie we
1905 can send more if LARGE_WRITE_X capability returned by the server and if
1906 our buffer is big enough or if we convert to iovecs on socket writes
1907 and eliminate the copy to the CIFS buffer */
1908 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1909 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1910 } else {
1911 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1912 & ~0xFF;
1915 if (bytes_sent > count)
1916 bytes_sent = count;
1917 pSMB->DataOffset =
1918 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1919 if (buf)
1920 memcpy(pSMB->Data, buf, bytes_sent);
1921 else if (ubuf) {
1922 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1923 cifs_buf_release(pSMB);
1924 return -EFAULT;
1926 } else if (count != 0) {
1927 /* No buffer */
1928 cifs_buf_release(pSMB);
1929 return -EINVAL;
1930 } /* else setting file size with write of zero bytes */
1931 if (wct == 14)
1932 byte_count = bytes_sent + 1; /* pad */
1933 else /* wct == 12 */
1934 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1936 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1937 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1938 inc_rfc1001_len(pSMB, byte_count);
1940 if (wct == 14)
1941 pSMB->ByteCount = cpu_to_le16(byte_count);
1942 else { /* old style write has byte count 4 bytes earlier
1943 so 4 bytes pad */
1944 struct smb_com_writex_req *pSMBW =
1945 (struct smb_com_writex_req *)pSMB;
1946 pSMBW->ByteCount = cpu_to_le16(byte_count);
1949 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1950 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1951 cifs_stats_inc(&tcon->num_writes);
1952 if (rc) {
1953 cFYI(1, "Send error in write = %d", rc);
1954 } else {
1955 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1956 *nbytes = (*nbytes) << 16;
1957 *nbytes += le16_to_cpu(pSMBr->Count);
1960 * Mask off high 16 bits when bytes written as returned by the
1961 * server is greater than bytes requested by the client. Some
1962 * OS/2 servers are known to set incorrect CountHigh values.
1964 if (*nbytes > count)
1965 *nbytes &= 0xFFFF;
1968 cifs_buf_release(pSMB);
1970 /* Note: On -EAGAIN error only caller can retry on handle based calls
1971 since file handle passed in no longer valid */
1973 return rc;
1976 void
1977 cifs_writedata_release(struct kref *refcount)
1979 struct cifs_writedata *wdata = container_of(refcount,
1980 struct cifs_writedata, refcount);
1982 if (wdata->cfile)
1983 cifsFileInfo_put(wdata->cfile);
1985 kfree(wdata);
1989 * Write failed with a retryable error. Resend the write request. It's also
1990 * possible that the page was redirtied so re-clean the page.
1992 static void
1993 cifs_writev_requeue(struct cifs_writedata *wdata)
1995 int i, rc;
1996 struct inode *inode = wdata->cfile->dentry->d_inode;
1998 for (i = 0; i < wdata->nr_pages; i++) {
1999 lock_page(wdata->pages[i]);
2000 clear_page_dirty_for_io(wdata->pages[i]);
2003 do {
2004 rc = cifs_async_writev(wdata);
2005 } while (rc == -EAGAIN);
2007 for (i = 0; i < wdata->nr_pages; i++) {
2008 if (rc != 0)
2009 SetPageError(wdata->pages[i]);
2010 unlock_page(wdata->pages[i]);
2013 mapping_set_error(inode->i_mapping, rc);
2014 kref_put(&wdata->refcount, cifs_writedata_release);
2017 static void
2018 cifs_writev_complete(struct work_struct *work)
2020 struct cifs_writedata *wdata = container_of(work,
2021 struct cifs_writedata, work);
2022 struct inode *inode = wdata->cfile->dentry->d_inode;
2023 int i = 0;
2025 if (wdata->result == 0) {
2026 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
2027 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2028 wdata->bytes);
2029 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2030 return cifs_writev_requeue(wdata);
2032 for (i = 0; i < wdata->nr_pages; i++) {
2033 struct page *page = wdata->pages[i];
2034 if (wdata->result == -EAGAIN)
2035 __set_page_dirty_nobuffers(page);
2036 else if (wdata->result < 0)
2037 SetPageError(page);
2038 end_page_writeback(page);
2039 page_cache_release(page);
2041 if (wdata->result != -EAGAIN)
2042 mapping_set_error(inode->i_mapping, wdata->result);
2043 kref_put(&wdata->refcount, cifs_writedata_release);
2046 struct cifs_writedata *
2047 cifs_writedata_alloc(unsigned int nr_pages)
2049 struct cifs_writedata *wdata;
2051 /* this would overflow */
2052 if (nr_pages == 0) {
2053 cERROR(1, "%s: called with nr_pages == 0!", __func__);
2054 return NULL;
2057 /* writedata + number of page pointers */
2058 wdata = kzalloc(sizeof(*wdata) +
2059 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
2060 if (wdata != NULL) {
2061 INIT_WORK(&wdata->work, cifs_writev_complete);
2062 kref_init(&wdata->refcount);
2064 return wdata;
2068 * Check the midState and signature on received buffer (if any), and queue the
2069 * workqueue completion task.
2071 static void
2072 cifs_writev_callback(struct mid_q_entry *mid)
2074 struct cifs_writedata *wdata = mid->callback_data;
2075 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
2076 unsigned int written;
2077 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2079 switch (mid->midState) {
2080 case MID_RESPONSE_RECEIVED:
2081 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2082 if (wdata->result != 0)
2083 break;
2085 written = le16_to_cpu(smb->CountHigh);
2086 written <<= 16;
2087 written += le16_to_cpu(smb->Count);
2089 * Mask off high 16 bits when bytes written as returned
2090 * by the server is greater than bytes requested by the
2091 * client. OS/2 servers are known to set incorrect
2092 * CountHigh values.
2094 if (written > wdata->bytes)
2095 written &= 0xFFFF;
2097 if (written < wdata->bytes)
2098 wdata->result = -ENOSPC;
2099 else
2100 wdata->bytes = written;
2101 break;
2102 case MID_REQUEST_SUBMITTED:
2103 case MID_RETRY_NEEDED:
2104 wdata->result = -EAGAIN;
2105 break;
2106 default:
2107 wdata->result = -EIO;
2108 break;
2111 queue_work(system_nrt_wq, &wdata->work);
2112 DeleteMidQEntry(mid);
2113 atomic_dec(&tcon->ses->server->inFlight);
2114 wake_up(&tcon->ses->server->request_q);
2117 /* cifs_async_writev - send an async write, and set up mid to handle result */
2119 cifs_async_writev(struct cifs_writedata *wdata)
2121 int i, rc = -EACCES;
2122 WRITE_REQ *smb = NULL;
2123 int wct;
2124 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
2125 struct inode *inode = wdata->cfile->dentry->d_inode;
2126 struct kvec *iov = NULL;
2128 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2129 wct = 14;
2130 } else {
2131 wct = 12;
2132 if (wdata->offset >> 32 > 0) {
2133 /* can not handle big offset for old srv */
2134 return -EIO;
2138 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2139 if (rc)
2140 goto async_writev_out;
2142 /* 1 iov per page + 1 for header */
2143 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2144 if (iov == NULL) {
2145 rc = -ENOMEM;
2146 goto async_writev_out;
2149 smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
2150 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
2152 smb->AndXCommand = 0xFF; /* none */
2153 smb->Fid = wdata->cfile->netfid;
2154 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2155 if (wct == 14)
2156 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2157 smb->Reserved = 0xFFFFFFFF;
2158 smb->WriteMode = 0;
2159 smb->Remaining = 0;
2161 smb->DataOffset =
2162 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2164 /* 4 for RFC1001 length + 1 for BCC */
2165 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2166 iov[0].iov_base = smb;
2168 /* marshal up the pages into iov array */
2169 wdata->bytes = 0;
2170 for (i = 0; i < wdata->nr_pages; i++) {
2171 iov[i + 1].iov_len = min(inode->i_size -
2172 page_offset(wdata->pages[i]),
2173 (loff_t)PAGE_CACHE_SIZE);
2174 iov[i + 1].iov_base = kmap(wdata->pages[i]);
2175 wdata->bytes += iov[i + 1].iov_len;
2178 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2180 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2181 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2183 if (wct == 14) {
2184 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2185 put_bcc(wdata->bytes + 1, &smb->hdr);
2186 } else {
2187 /* wct == 12 */
2188 struct smb_com_writex_req *smbw =
2189 (struct smb_com_writex_req *)smb;
2190 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2191 put_bcc(wdata->bytes + 5, &smbw->hdr);
2192 iov[0].iov_len += 4; /* pad bigger by four bytes */
2195 kref_get(&wdata->refcount);
2196 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
2197 NULL, cifs_writev_callback, wdata, false);
2199 if (rc == 0)
2200 cifs_stats_inc(&tcon->num_writes);
2201 else
2202 kref_put(&wdata->refcount, cifs_writedata_release);
2204 /* send is done, unmap pages */
2205 for (i = 0; i < wdata->nr_pages; i++)
2206 kunmap(wdata->pages[i]);
2208 async_writev_out:
2209 cifs_small_buf_release(smb);
2210 kfree(iov);
2211 return rc;
2215 CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
2216 unsigned int *nbytes, struct kvec *iov, int n_vec,
2217 const int long_op)
2219 int rc = -EACCES;
2220 WRITE_REQ *pSMB = NULL;
2221 int wct;
2222 int smb_hdr_len;
2223 int resp_buf_type = 0;
2224 __u32 pid = io_parms->pid;
2225 __u16 netfid = io_parms->netfid;
2226 __u64 offset = io_parms->offset;
2227 struct cifs_tcon *tcon = io_parms->tcon;
2228 unsigned int count = io_parms->length;
2230 *nbytes = 0;
2232 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
2234 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2235 wct = 14;
2236 } else {
2237 wct = 12;
2238 if ((offset >> 32) > 0) {
2239 /* can not handle big offset for old srv */
2240 return -EIO;
2243 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
2244 if (rc)
2245 return rc;
2247 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2248 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2250 /* tcon and ses pointer are checked in smb_init */
2251 if (tcon->ses->server == NULL)
2252 return -ECONNABORTED;
2254 pSMB->AndXCommand = 0xFF; /* none */
2255 pSMB->Fid = netfid;
2256 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
2257 if (wct == 14)
2258 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
2259 pSMB->Reserved = 0xFFFFFFFF;
2260 pSMB->WriteMode = 0;
2261 pSMB->Remaining = 0;
2263 pSMB->DataOffset =
2264 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2266 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2267 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
2268 /* header + 1 byte pad */
2269 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
2270 if (wct == 14)
2271 inc_rfc1001_len(pSMB, count + 1);
2272 else /* wct == 12 */
2273 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
2274 if (wct == 14)
2275 pSMB->ByteCount = cpu_to_le16(count + 1);
2276 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
2277 struct smb_com_writex_req *pSMBW =
2278 (struct smb_com_writex_req *)pSMB;
2279 pSMBW->ByteCount = cpu_to_le16(count + 5);
2281 iov[0].iov_base = pSMB;
2282 if (wct == 14)
2283 iov[0].iov_len = smb_hdr_len + 4;
2284 else /* wct == 12 pad bigger by four bytes */
2285 iov[0].iov_len = smb_hdr_len + 8;
2288 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
2289 long_op);
2290 cifs_stats_inc(&tcon->num_writes);
2291 if (rc) {
2292 cFYI(1, "Send error Write2 = %d", rc);
2293 } else if (resp_buf_type == 0) {
2294 /* presumably this can not happen, but best to be safe */
2295 rc = -EIO;
2296 } else {
2297 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
2298 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2299 *nbytes = (*nbytes) << 16;
2300 *nbytes += le16_to_cpu(pSMBr->Count);
2303 * Mask off high 16 bits when bytes written as returned by the
2304 * server is greater than bytes requested by the client. OS/2
2305 * servers are known to set incorrect CountHigh values.
2307 if (*nbytes > count)
2308 *nbytes &= 0xFFFF;
2311 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2312 if (resp_buf_type == CIFS_SMALL_BUFFER)
2313 cifs_small_buf_release(iov[0].iov_base);
2314 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2315 cifs_buf_release(iov[0].iov_base);
2317 /* Note: On -EAGAIN error only caller can retry on handle based calls
2318 since file handle passed in no longer valid */
2320 return rc;
2323 int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
2324 const __u8 lock_type, const __u32 num_unlock,
2325 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2327 int rc = 0;
2328 LOCK_REQ *pSMB = NULL;
2329 struct kvec iov[2];
2330 int resp_buf_type;
2331 __u16 count;
2333 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2335 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2336 if (rc)
2337 return rc;
2339 pSMB->Timeout = 0;
2340 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2341 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2342 pSMB->LockType = lock_type;
2343 pSMB->AndXCommand = 0xFF; /* none */
2344 pSMB->Fid = netfid; /* netfid stays le */
2346 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2347 inc_rfc1001_len(pSMB, count);
2348 pSMB->ByteCount = cpu_to_le16(count);
2350 iov[0].iov_base = (char *)pSMB;
2351 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2352 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2353 iov[1].iov_base = (char *)buf;
2354 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2356 cifs_stats_inc(&tcon->num_locks);
2357 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2358 if (rc)
2359 cFYI(1, "Send error in cifs_lockv = %d", rc);
2361 return rc;
2365 CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
2366 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
2367 const __u64 offset, const __u32 numUnlock,
2368 const __u32 numLock, const __u8 lockType,
2369 const bool waitFlag, const __u8 oplock_level)
2371 int rc = 0;
2372 LOCK_REQ *pSMB = NULL;
2373 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
2374 int bytes_returned;
2375 int timeout = 0;
2376 __u16 count;
2378 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
2379 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2381 if (rc)
2382 return rc;
2384 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
2385 timeout = CIFS_ASYNC_OP; /* no response expected */
2386 pSMB->Timeout = 0;
2387 } else if (waitFlag) {
2388 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2389 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2390 } else {
2391 pSMB->Timeout = 0;
2394 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2395 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2396 pSMB->LockType = lockType;
2397 pSMB->OplockLevel = oplock_level;
2398 pSMB->AndXCommand = 0xFF; /* none */
2399 pSMB->Fid = smb_file_id; /* netfid stays le */
2401 if ((numLock != 0) || (numUnlock != 0)) {
2402 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
2403 /* BB where to store pid high? */
2404 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2405 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2406 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2407 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2408 count = sizeof(LOCKING_ANDX_RANGE);
2409 } else {
2410 /* oplock break */
2411 count = 0;
2413 inc_rfc1001_len(pSMB, count);
2414 pSMB->ByteCount = cpu_to_le16(count);
2416 if (waitFlag) {
2417 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2418 (struct smb_hdr *) pSMB, &bytes_returned);
2419 cifs_small_buf_release(pSMB);
2420 } else {
2421 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
2422 timeout);
2423 /* SMB buffer freed by function above */
2425 cifs_stats_inc(&tcon->num_locks);
2426 if (rc)
2427 cFYI(1, "Send error in Lock = %d", rc);
2429 /* Note: On -EAGAIN error only caller can retry on handle based calls
2430 since file handle passed in no longer valid */
2431 return rc;
2435 CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
2436 const __u16 smb_file_id, const __u32 netpid, const int get_flag,
2437 const __u64 len, struct file_lock *pLockData,
2438 const __u16 lock_type, const bool waitFlag)
2440 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2441 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2442 struct cifs_posix_lock *parm_data;
2443 int rc = 0;
2444 int timeout = 0;
2445 int bytes_returned = 0;
2446 int resp_buf_type = 0;
2447 __u16 params, param_offset, offset, byte_count, count;
2448 struct kvec iov[1];
2450 cFYI(1, "Posix Lock");
2452 if (pLockData == NULL)
2453 return -EINVAL;
2455 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2457 if (rc)
2458 return rc;
2460 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2462 params = 6;
2463 pSMB->MaxSetupCount = 0;
2464 pSMB->Reserved = 0;
2465 pSMB->Flags = 0;
2466 pSMB->Reserved2 = 0;
2467 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2468 offset = param_offset + params;
2470 count = sizeof(struct cifs_posix_lock);
2471 pSMB->MaxParameterCount = cpu_to_le16(2);
2472 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2473 pSMB->SetupCount = 1;
2474 pSMB->Reserved3 = 0;
2475 if (get_flag)
2476 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2477 else
2478 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2479 byte_count = 3 /* pad */ + params + count;
2480 pSMB->DataCount = cpu_to_le16(count);
2481 pSMB->ParameterCount = cpu_to_le16(params);
2482 pSMB->TotalDataCount = pSMB->DataCount;
2483 pSMB->TotalParameterCount = pSMB->ParameterCount;
2484 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2485 parm_data = (struct cifs_posix_lock *)
2486 (((char *) &pSMB->hdr.Protocol) + offset);
2488 parm_data->lock_type = cpu_to_le16(lock_type);
2489 if (waitFlag) {
2490 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2491 parm_data->lock_flags = cpu_to_le16(1);
2492 pSMB->Timeout = cpu_to_le32(-1);
2493 } else
2494 pSMB->Timeout = 0;
2496 parm_data->pid = cpu_to_le32(netpid);
2497 parm_data->start = cpu_to_le64(pLockData->fl_start);
2498 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
2500 pSMB->DataOffset = cpu_to_le16(offset);
2501 pSMB->Fid = smb_file_id;
2502 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2503 pSMB->Reserved4 = 0;
2504 inc_rfc1001_len(pSMB, byte_count);
2505 pSMB->ByteCount = cpu_to_le16(byte_count);
2506 if (waitFlag) {
2507 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2508 (struct smb_hdr *) pSMBr, &bytes_returned);
2509 } else {
2510 iov[0].iov_base = (char *)pSMB;
2511 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
2512 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2513 &resp_buf_type, timeout);
2514 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2515 not try to free it twice below on exit */
2516 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
2519 if (rc) {
2520 cFYI(1, "Send error in Posix Lock = %d", rc);
2521 } else if (get_flag) {
2522 /* lock structure can be returned on get */
2523 __u16 data_offset;
2524 __u16 data_count;
2525 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2527 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
2528 rc = -EIO; /* bad smb */
2529 goto plk_err_exit;
2531 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2532 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2533 if (data_count < sizeof(struct cifs_posix_lock)) {
2534 rc = -EIO;
2535 goto plk_err_exit;
2537 parm_data = (struct cifs_posix_lock *)
2538 ((char *)&pSMBr->hdr.Protocol + data_offset);
2539 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
2540 pLockData->fl_type = F_UNLCK;
2541 else {
2542 if (parm_data->lock_type ==
2543 __constant_cpu_to_le16(CIFS_RDLCK))
2544 pLockData->fl_type = F_RDLCK;
2545 else if (parm_data->lock_type ==
2546 __constant_cpu_to_le16(CIFS_WRLCK))
2547 pLockData->fl_type = F_WRLCK;
2549 pLockData->fl_start = le64_to_cpu(parm_data->start);
2550 pLockData->fl_end = pLockData->fl_start +
2551 le64_to_cpu(parm_data->length) - 1;
2552 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
2556 plk_err_exit:
2557 if (pSMB)
2558 cifs_small_buf_release(pSMB);
2560 if (resp_buf_type == CIFS_SMALL_BUFFER)
2561 cifs_small_buf_release(iov[0].iov_base);
2562 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2563 cifs_buf_release(iov[0].iov_base);
2565 /* Note: On -EAGAIN error only caller can retry on handle based calls
2566 since file handle passed in no longer valid */
2568 return rc;
2573 CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
2575 int rc = 0;
2576 CLOSE_REQ *pSMB = NULL;
2577 cFYI(1, "In CIFSSMBClose");
2579 /* do not retry on dead session on close */
2580 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
2581 if (rc == -EAGAIN)
2582 return 0;
2583 if (rc)
2584 return rc;
2586 pSMB->FileID = (__u16) smb_file_id;
2587 pSMB->LastWriteTime = 0xFFFFFFFF;
2588 pSMB->ByteCount = 0;
2589 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2590 cifs_stats_inc(&tcon->num_closes);
2591 if (rc) {
2592 if (rc != -EINTR) {
2593 /* EINTR is expected when user ctl-c to kill app */
2594 cERROR(1, "Send error in Close = %d", rc);
2598 /* Since session is dead, file will be closed on server already */
2599 if (rc == -EAGAIN)
2600 rc = 0;
2602 return rc;
2606 CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
2608 int rc = 0;
2609 FLUSH_REQ *pSMB = NULL;
2610 cFYI(1, "In CIFSSMBFlush");
2612 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2613 if (rc)
2614 return rc;
2616 pSMB->FileID = (__u16) smb_file_id;
2617 pSMB->ByteCount = 0;
2618 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2619 cifs_stats_inc(&tcon->num_flushes);
2620 if (rc)
2621 cERROR(1, "Send error in Flush = %d", rc);
2623 return rc;
2627 CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
2628 const char *fromName, const char *toName,
2629 const struct nls_table *nls_codepage, int remap)
2631 int rc = 0;
2632 RENAME_REQ *pSMB = NULL;
2633 RENAME_RSP *pSMBr = NULL;
2634 int bytes_returned;
2635 int name_len, name_len2;
2636 __u16 count;
2638 cFYI(1, "In CIFSSMBRename");
2639 renameRetry:
2640 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2641 (void **) &pSMBr);
2642 if (rc)
2643 return rc;
2645 pSMB->BufferFormat = 0x04;
2646 pSMB->SearchAttributes =
2647 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2648 ATTR_DIRECTORY);
2650 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2651 name_len =
2652 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2653 PATH_MAX, nls_codepage, remap);
2654 name_len++; /* trailing null */
2655 name_len *= 2;
2656 pSMB->OldFileName[name_len] = 0x04; /* pad */
2657 /* protocol requires ASCII signature byte on Unicode string */
2658 pSMB->OldFileName[name_len + 1] = 0x00;
2659 name_len2 =
2660 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2661 toName, PATH_MAX, nls_codepage, remap);
2662 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2663 name_len2 *= 2; /* convert to bytes */
2664 } else { /* BB improve the check for buffer overruns BB */
2665 name_len = strnlen(fromName, PATH_MAX);
2666 name_len++; /* trailing null */
2667 strncpy(pSMB->OldFileName, fromName, name_len);
2668 name_len2 = strnlen(toName, PATH_MAX);
2669 name_len2++; /* trailing null */
2670 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2671 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2672 name_len2++; /* trailing null */
2673 name_len2++; /* signature byte */
2676 count = 1 /* 1st signature byte */ + name_len + name_len2;
2677 inc_rfc1001_len(pSMB, count);
2678 pSMB->ByteCount = cpu_to_le16(count);
2680 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2681 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2682 cifs_stats_inc(&tcon->num_renames);
2683 if (rc)
2684 cFYI(1, "Send error in rename = %d", rc);
2686 cifs_buf_release(pSMB);
2688 if (rc == -EAGAIN)
2689 goto renameRetry;
2691 return rc;
2694 int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
2695 int netfid, const char *target_name,
2696 const struct nls_table *nls_codepage, int remap)
2698 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2699 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2700 struct set_file_rename *rename_info;
2701 char *data_offset;
2702 char dummy_string[30];
2703 int rc = 0;
2704 int bytes_returned = 0;
2705 int len_of_str;
2706 __u16 params, param_offset, offset, count, byte_count;
2708 cFYI(1, "Rename to File by handle");
2709 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2710 (void **) &pSMBr);
2711 if (rc)
2712 return rc;
2714 params = 6;
2715 pSMB->MaxSetupCount = 0;
2716 pSMB->Reserved = 0;
2717 pSMB->Flags = 0;
2718 pSMB->Timeout = 0;
2719 pSMB->Reserved2 = 0;
2720 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2721 offset = param_offset + params;
2723 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2724 rename_info = (struct set_file_rename *) data_offset;
2725 pSMB->MaxParameterCount = cpu_to_le16(2);
2726 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2727 pSMB->SetupCount = 1;
2728 pSMB->Reserved3 = 0;
2729 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2730 byte_count = 3 /* pad */ + params;
2731 pSMB->ParameterCount = cpu_to_le16(params);
2732 pSMB->TotalParameterCount = pSMB->ParameterCount;
2733 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2734 pSMB->DataOffset = cpu_to_le16(offset);
2735 /* construct random name ".cifs_tmp<inodenum><mid>" */
2736 rename_info->overwrite = cpu_to_le32(1);
2737 rename_info->root_fid = 0;
2738 /* unicode only call */
2739 if (target_name == NULL) {
2740 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2741 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2742 dummy_string, 24, nls_codepage, remap);
2743 } else {
2744 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2745 target_name, PATH_MAX, nls_codepage,
2746 remap);
2748 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2749 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2750 byte_count += count;
2751 pSMB->DataCount = cpu_to_le16(count);
2752 pSMB->TotalDataCount = pSMB->DataCount;
2753 pSMB->Fid = netfid;
2754 pSMB->InformationLevel =
2755 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2756 pSMB->Reserved4 = 0;
2757 inc_rfc1001_len(pSMB, byte_count);
2758 pSMB->ByteCount = cpu_to_le16(byte_count);
2759 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2760 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2761 cifs_stats_inc(&pTcon->num_t2renames);
2762 if (rc)
2763 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
2765 cifs_buf_release(pSMB);
2767 /* Note: On -EAGAIN error only caller can retry on handle based calls
2768 since file handle passed in no longer valid */
2770 return rc;
2774 CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
2775 const __u16 target_tid, const char *toName, const int flags,
2776 const struct nls_table *nls_codepage, int remap)
2778 int rc = 0;
2779 COPY_REQ *pSMB = NULL;
2780 COPY_RSP *pSMBr = NULL;
2781 int bytes_returned;
2782 int name_len, name_len2;
2783 __u16 count;
2785 cFYI(1, "In CIFSSMBCopy");
2786 copyRetry:
2787 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2788 (void **) &pSMBr);
2789 if (rc)
2790 return rc;
2792 pSMB->BufferFormat = 0x04;
2793 pSMB->Tid2 = target_tid;
2795 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2797 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2798 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2799 fromName, PATH_MAX, nls_codepage,
2800 remap);
2801 name_len++; /* trailing null */
2802 name_len *= 2;
2803 pSMB->OldFileName[name_len] = 0x04; /* pad */
2804 /* protocol requires ASCII signature byte on Unicode string */
2805 pSMB->OldFileName[name_len + 1] = 0x00;
2806 name_len2 =
2807 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2808 toName, PATH_MAX, nls_codepage, remap);
2809 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2810 name_len2 *= 2; /* convert to bytes */
2811 } else { /* BB improve the check for buffer overruns BB */
2812 name_len = strnlen(fromName, PATH_MAX);
2813 name_len++; /* trailing null */
2814 strncpy(pSMB->OldFileName, fromName, name_len);
2815 name_len2 = strnlen(toName, PATH_MAX);
2816 name_len2++; /* trailing null */
2817 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2818 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2819 name_len2++; /* trailing null */
2820 name_len2++; /* signature byte */
2823 count = 1 /* 1st signature byte */ + name_len + name_len2;
2824 inc_rfc1001_len(pSMB, count);
2825 pSMB->ByteCount = cpu_to_le16(count);
2827 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2828 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2829 if (rc) {
2830 cFYI(1, "Send error in copy = %d with %d files copied",
2831 rc, le16_to_cpu(pSMBr->CopyCount));
2833 cifs_buf_release(pSMB);
2835 if (rc == -EAGAIN)
2836 goto copyRetry;
2838 return rc;
2842 CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
2843 const char *fromName, const char *toName,
2844 const struct nls_table *nls_codepage)
2846 TRANSACTION2_SPI_REQ *pSMB = NULL;
2847 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2848 char *data_offset;
2849 int name_len;
2850 int name_len_target;
2851 int rc = 0;
2852 int bytes_returned = 0;
2853 __u16 params, param_offset, offset, byte_count;
2855 cFYI(1, "In Symlink Unix style");
2856 createSymLinkRetry:
2857 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2858 (void **) &pSMBr);
2859 if (rc)
2860 return rc;
2862 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2863 name_len =
2864 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2865 /* find define for this maxpathcomponent */
2866 , nls_codepage);
2867 name_len++; /* trailing null */
2868 name_len *= 2;
2870 } else { /* BB improve the check for buffer overruns BB */
2871 name_len = strnlen(fromName, PATH_MAX);
2872 name_len++; /* trailing null */
2873 strncpy(pSMB->FileName, fromName, name_len);
2875 params = 6 + name_len;
2876 pSMB->MaxSetupCount = 0;
2877 pSMB->Reserved = 0;
2878 pSMB->Flags = 0;
2879 pSMB->Timeout = 0;
2880 pSMB->Reserved2 = 0;
2881 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2882 InformationLevel) - 4;
2883 offset = param_offset + params;
2885 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2886 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2887 name_len_target =
2888 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2889 /* find define for this maxpathcomponent */
2890 , nls_codepage);
2891 name_len_target++; /* trailing null */
2892 name_len_target *= 2;
2893 } else { /* BB improve the check for buffer overruns BB */
2894 name_len_target = strnlen(toName, PATH_MAX);
2895 name_len_target++; /* trailing null */
2896 strncpy(data_offset, toName, name_len_target);
2899 pSMB->MaxParameterCount = cpu_to_le16(2);
2900 /* BB find exact max on data count below from sess */
2901 pSMB->MaxDataCount = cpu_to_le16(1000);
2902 pSMB->SetupCount = 1;
2903 pSMB->Reserved3 = 0;
2904 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2905 byte_count = 3 /* pad */ + params + name_len_target;
2906 pSMB->DataCount = cpu_to_le16(name_len_target);
2907 pSMB->ParameterCount = cpu_to_le16(params);
2908 pSMB->TotalDataCount = pSMB->DataCount;
2909 pSMB->TotalParameterCount = pSMB->ParameterCount;
2910 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2911 pSMB->DataOffset = cpu_to_le16(offset);
2912 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2913 pSMB->Reserved4 = 0;
2914 inc_rfc1001_len(pSMB, byte_count);
2915 pSMB->ByteCount = cpu_to_le16(byte_count);
2916 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2917 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2918 cifs_stats_inc(&tcon->num_symlinks);
2919 if (rc)
2920 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
2922 cifs_buf_release(pSMB);
2924 if (rc == -EAGAIN)
2925 goto createSymLinkRetry;
2927 return rc;
2931 CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
2932 const char *fromName, const char *toName,
2933 const struct nls_table *nls_codepage, int remap)
2935 TRANSACTION2_SPI_REQ *pSMB = NULL;
2936 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2937 char *data_offset;
2938 int name_len;
2939 int name_len_target;
2940 int rc = 0;
2941 int bytes_returned = 0;
2942 __u16 params, param_offset, offset, byte_count;
2944 cFYI(1, "In Create Hard link Unix style");
2945 createHardLinkRetry:
2946 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2947 (void **) &pSMBr);
2948 if (rc)
2949 return rc;
2951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2952 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2953 PATH_MAX, nls_codepage, remap);
2954 name_len++; /* trailing null */
2955 name_len *= 2;
2957 } else { /* BB improve the check for buffer overruns BB */
2958 name_len = strnlen(toName, PATH_MAX);
2959 name_len++; /* trailing null */
2960 strncpy(pSMB->FileName, toName, name_len);
2962 params = 6 + name_len;
2963 pSMB->MaxSetupCount = 0;
2964 pSMB->Reserved = 0;
2965 pSMB->Flags = 0;
2966 pSMB->Timeout = 0;
2967 pSMB->Reserved2 = 0;
2968 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2969 InformationLevel) - 4;
2970 offset = param_offset + params;
2972 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2973 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2974 name_len_target =
2975 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2976 nls_codepage, remap);
2977 name_len_target++; /* trailing null */
2978 name_len_target *= 2;
2979 } else { /* BB improve the check for buffer overruns BB */
2980 name_len_target = strnlen(fromName, PATH_MAX);
2981 name_len_target++; /* trailing null */
2982 strncpy(data_offset, fromName, name_len_target);
2985 pSMB->MaxParameterCount = cpu_to_le16(2);
2986 /* BB find exact max on data count below from sess*/
2987 pSMB->MaxDataCount = cpu_to_le16(1000);
2988 pSMB->SetupCount = 1;
2989 pSMB->Reserved3 = 0;
2990 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2991 byte_count = 3 /* pad */ + params + name_len_target;
2992 pSMB->ParameterCount = cpu_to_le16(params);
2993 pSMB->TotalParameterCount = pSMB->ParameterCount;
2994 pSMB->DataCount = cpu_to_le16(name_len_target);
2995 pSMB->TotalDataCount = pSMB->DataCount;
2996 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2997 pSMB->DataOffset = cpu_to_le16(offset);
2998 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2999 pSMB->Reserved4 = 0;
3000 inc_rfc1001_len(pSMB, byte_count);
3001 pSMB->ByteCount = cpu_to_le16(byte_count);
3002 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3004 cifs_stats_inc(&tcon->num_hardlinks);
3005 if (rc)
3006 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
3008 cifs_buf_release(pSMB);
3009 if (rc == -EAGAIN)
3010 goto createHardLinkRetry;
3012 return rc;
3016 CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
3017 const char *fromName, const char *toName,
3018 const struct nls_table *nls_codepage, int remap)
3020 int rc = 0;
3021 NT_RENAME_REQ *pSMB = NULL;
3022 RENAME_RSP *pSMBr = NULL;
3023 int bytes_returned;
3024 int name_len, name_len2;
3025 __u16 count;
3027 cFYI(1, "In CIFSCreateHardLink");
3028 winCreateHardLinkRetry:
3030 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3031 (void **) &pSMBr);
3032 if (rc)
3033 return rc;
3035 pSMB->SearchAttributes =
3036 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3037 ATTR_DIRECTORY);
3038 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3039 pSMB->ClusterCount = 0;
3041 pSMB->BufferFormat = 0x04;
3043 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3044 name_len =
3045 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
3046 PATH_MAX, nls_codepage, remap);
3047 name_len++; /* trailing null */
3048 name_len *= 2;
3050 /* protocol specifies ASCII buffer format (0x04) for unicode */
3051 pSMB->OldFileName[name_len] = 0x04;
3052 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
3053 name_len2 =
3054 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
3055 toName, PATH_MAX, nls_codepage, remap);
3056 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3057 name_len2 *= 2; /* convert to bytes */
3058 } else { /* BB improve the check for buffer overruns BB */
3059 name_len = strnlen(fromName, PATH_MAX);
3060 name_len++; /* trailing null */
3061 strncpy(pSMB->OldFileName, fromName, name_len);
3062 name_len2 = strnlen(toName, PATH_MAX);
3063 name_len2++; /* trailing null */
3064 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
3065 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
3066 name_len2++; /* trailing null */
3067 name_len2++; /* signature byte */
3070 count = 1 /* string type byte */ + name_len + name_len2;
3071 inc_rfc1001_len(pSMB, count);
3072 pSMB->ByteCount = cpu_to_le16(count);
3074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3075 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3076 cifs_stats_inc(&tcon->num_hardlinks);
3077 if (rc)
3078 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
3080 cifs_buf_release(pSMB);
3081 if (rc == -EAGAIN)
3082 goto winCreateHardLinkRetry;
3084 return rc;
3088 CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
3089 const unsigned char *searchName, char **symlinkinfo,
3090 const struct nls_table *nls_codepage)
3092 /* SMB_QUERY_FILE_UNIX_LINK */
3093 TRANSACTION2_QPI_REQ *pSMB = NULL;
3094 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3095 int rc = 0;
3096 int bytes_returned;
3097 int name_len;
3098 __u16 params, byte_count;
3099 char *data_start;
3101 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
3103 querySymLinkRetry:
3104 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3105 (void **) &pSMBr);
3106 if (rc)
3107 return rc;
3109 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3110 name_len =
3111 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
3112 PATH_MAX, nls_codepage);
3113 name_len++; /* trailing null */
3114 name_len *= 2;
3115 } else { /* BB improve the check for buffer overruns BB */
3116 name_len = strnlen(searchName, PATH_MAX);
3117 name_len++; /* trailing null */
3118 strncpy(pSMB->FileName, searchName, name_len);
3121 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3122 pSMB->TotalDataCount = 0;
3123 pSMB->MaxParameterCount = cpu_to_le16(2);
3124 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3125 pSMB->MaxSetupCount = 0;
3126 pSMB->Reserved = 0;
3127 pSMB->Flags = 0;
3128 pSMB->Timeout = 0;
3129 pSMB->Reserved2 = 0;
3130 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3131 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3132 pSMB->DataCount = 0;
3133 pSMB->DataOffset = 0;
3134 pSMB->SetupCount = 1;
3135 pSMB->Reserved3 = 0;
3136 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3137 byte_count = params + 1 /* pad */ ;
3138 pSMB->TotalParameterCount = cpu_to_le16(params);
3139 pSMB->ParameterCount = pSMB->TotalParameterCount;
3140 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3141 pSMB->Reserved4 = 0;
3142 inc_rfc1001_len(pSMB, byte_count);
3143 pSMB->ByteCount = cpu_to_le16(byte_count);
3145 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3146 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3147 if (rc) {
3148 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
3149 } else {
3150 /* decode response */
3152 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3153 /* BB also check enough total bytes returned */
3154 if (rc || get_bcc(&pSMBr->hdr) < 2)
3155 rc = -EIO;
3156 else {
3157 bool is_unicode;
3158 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3160 data_start = ((char *) &pSMBr->hdr.Protocol) +
3161 le16_to_cpu(pSMBr->t2.DataOffset);
3163 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3164 is_unicode = true;
3165 else
3166 is_unicode = false;
3168 /* BB FIXME investigate remapping reserved chars here */
3169 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
3170 is_unicode, nls_codepage);
3171 if (!*symlinkinfo)
3172 rc = -ENOMEM;
3175 cifs_buf_release(pSMB);
3176 if (rc == -EAGAIN)
3177 goto querySymLinkRetry;
3178 return rc;
3181 #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3183 * Recent Windows versions now create symlinks more frequently
3184 * and they use the "reparse point" mechanism below. We can of course
3185 * do symlinks nicely to Samba and other servers which support the
3186 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3187 * "MF" symlinks optionally, but for recent Windows we really need to
3188 * reenable the code below and fix the cifs_symlink callers to handle this.
3189 * In the interim this code has been moved to its own config option so
3190 * it is not compiled in by default until callers fixed up and more tested.
3193 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
3194 const unsigned char *searchName,
3195 char *symlinkinfo, const int buflen, __u16 fid,
3196 const struct nls_table *nls_codepage)
3198 int rc = 0;
3199 int bytes_returned;
3200 struct smb_com_transaction_ioctl_req *pSMB;
3201 struct smb_com_transaction_ioctl_rsp *pSMBr;
3203 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
3204 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3205 (void **) &pSMBr);
3206 if (rc)
3207 return rc;
3209 pSMB->TotalParameterCount = 0 ;
3210 pSMB->TotalDataCount = 0;
3211 pSMB->MaxParameterCount = cpu_to_le32(2);
3212 /* BB find exact data count max from sess structure BB */
3213 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
3214 pSMB->MaxSetupCount = 4;
3215 pSMB->Reserved = 0;
3216 pSMB->ParameterOffset = 0;
3217 pSMB->DataCount = 0;
3218 pSMB->DataOffset = 0;
3219 pSMB->SetupCount = 4;
3220 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3221 pSMB->ParameterCount = pSMB->TotalParameterCount;
3222 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3223 pSMB->IsFsctl = 1; /* FSCTL */
3224 pSMB->IsRootFlag = 0;
3225 pSMB->Fid = fid; /* file handle always le */
3226 pSMB->ByteCount = 0;
3228 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3229 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3230 if (rc) {
3231 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
3232 } else { /* decode response */
3233 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3234 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
3235 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3236 /* BB also check enough total bytes returned */
3237 rc = -EIO; /* bad smb */
3238 goto qreparse_out;
3240 if (data_count && (data_count < 2048)) {
3241 char *end_of_smb = 2 /* sizeof byte count */ +
3242 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
3244 struct reparse_data *reparse_buf =
3245 (struct reparse_data *)
3246 ((char *)&pSMBr->hdr.Protocol
3247 + data_offset);
3248 if ((char *)reparse_buf >= end_of_smb) {
3249 rc = -EIO;
3250 goto qreparse_out;
3252 if ((reparse_buf->LinkNamesBuf +
3253 reparse_buf->TargetNameOffset +
3254 reparse_buf->TargetNameLen) > end_of_smb) {
3255 cFYI(1, "reparse buf beyond SMB");
3256 rc = -EIO;
3257 goto qreparse_out;
3260 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3261 cifs_from_ucs2(symlinkinfo, (__le16 *)
3262 (reparse_buf->LinkNamesBuf +
3263 reparse_buf->TargetNameOffset),
3264 buflen,
3265 reparse_buf->TargetNameLen,
3266 nls_codepage, 0);
3267 } else { /* ASCII names */
3268 strncpy(symlinkinfo,
3269 reparse_buf->LinkNamesBuf +
3270 reparse_buf->TargetNameOffset,
3271 min_t(const int, buflen,
3272 reparse_buf->TargetNameLen));
3274 } else {
3275 rc = -EIO;
3276 cFYI(1, "Invalid return data count on "
3277 "get reparse info ioctl");
3279 symlinkinfo[buflen] = 0; /* just in case so the caller
3280 does not go off the end of the buffer */
3281 cFYI(1, "readlink result - %s", symlinkinfo);
3284 qreparse_out:
3285 cifs_buf_release(pSMB);
3287 /* Note: On -EAGAIN error only caller can retry on handle based calls
3288 since file handle passed in no longer valid */
3290 return rc;
3292 #endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
3294 #ifdef CONFIG_CIFS_POSIX
3296 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
3297 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3298 struct cifs_posix_ace *cifs_ace)
3300 /* u8 cifs fields do not need le conversion */
3301 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3302 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3303 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
3304 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
3306 return;
3309 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
3310 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3311 const int acl_type, const int size_of_data_area)
3313 int size = 0;
3314 int i;
3315 __u16 count;
3316 struct cifs_posix_ace *pACE;
3317 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3318 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
3320 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3321 return -EOPNOTSUPP;
3323 if (acl_type & ACL_TYPE_ACCESS) {
3324 count = le16_to_cpu(cifs_acl->access_entry_count);
3325 pACE = &cifs_acl->ace_array[0];
3326 size = sizeof(struct cifs_posix_acl);
3327 size += sizeof(struct cifs_posix_ace) * count;
3328 /* check if we would go beyond end of SMB */
3329 if (size_of_data_area < size) {
3330 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3331 size_of_data_area, size);
3332 return -EINVAL;
3334 } else if (acl_type & ACL_TYPE_DEFAULT) {
3335 count = le16_to_cpu(cifs_acl->access_entry_count);
3336 size = sizeof(struct cifs_posix_acl);
3337 size += sizeof(struct cifs_posix_ace) * count;
3338 /* skip past access ACEs to get to default ACEs */
3339 pACE = &cifs_acl->ace_array[count];
3340 count = le16_to_cpu(cifs_acl->default_entry_count);
3341 size += sizeof(struct cifs_posix_ace) * count;
3342 /* check if we would go beyond end of SMB */
3343 if (size_of_data_area < size)
3344 return -EINVAL;
3345 } else {
3346 /* illegal type */
3347 return -EINVAL;
3350 size = posix_acl_xattr_size(count);
3351 if ((buflen == 0) || (local_acl == NULL)) {
3352 /* used to query ACL EA size */
3353 } else if (size > buflen) {
3354 return -ERANGE;
3355 } else /* buffer big enough */ {
3356 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
3357 for (i = 0; i < count ; i++) {
3358 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3359 pACE++;
3362 return size;
3365 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3366 const posix_acl_xattr_entry *local_ace)
3368 __u16 rc = 0; /* 0 = ACL converted ok */
3370 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3371 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
3372 /* BB is there a better way to handle the large uid? */
3373 if (local_ace->e_id == cpu_to_le32(-1)) {
3374 /* Probably no need to le convert -1 on any arch but can not hurt */
3375 cifs_ace->cifs_uid = cpu_to_le64(-1);
3376 } else
3377 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
3378 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
3379 return rc;
3382 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
3383 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3384 const int buflen, const int acl_type)
3386 __u16 rc = 0;
3387 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3388 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
3389 int count;
3390 int i;
3392 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
3393 return 0;
3395 count = posix_acl_xattr_count((size_t)buflen);
3396 cFYI(1, "setting acl with %d entries from buf of length %d and "
3397 "version of %d",
3398 count, buflen, le32_to_cpu(local_acl->a_version));
3399 if (le32_to_cpu(local_acl->a_version) != 2) {
3400 cFYI(1, "unknown POSIX ACL version %d",
3401 le32_to_cpu(local_acl->a_version));
3402 return 0;
3404 cifs_acl->version = cpu_to_le16(1);
3405 if (acl_type == ACL_TYPE_ACCESS)
3406 cifs_acl->access_entry_count = cpu_to_le16(count);
3407 else if (acl_type == ACL_TYPE_DEFAULT)
3408 cifs_acl->default_entry_count = cpu_to_le16(count);
3409 else {
3410 cFYI(1, "unknown ACL type %d", acl_type);
3411 return 0;
3413 for (i = 0; i < count; i++) {
3414 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3415 &local_acl->a_entries[i]);
3416 if (rc != 0) {
3417 /* ACE not converted */
3418 break;
3421 if (rc == 0) {
3422 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3423 rc += sizeof(struct cifs_posix_acl);
3424 /* BB add check to make sure ACL does not overflow SMB */
3426 return rc;
3430 CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
3431 const unsigned char *searchName,
3432 char *acl_inf, const int buflen, const int acl_type,
3433 const struct nls_table *nls_codepage, int remap)
3435 /* SMB_QUERY_POSIX_ACL */
3436 TRANSACTION2_QPI_REQ *pSMB = NULL;
3437 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3438 int rc = 0;
3439 int bytes_returned;
3440 int name_len;
3441 __u16 params, byte_count;
3443 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
3445 queryAclRetry:
3446 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3447 (void **) &pSMBr);
3448 if (rc)
3449 return rc;
3451 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3452 name_len =
3453 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3454 PATH_MAX, nls_codepage, remap);
3455 name_len++; /* trailing null */
3456 name_len *= 2;
3457 pSMB->FileName[name_len] = 0;
3458 pSMB->FileName[name_len+1] = 0;
3459 } else { /* BB improve the check for buffer overruns BB */
3460 name_len = strnlen(searchName, PATH_MAX);
3461 name_len++; /* trailing null */
3462 strncpy(pSMB->FileName, searchName, name_len);
3465 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3466 pSMB->TotalDataCount = 0;
3467 pSMB->MaxParameterCount = cpu_to_le16(2);
3468 /* BB find exact max data count below from sess structure BB */
3469 pSMB->MaxDataCount = cpu_to_le16(4000);
3470 pSMB->MaxSetupCount = 0;
3471 pSMB->Reserved = 0;
3472 pSMB->Flags = 0;
3473 pSMB->Timeout = 0;
3474 pSMB->Reserved2 = 0;
3475 pSMB->ParameterOffset = cpu_to_le16(
3476 offsetof(struct smb_com_transaction2_qpi_req,
3477 InformationLevel) - 4);
3478 pSMB->DataCount = 0;
3479 pSMB->DataOffset = 0;
3480 pSMB->SetupCount = 1;
3481 pSMB->Reserved3 = 0;
3482 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3483 byte_count = params + 1 /* pad */ ;
3484 pSMB->TotalParameterCount = cpu_to_le16(params);
3485 pSMB->ParameterCount = pSMB->TotalParameterCount;
3486 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3487 pSMB->Reserved4 = 0;
3488 inc_rfc1001_len(pSMB, byte_count);
3489 pSMB->ByteCount = cpu_to_le16(byte_count);
3491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3492 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3493 cifs_stats_inc(&tcon->num_acl_get);
3494 if (rc) {
3495 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
3496 } else {
3497 /* decode response */
3499 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3500 /* BB also check enough total bytes returned */
3501 if (rc || get_bcc(&pSMBr->hdr) < 2)
3502 rc = -EIO; /* bad smb */
3503 else {
3504 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3505 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3506 rc = cifs_copy_posix_acl(acl_inf,
3507 (char *)&pSMBr->hdr.Protocol+data_offset,
3508 buflen, acl_type, count);
3511 cifs_buf_release(pSMB);
3512 if (rc == -EAGAIN)
3513 goto queryAclRetry;
3514 return rc;
3518 CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
3519 const unsigned char *fileName,
3520 const char *local_acl, const int buflen,
3521 const int acl_type,
3522 const struct nls_table *nls_codepage, int remap)
3524 struct smb_com_transaction2_spi_req *pSMB = NULL;
3525 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3526 char *parm_data;
3527 int name_len;
3528 int rc = 0;
3529 int bytes_returned = 0;
3530 __u16 params, byte_count, data_count, param_offset, offset;
3532 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
3533 setAclRetry:
3534 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3535 (void **) &pSMBr);
3536 if (rc)
3537 return rc;
3538 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3539 name_len =
3540 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3541 PATH_MAX, nls_codepage, remap);
3542 name_len++; /* trailing null */
3543 name_len *= 2;
3544 } else { /* BB improve the check for buffer overruns BB */
3545 name_len = strnlen(fileName, PATH_MAX);
3546 name_len++; /* trailing null */
3547 strncpy(pSMB->FileName, fileName, name_len);
3549 params = 6 + name_len;
3550 pSMB->MaxParameterCount = cpu_to_le16(2);
3551 /* BB find max SMB size from sess */
3552 pSMB->MaxDataCount = cpu_to_le16(1000);
3553 pSMB->MaxSetupCount = 0;
3554 pSMB->Reserved = 0;
3555 pSMB->Flags = 0;
3556 pSMB->Timeout = 0;
3557 pSMB->Reserved2 = 0;
3558 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3559 InformationLevel) - 4;
3560 offset = param_offset + params;
3561 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3562 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3564 /* convert to on the wire format for POSIX ACL */
3565 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
3567 if (data_count == 0) {
3568 rc = -EOPNOTSUPP;
3569 goto setACLerrorExit;
3571 pSMB->DataOffset = cpu_to_le16(offset);
3572 pSMB->SetupCount = 1;
3573 pSMB->Reserved3 = 0;
3574 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3575 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3576 byte_count = 3 /* pad */ + params + data_count;
3577 pSMB->DataCount = cpu_to_le16(data_count);
3578 pSMB->TotalDataCount = pSMB->DataCount;
3579 pSMB->ParameterCount = cpu_to_le16(params);
3580 pSMB->TotalParameterCount = pSMB->ParameterCount;
3581 pSMB->Reserved4 = 0;
3582 inc_rfc1001_len(pSMB, byte_count);
3583 pSMB->ByteCount = cpu_to_le16(byte_count);
3584 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3585 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3586 if (rc)
3587 cFYI(1, "Set POSIX ACL returned %d", rc);
3589 setACLerrorExit:
3590 cifs_buf_release(pSMB);
3591 if (rc == -EAGAIN)
3592 goto setAclRetry;
3593 return rc;
3596 /* BB fix tabs in this function FIXME BB */
3598 CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
3599 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
3601 int rc = 0;
3602 struct smb_t2_qfi_req *pSMB = NULL;
3603 struct smb_t2_qfi_rsp *pSMBr = NULL;
3604 int bytes_returned;
3605 __u16 params, byte_count;
3607 cFYI(1, "In GetExtAttr");
3608 if (tcon == NULL)
3609 return -ENODEV;
3611 GetExtAttrRetry:
3612 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3613 (void **) &pSMBr);
3614 if (rc)
3615 return rc;
3617 params = 2 /* level */ + 2 /* fid */;
3618 pSMB->t2.TotalDataCount = 0;
3619 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3620 /* BB find exact max data count below from sess structure BB */
3621 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3622 pSMB->t2.MaxSetupCount = 0;
3623 pSMB->t2.Reserved = 0;
3624 pSMB->t2.Flags = 0;
3625 pSMB->t2.Timeout = 0;
3626 pSMB->t2.Reserved2 = 0;
3627 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3628 Fid) - 4);
3629 pSMB->t2.DataCount = 0;
3630 pSMB->t2.DataOffset = 0;
3631 pSMB->t2.SetupCount = 1;
3632 pSMB->t2.Reserved3 = 0;
3633 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3634 byte_count = params + 1 /* pad */ ;
3635 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3636 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3637 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3638 pSMB->Pad = 0;
3639 pSMB->Fid = netfid;
3640 inc_rfc1001_len(pSMB, byte_count);
3641 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3643 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3644 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3645 if (rc) {
3646 cFYI(1, "error %d in GetExtAttr", rc);
3647 } else {
3648 /* decode response */
3649 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3650 /* BB also check enough total bytes returned */
3651 if (rc || get_bcc(&pSMBr->hdr) < 2)
3652 /* If rc should we check for EOPNOSUPP and
3653 disable the srvino flag? or in caller? */
3654 rc = -EIO; /* bad smb */
3655 else {
3656 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3657 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3658 struct file_chattr_info *pfinfo;
3659 /* BB Do we need a cast or hash here ? */
3660 if (count != 16) {
3661 cFYI(1, "Illegal size ret in GetExtAttr");
3662 rc = -EIO;
3663 goto GetExtAttrOut;
3665 pfinfo = (struct file_chattr_info *)
3666 (data_offset + (char *) &pSMBr->hdr.Protocol);
3667 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3668 *pMask = le64_to_cpu(pfinfo->mask);
3671 GetExtAttrOut:
3672 cifs_buf_release(pSMB);
3673 if (rc == -EAGAIN)
3674 goto GetExtAttrRetry;
3675 return rc;
3678 #endif /* CONFIG_POSIX */
3680 #ifdef CONFIG_CIFS_ACL
3682 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3683 * all NT TRANSACTS that we init here have total parm and data under about 400
3684 * bytes (to fit in small cifs buffer size), which is the case so far, it
3685 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3686 * returned setup area) and MaxParameterCount (returned parms size) must be set
3687 * by caller
3689 static int
3690 smb_init_nttransact(const __u16 sub_command, const int setup_count,
3691 const int parm_len, struct cifs_tcon *tcon,
3692 void **ret_buf)
3694 int rc;
3695 __u32 temp_offset;
3696 struct smb_com_ntransact_req *pSMB;
3698 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3699 (void **)&pSMB);
3700 if (rc)
3701 return rc;
3702 *ret_buf = (void *)pSMB;
3703 pSMB->Reserved = 0;
3704 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3705 pSMB->TotalDataCount = 0;
3706 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
3707 pSMB->ParameterCount = pSMB->TotalParameterCount;
3708 pSMB->DataCount = pSMB->TotalDataCount;
3709 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3710 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3711 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3712 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3713 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3714 pSMB->SubCommand = cpu_to_le16(sub_command);
3715 return 0;
3718 static int
3719 validate_ntransact(char *buf, char **ppparm, char **ppdata,
3720 __u32 *pparmlen, __u32 *pdatalen)
3722 char *end_of_smb;
3723 __u32 data_count, data_offset, parm_count, parm_offset;
3724 struct smb_com_ntransact_rsp *pSMBr;
3725 u16 bcc;
3727 *pdatalen = 0;
3728 *pparmlen = 0;
3730 if (buf == NULL)
3731 return -EINVAL;
3733 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3735 bcc = get_bcc(&pSMBr->hdr);
3736 end_of_smb = 2 /* sizeof byte count */ + bcc +
3737 (char *)&pSMBr->ByteCount;
3739 data_offset = le32_to_cpu(pSMBr->DataOffset);
3740 data_count = le32_to_cpu(pSMBr->DataCount);
3741 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3742 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3744 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3745 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3747 /* should we also check that parm and data areas do not overlap? */
3748 if (*ppparm > end_of_smb) {
3749 cFYI(1, "parms start after end of smb");
3750 return -EINVAL;
3751 } else if (parm_count + *ppparm > end_of_smb) {
3752 cFYI(1, "parm end after end of smb");
3753 return -EINVAL;
3754 } else if (*ppdata > end_of_smb) {
3755 cFYI(1, "data starts after end of smb");
3756 return -EINVAL;
3757 } else if (data_count + *ppdata > end_of_smb) {
3758 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3759 *ppdata, data_count, (data_count + *ppdata),
3760 end_of_smb, pSMBr);
3761 return -EINVAL;
3762 } else if (parm_count + data_count > bcc) {
3763 cFYI(1, "parm count and data count larger than SMB");
3764 return -EINVAL;
3766 *pdatalen = data_count;
3767 *pparmlen = parm_count;
3768 return 0;
3771 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3773 CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
3774 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3776 int rc = 0;
3777 int buf_type = 0;
3778 QUERY_SEC_DESC_REQ *pSMB;
3779 struct kvec iov[1];
3781 cFYI(1, "GetCifsACL");
3783 *pbuflen = 0;
3784 *acl_inf = NULL;
3786 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3787 8 /* parm len */, tcon, (void **) &pSMB);
3788 if (rc)
3789 return rc;
3791 pSMB->MaxParameterCount = cpu_to_le32(4);
3792 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3793 pSMB->MaxSetupCount = 0;
3794 pSMB->Fid = fid; /* file handle always le */
3795 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3796 CIFS_ACL_DACL);
3797 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3798 inc_rfc1001_len(pSMB, 11);
3799 iov[0].iov_base = (char *)pSMB;
3800 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
3802 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3804 cifs_stats_inc(&tcon->num_acl_get);
3805 if (rc) {
3806 cFYI(1, "Send error in QuerySecDesc = %d", rc);
3807 } else { /* decode response */
3808 __le32 *parm;
3809 __u32 parm_len;
3810 __u32 acl_len;
3811 struct smb_com_ntransact_rsp *pSMBr;
3812 char *pdata;
3814 /* validate_nttransact */
3815 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3816 &pdata, &parm_len, pbuflen);
3817 if (rc)
3818 goto qsec_out;
3819 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3821 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
3823 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3824 rc = -EIO; /* bad smb */
3825 *pbuflen = 0;
3826 goto qsec_out;
3829 /* BB check that data area is minimum length and as big as acl_len */
3831 acl_len = le32_to_cpu(*parm);
3832 if (acl_len != *pbuflen) {
3833 cERROR(1, "acl length %d does not match %d",
3834 acl_len, *pbuflen);
3835 if (*pbuflen > acl_len)
3836 *pbuflen = acl_len;
3839 /* check if buffer is big enough for the acl
3840 header followed by the smallest SID */
3841 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3842 (*pbuflen >= 64 * 1024)) {
3843 cERROR(1, "bad acl length %d", *pbuflen);
3844 rc = -EINVAL;
3845 *pbuflen = 0;
3846 } else {
3847 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3848 if (*acl_inf == NULL) {
3849 *pbuflen = 0;
3850 rc = -ENOMEM;
3852 memcpy(*acl_inf, pdata, *pbuflen);
3855 qsec_out:
3856 if (buf_type == CIFS_SMALL_BUFFER)
3857 cifs_small_buf_release(iov[0].iov_base);
3858 else if (buf_type == CIFS_LARGE_BUFFER)
3859 cifs_buf_release(iov[0].iov_base);
3860 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3861 return rc;
3865 CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
3866 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
3868 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3869 int rc = 0;
3870 int bytes_returned = 0;
3871 SET_SEC_DESC_REQ *pSMB = NULL;
3872 NTRANSACT_RSP *pSMBr = NULL;
3874 setCifsAclRetry:
3875 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3876 (void **) &pSMBr);
3877 if (rc)
3878 return (rc);
3880 pSMB->MaxSetupCount = 0;
3881 pSMB->Reserved = 0;
3883 param_count = 8;
3884 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3885 data_count = acllen;
3886 data_offset = param_offset + param_count;
3887 byte_count = 3 /* pad */ + param_count;
3889 pSMB->DataCount = cpu_to_le32(data_count);
3890 pSMB->TotalDataCount = pSMB->DataCount;
3891 pSMB->MaxParameterCount = cpu_to_le32(4);
3892 pSMB->MaxDataCount = cpu_to_le32(16384);
3893 pSMB->ParameterCount = cpu_to_le32(param_count);
3894 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3895 pSMB->TotalParameterCount = pSMB->ParameterCount;
3896 pSMB->DataOffset = cpu_to_le32(data_offset);
3897 pSMB->SetupCount = 0;
3898 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3899 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3901 pSMB->Fid = fid; /* file handle always le */
3902 pSMB->Reserved2 = 0;
3903 pSMB->AclFlags = cpu_to_le32(aclflag);
3905 if (pntsd && acllen) {
3906 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3907 (char *) pntsd,
3908 acllen);
3909 inc_rfc1001_len(pSMB, byte_count + data_count);
3910 } else
3911 inc_rfc1001_len(pSMB, byte_count);
3913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3916 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
3917 if (rc)
3918 cFYI(1, "Set CIFS ACL returned %d", rc);
3919 cifs_buf_release(pSMB);
3921 if (rc == -EAGAIN)
3922 goto setCifsAclRetry;
3924 return (rc);
3927 #endif /* CONFIG_CIFS_ACL */
3929 /* Legacy Query Path Information call for lookup to old servers such
3930 as Win9x/WinME */
3931 int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
3932 const unsigned char *searchName,
3933 FILE_ALL_INFO *pFinfo,
3934 const struct nls_table *nls_codepage, int remap)
3936 QUERY_INFORMATION_REQ *pSMB;
3937 QUERY_INFORMATION_RSP *pSMBr;
3938 int rc = 0;
3939 int bytes_returned;
3940 int name_len;
3942 cFYI(1, "In SMBQPath path %s", searchName);
3943 QInfRetry:
3944 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3945 (void **) &pSMBr);
3946 if (rc)
3947 return rc;
3949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3950 name_len =
3951 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3952 PATH_MAX, nls_codepage, remap);
3953 name_len++; /* trailing null */
3954 name_len *= 2;
3955 } else {
3956 name_len = strnlen(searchName, PATH_MAX);
3957 name_len++; /* trailing null */
3958 strncpy(pSMB->FileName, searchName, name_len);
3960 pSMB->BufferFormat = 0x04;
3961 name_len++; /* account for buffer type byte */
3962 inc_rfc1001_len(pSMB, (__u16)name_len);
3963 pSMB->ByteCount = cpu_to_le16(name_len);
3965 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3967 if (rc) {
3968 cFYI(1, "Send error in QueryInfo = %d", rc);
3969 } else if (pFinfo) {
3970 struct timespec ts;
3971 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3973 /* decode response */
3974 /* BB FIXME - add time zone adjustment BB */
3975 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3976 ts.tv_nsec = 0;
3977 ts.tv_sec = time;
3978 /* decode time fields */
3979 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3980 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3981 pFinfo->LastAccessTime = 0;
3982 pFinfo->AllocationSize =
3983 cpu_to_le64(le32_to_cpu(pSMBr->size));
3984 pFinfo->EndOfFile = pFinfo->AllocationSize;
3985 pFinfo->Attributes =
3986 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3987 } else
3988 rc = -EIO; /* bad buffer passed in */
3990 cifs_buf_release(pSMB);
3992 if (rc == -EAGAIN)
3993 goto QInfRetry;
3995 return rc;
3999 CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
4000 u16 netfid, FILE_ALL_INFO *pFindData)
4002 struct smb_t2_qfi_req *pSMB = NULL;
4003 struct smb_t2_qfi_rsp *pSMBr = NULL;
4004 int rc = 0;
4005 int bytes_returned;
4006 __u16 params, byte_count;
4008 QFileInfoRetry:
4009 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4010 (void **) &pSMBr);
4011 if (rc)
4012 return rc;
4014 params = 2 /* level */ + 2 /* fid */;
4015 pSMB->t2.TotalDataCount = 0;
4016 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4017 /* BB find exact max data count below from sess structure BB */
4018 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4019 pSMB->t2.MaxSetupCount = 0;
4020 pSMB->t2.Reserved = 0;
4021 pSMB->t2.Flags = 0;
4022 pSMB->t2.Timeout = 0;
4023 pSMB->t2.Reserved2 = 0;
4024 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4025 Fid) - 4);
4026 pSMB->t2.DataCount = 0;
4027 pSMB->t2.DataOffset = 0;
4028 pSMB->t2.SetupCount = 1;
4029 pSMB->t2.Reserved3 = 0;
4030 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4031 byte_count = params + 1 /* pad */ ;
4032 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4033 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4034 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4035 pSMB->Pad = 0;
4036 pSMB->Fid = netfid;
4037 inc_rfc1001_len(pSMB, byte_count);
4039 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4040 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4041 if (rc) {
4042 cFYI(1, "Send error in QPathInfo = %d", rc);
4043 } else { /* decode response */
4044 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4046 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4047 rc = -EIO;
4048 else if (get_bcc(&pSMBr->hdr) < 40)
4049 rc = -EIO; /* bad smb */
4050 else if (pFindData) {
4051 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4052 memcpy((char *) pFindData,
4053 (char *) &pSMBr->hdr.Protocol +
4054 data_offset, sizeof(FILE_ALL_INFO));
4055 } else
4056 rc = -ENOMEM;
4058 cifs_buf_release(pSMB);
4059 if (rc == -EAGAIN)
4060 goto QFileInfoRetry;
4062 return rc;
4066 CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
4067 const unsigned char *searchName,
4068 FILE_ALL_INFO *pFindData,
4069 int legacy /* old style infolevel */,
4070 const struct nls_table *nls_codepage, int remap)
4072 /* level 263 SMB_QUERY_FILE_ALL_INFO */
4073 TRANSACTION2_QPI_REQ *pSMB = NULL;
4074 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4075 int rc = 0;
4076 int bytes_returned;
4077 int name_len;
4078 __u16 params, byte_count;
4080 /* cFYI(1, "In QPathInfo path %s", searchName); */
4081 QPathInfoRetry:
4082 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4083 (void **) &pSMBr);
4084 if (rc)
4085 return rc;
4087 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4088 name_len =
4089 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4090 PATH_MAX, nls_codepage, remap);
4091 name_len++; /* trailing null */
4092 name_len *= 2;
4093 } else { /* BB improve the check for buffer overruns BB */
4094 name_len = strnlen(searchName, PATH_MAX);
4095 name_len++; /* trailing null */
4096 strncpy(pSMB->FileName, searchName, name_len);
4099 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
4100 pSMB->TotalDataCount = 0;
4101 pSMB->MaxParameterCount = cpu_to_le16(2);
4102 /* BB find exact max SMB PDU from sess structure BB */
4103 pSMB->MaxDataCount = cpu_to_le16(4000);
4104 pSMB->MaxSetupCount = 0;
4105 pSMB->Reserved = 0;
4106 pSMB->Flags = 0;
4107 pSMB->Timeout = 0;
4108 pSMB->Reserved2 = 0;
4109 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4110 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4111 pSMB->DataCount = 0;
4112 pSMB->DataOffset = 0;
4113 pSMB->SetupCount = 1;
4114 pSMB->Reserved3 = 0;
4115 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4116 byte_count = params + 1 /* pad */ ;
4117 pSMB->TotalParameterCount = cpu_to_le16(params);
4118 pSMB->ParameterCount = pSMB->TotalParameterCount;
4119 if (legacy)
4120 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4121 else
4122 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4123 pSMB->Reserved4 = 0;
4124 inc_rfc1001_len(pSMB, byte_count);
4125 pSMB->ByteCount = cpu_to_le16(byte_count);
4127 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4129 if (rc) {
4130 cFYI(1, "Send error in QPathInfo = %d", rc);
4131 } else { /* decode response */
4132 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4134 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4135 rc = -EIO;
4136 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
4137 rc = -EIO; /* bad smb */
4138 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
4139 rc = -EIO; /* 24 or 26 expected but we do not read
4140 last field */
4141 else if (pFindData) {
4142 int size;
4143 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4145 /* On legacy responses we do not read the last field,
4146 EAsize, fortunately since it varies by subdialect and
4147 also note it differs on Set vs. Get, ie two bytes or 4
4148 bytes depending but we don't care here */
4149 if (legacy)
4150 size = sizeof(FILE_INFO_STANDARD);
4151 else
4152 size = sizeof(FILE_ALL_INFO);
4153 memcpy((char *) pFindData,
4154 (char *) &pSMBr->hdr.Protocol +
4155 data_offset, size);
4156 } else
4157 rc = -ENOMEM;
4159 cifs_buf_release(pSMB);
4160 if (rc == -EAGAIN)
4161 goto QPathInfoRetry;
4163 return rc;
4167 CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
4168 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4170 struct smb_t2_qfi_req *pSMB = NULL;
4171 struct smb_t2_qfi_rsp *pSMBr = NULL;
4172 int rc = 0;
4173 int bytes_returned;
4174 __u16 params, byte_count;
4176 UnixQFileInfoRetry:
4177 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4178 (void **) &pSMBr);
4179 if (rc)
4180 return rc;
4182 params = 2 /* level */ + 2 /* fid */;
4183 pSMB->t2.TotalDataCount = 0;
4184 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4185 /* BB find exact max data count below from sess structure BB */
4186 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4187 pSMB->t2.MaxSetupCount = 0;
4188 pSMB->t2.Reserved = 0;
4189 pSMB->t2.Flags = 0;
4190 pSMB->t2.Timeout = 0;
4191 pSMB->t2.Reserved2 = 0;
4192 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4193 Fid) - 4);
4194 pSMB->t2.DataCount = 0;
4195 pSMB->t2.DataOffset = 0;
4196 pSMB->t2.SetupCount = 1;
4197 pSMB->t2.Reserved3 = 0;
4198 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4199 byte_count = params + 1 /* pad */ ;
4200 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4201 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4202 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4203 pSMB->Pad = 0;
4204 pSMB->Fid = netfid;
4205 inc_rfc1001_len(pSMB, byte_count);
4207 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4208 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4209 if (rc) {
4210 cFYI(1, "Send error in QPathInfo = %d", rc);
4211 } else { /* decode response */
4212 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4214 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4215 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
4216 "Unix Extensions can be disabled on mount "
4217 "by specifying the nosfu mount option.");
4218 rc = -EIO; /* bad smb */
4219 } else {
4220 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4221 memcpy((char *) pFindData,
4222 (char *) &pSMBr->hdr.Protocol +
4223 data_offset,
4224 sizeof(FILE_UNIX_BASIC_INFO));
4228 cifs_buf_release(pSMB);
4229 if (rc == -EAGAIN)
4230 goto UnixQFileInfoRetry;
4232 return rc;
4236 CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
4237 const unsigned char *searchName,
4238 FILE_UNIX_BASIC_INFO *pFindData,
4239 const struct nls_table *nls_codepage, int remap)
4241 /* SMB_QUERY_FILE_UNIX_BASIC */
4242 TRANSACTION2_QPI_REQ *pSMB = NULL;
4243 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4244 int rc = 0;
4245 int bytes_returned = 0;
4246 int name_len;
4247 __u16 params, byte_count;
4249 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
4250 UnixQPathInfoRetry:
4251 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4252 (void **) &pSMBr);
4253 if (rc)
4254 return rc;
4256 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4257 name_len =
4258 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4259 PATH_MAX, nls_codepage, remap);
4260 name_len++; /* trailing null */
4261 name_len *= 2;
4262 } else { /* BB improve the check for buffer overruns BB */
4263 name_len = strnlen(searchName, PATH_MAX);
4264 name_len++; /* trailing null */
4265 strncpy(pSMB->FileName, searchName, name_len);
4268 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
4269 pSMB->TotalDataCount = 0;
4270 pSMB->MaxParameterCount = cpu_to_le16(2);
4271 /* BB find exact max SMB PDU from sess structure BB */
4272 pSMB->MaxDataCount = cpu_to_le16(4000);
4273 pSMB->MaxSetupCount = 0;
4274 pSMB->Reserved = 0;
4275 pSMB->Flags = 0;
4276 pSMB->Timeout = 0;
4277 pSMB->Reserved2 = 0;
4278 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4279 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4280 pSMB->DataCount = 0;
4281 pSMB->DataOffset = 0;
4282 pSMB->SetupCount = 1;
4283 pSMB->Reserved3 = 0;
4284 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4285 byte_count = params + 1 /* pad */ ;
4286 pSMB->TotalParameterCount = cpu_to_le16(params);
4287 pSMB->ParameterCount = pSMB->TotalParameterCount;
4288 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4289 pSMB->Reserved4 = 0;
4290 inc_rfc1001_len(pSMB, byte_count);
4291 pSMB->ByteCount = cpu_to_le16(byte_count);
4293 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4294 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4295 if (rc) {
4296 cFYI(1, "Send error in QPathInfo = %d", rc);
4297 } else { /* decode response */
4298 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4300 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4301 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
4302 "Unix Extensions can be disabled on mount "
4303 "by specifying the nosfu mount option.");
4304 rc = -EIO; /* bad smb */
4305 } else {
4306 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4307 memcpy((char *) pFindData,
4308 (char *) &pSMBr->hdr.Protocol +
4309 data_offset,
4310 sizeof(FILE_UNIX_BASIC_INFO));
4313 cifs_buf_release(pSMB);
4314 if (rc == -EAGAIN)
4315 goto UnixQPathInfoRetry;
4317 return rc;
4320 /* xid, tcon, searchName and codepage are input parms, rest are returned */
4322 CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
4323 const char *searchName,
4324 const struct nls_table *nls_codepage,
4325 __u16 *pnetfid,
4326 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
4328 /* level 257 SMB_ */
4329 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4330 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
4331 T2_FFIRST_RSP_PARMS *parms;
4332 int rc = 0;
4333 int bytes_returned = 0;
4334 int name_len;
4335 __u16 params, byte_count;
4337 cFYI(1, "In FindFirst for %s", searchName);
4339 findFirstRetry:
4340 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4341 (void **) &pSMBr);
4342 if (rc)
4343 return rc;
4345 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4346 name_len =
4347 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4348 PATH_MAX, nls_codepage, remap);
4349 /* We can not add the asterik earlier in case
4350 it got remapped to 0xF03A as if it were part of the
4351 directory name instead of a wildcard */
4352 name_len *= 2;
4353 pSMB->FileName[name_len] = dirsep;
4354 pSMB->FileName[name_len+1] = 0;
4355 pSMB->FileName[name_len+2] = '*';
4356 pSMB->FileName[name_len+3] = 0;
4357 name_len += 4; /* now the trailing null */
4358 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4359 pSMB->FileName[name_len+1] = 0;
4360 name_len += 2;
4361 } else { /* BB add check for overrun of SMB buf BB */
4362 name_len = strnlen(searchName, PATH_MAX);
4363 /* BB fix here and in unicode clause above ie
4364 if (name_len > buffersize-header)
4365 free buffer exit; BB */
4366 strncpy(pSMB->FileName, searchName, name_len);
4367 pSMB->FileName[name_len] = dirsep;
4368 pSMB->FileName[name_len+1] = '*';
4369 pSMB->FileName[name_len+2] = 0;
4370 name_len += 3;
4373 params = 12 + name_len /* includes null */ ;
4374 pSMB->TotalDataCount = 0; /* no EAs */
4375 pSMB->MaxParameterCount = cpu_to_le16(10);
4376 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
4377 pSMB->MaxSetupCount = 0;
4378 pSMB->Reserved = 0;
4379 pSMB->Flags = 0;
4380 pSMB->Timeout = 0;
4381 pSMB->Reserved2 = 0;
4382 byte_count = params + 1 /* pad */ ;
4383 pSMB->TotalParameterCount = cpu_to_le16(params);
4384 pSMB->ParameterCount = pSMB->TotalParameterCount;
4385 pSMB->ParameterOffset = cpu_to_le16(
4386 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4387 - 4);
4388 pSMB->DataCount = 0;
4389 pSMB->DataOffset = 0;
4390 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4391 pSMB->Reserved3 = 0;
4392 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4393 pSMB->SearchAttributes =
4394 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4395 ATTR_DIRECTORY);
4396 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4397 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
4398 CIFS_SEARCH_RETURN_RESUME);
4399 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4401 /* BB what should we set StorageType to? Does it matter? BB */
4402 pSMB->SearchStorageType = 0;
4403 inc_rfc1001_len(pSMB, byte_count);
4404 pSMB->ByteCount = cpu_to_le16(byte_count);
4406 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4408 cifs_stats_inc(&tcon->num_ffirst);
4410 if (rc) {/* BB add logic to retry regular search if Unix search
4411 rejected unexpectedly by server */
4412 /* BB Add code to handle unsupported level rc */
4413 cFYI(1, "Error in FindFirst = %d", rc);
4415 cifs_buf_release(pSMB);
4417 /* BB eventually could optimize out free and realloc of buf */
4418 /* for this case */
4419 if (rc == -EAGAIN)
4420 goto findFirstRetry;
4421 } else { /* decode response */
4422 /* BB remember to free buffer if error BB */
4423 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4424 if (rc == 0) {
4425 unsigned int lnoff;
4427 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4428 psrch_inf->unicode = true;
4429 else
4430 psrch_inf->unicode = false;
4432 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
4433 psrch_inf->smallBuf = 0;
4434 psrch_inf->srch_entries_start =
4435 (char *) &pSMBr->hdr.Protocol +
4436 le16_to_cpu(pSMBr->t2.DataOffset);
4437 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4438 le16_to_cpu(pSMBr->t2.ParameterOffset));
4440 if (parms->EndofSearch)
4441 psrch_inf->endOfSearch = true;
4442 else
4443 psrch_inf->endOfSearch = false;
4445 psrch_inf->entries_in_buffer =
4446 le16_to_cpu(parms->SearchCount);
4447 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
4448 psrch_inf->entries_in_buffer;
4449 lnoff = le16_to_cpu(parms->LastNameOffset);
4450 if (CIFSMaxBufSize < lnoff) {
4451 cERROR(1, "ignoring corrupt resume name");
4452 psrch_inf->last_entry = NULL;
4453 return rc;
4456 psrch_inf->last_entry = psrch_inf->srch_entries_start +
4457 lnoff;
4459 *pnetfid = parms->SearchHandle;
4460 } else {
4461 cifs_buf_release(pSMB);
4465 return rc;
4468 int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
4469 __u16 searchHandle, struct cifs_search_info *psrch_inf)
4471 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4472 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
4473 T2_FNEXT_RSP_PARMS *parms;
4474 char *response_data;
4475 int rc = 0;
4476 int bytes_returned;
4477 unsigned int name_len;
4478 __u16 params, byte_count;
4480 cFYI(1, "In FindNext");
4482 if (psrch_inf->endOfSearch)
4483 return -ENOENT;
4485 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4486 (void **) &pSMBr);
4487 if (rc)
4488 return rc;
4490 params = 14; /* includes 2 bytes of null string, converted to LE below*/
4491 byte_count = 0;
4492 pSMB->TotalDataCount = 0; /* no EAs */
4493 pSMB->MaxParameterCount = cpu_to_le16(8);
4494 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
4495 pSMB->MaxSetupCount = 0;
4496 pSMB->Reserved = 0;
4497 pSMB->Flags = 0;
4498 pSMB->Timeout = 0;
4499 pSMB->Reserved2 = 0;
4500 pSMB->ParameterOffset = cpu_to_le16(
4501 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4502 pSMB->DataCount = 0;
4503 pSMB->DataOffset = 0;
4504 pSMB->SetupCount = 1;
4505 pSMB->Reserved3 = 0;
4506 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4507 pSMB->SearchHandle = searchHandle; /* always kept as le */
4508 pSMB->SearchCount =
4509 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
4510 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4511 pSMB->ResumeKey = psrch_inf->resume_key;
4512 pSMB->SearchFlags =
4513 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
4515 name_len = psrch_inf->resume_name_len;
4516 params += name_len;
4517 if (name_len < PATH_MAX) {
4518 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4519 byte_count += name_len;
4520 /* 14 byte parm len above enough for 2 byte null terminator */
4521 pSMB->ResumeFileName[name_len] = 0;
4522 pSMB->ResumeFileName[name_len+1] = 0;
4523 } else {
4524 rc = -EINVAL;
4525 goto FNext2_err_exit;
4527 byte_count = params + 1 /* pad */ ;
4528 pSMB->TotalParameterCount = cpu_to_le16(params);
4529 pSMB->ParameterCount = pSMB->TotalParameterCount;
4530 inc_rfc1001_len(pSMB, byte_count);
4531 pSMB->ByteCount = cpu_to_le16(byte_count);
4533 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4534 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4535 cifs_stats_inc(&tcon->num_fnext);
4536 if (rc) {
4537 if (rc == -EBADF) {
4538 psrch_inf->endOfSearch = true;
4539 cifs_buf_release(pSMB);
4540 rc = 0; /* search probably was closed at end of search*/
4541 } else
4542 cFYI(1, "FindNext returned = %d", rc);
4543 } else { /* decode response */
4544 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4546 if (rc == 0) {
4547 unsigned int lnoff;
4549 /* BB fixme add lock for file (srch_info) struct here */
4550 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4551 psrch_inf->unicode = true;
4552 else
4553 psrch_inf->unicode = false;
4554 response_data = (char *) &pSMBr->hdr.Protocol +
4555 le16_to_cpu(pSMBr->t2.ParameterOffset);
4556 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4557 response_data = (char *)&pSMBr->hdr.Protocol +
4558 le16_to_cpu(pSMBr->t2.DataOffset);
4559 if (psrch_inf->smallBuf)
4560 cifs_small_buf_release(
4561 psrch_inf->ntwrk_buf_start);
4562 else
4563 cifs_buf_release(psrch_inf->ntwrk_buf_start);
4564 psrch_inf->srch_entries_start = response_data;
4565 psrch_inf->ntwrk_buf_start = (char *)pSMB;
4566 psrch_inf->smallBuf = 0;
4567 if (parms->EndofSearch)
4568 psrch_inf->endOfSearch = true;
4569 else
4570 psrch_inf->endOfSearch = false;
4571 psrch_inf->entries_in_buffer =
4572 le16_to_cpu(parms->SearchCount);
4573 psrch_inf->index_of_last_entry +=
4574 psrch_inf->entries_in_buffer;
4575 lnoff = le16_to_cpu(parms->LastNameOffset);
4576 if (CIFSMaxBufSize < lnoff) {
4577 cERROR(1, "ignoring corrupt resume name");
4578 psrch_inf->last_entry = NULL;
4579 return rc;
4580 } else
4581 psrch_inf->last_entry =
4582 psrch_inf->srch_entries_start + lnoff;
4584 /* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4585 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
4587 /* BB fixme add unlock here */
4592 /* BB On error, should we leave previous search buf (and count and
4593 last entry fields) intact or free the previous one? */
4595 /* Note: On -EAGAIN error only caller can retry on handle based calls
4596 since file handle passed in no longer valid */
4597 FNext2_err_exit:
4598 if (rc != 0)
4599 cifs_buf_release(pSMB);
4600 return rc;
4604 CIFSFindClose(const int xid, struct cifs_tcon *tcon,
4605 const __u16 searchHandle)
4607 int rc = 0;
4608 FINDCLOSE_REQ *pSMB = NULL;
4610 cFYI(1, "In CIFSSMBFindClose");
4611 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4613 /* no sense returning error if session restarted
4614 as file handle has been closed */
4615 if (rc == -EAGAIN)
4616 return 0;
4617 if (rc)
4618 return rc;
4620 pSMB->FileID = searchHandle;
4621 pSMB->ByteCount = 0;
4622 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4623 if (rc)
4624 cERROR(1, "Send error in FindClose = %d", rc);
4626 cifs_stats_inc(&tcon->num_fclose);
4628 /* Since session is dead, search handle closed on server already */
4629 if (rc == -EAGAIN)
4630 rc = 0;
4632 return rc;
4636 CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
4637 const unsigned char *searchName,
4638 __u64 *inode_number,
4639 const struct nls_table *nls_codepage, int remap)
4641 int rc = 0;
4642 TRANSACTION2_QPI_REQ *pSMB = NULL;
4643 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4644 int name_len, bytes_returned;
4645 __u16 params, byte_count;
4647 cFYI(1, "In GetSrvInodeNum for %s", searchName);
4648 if (tcon == NULL)
4649 return -ENODEV;
4651 GetInodeNumberRetry:
4652 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4653 (void **) &pSMBr);
4654 if (rc)
4655 return rc;
4657 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4658 name_len =
4659 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4660 PATH_MAX, nls_codepage, remap);
4661 name_len++; /* trailing null */
4662 name_len *= 2;
4663 } else { /* BB improve the check for buffer overruns BB */
4664 name_len = strnlen(searchName, PATH_MAX);
4665 name_len++; /* trailing null */
4666 strncpy(pSMB->FileName, searchName, name_len);
4669 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4670 pSMB->TotalDataCount = 0;
4671 pSMB->MaxParameterCount = cpu_to_le16(2);
4672 /* BB find exact max data count below from sess structure BB */
4673 pSMB->MaxDataCount = cpu_to_le16(4000);
4674 pSMB->MaxSetupCount = 0;
4675 pSMB->Reserved = 0;
4676 pSMB->Flags = 0;
4677 pSMB->Timeout = 0;
4678 pSMB->Reserved2 = 0;
4679 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4680 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4681 pSMB->DataCount = 0;
4682 pSMB->DataOffset = 0;
4683 pSMB->SetupCount = 1;
4684 pSMB->Reserved3 = 0;
4685 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4686 byte_count = params + 1 /* pad */ ;
4687 pSMB->TotalParameterCount = cpu_to_le16(params);
4688 pSMB->ParameterCount = pSMB->TotalParameterCount;
4689 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4690 pSMB->Reserved4 = 0;
4691 inc_rfc1001_len(pSMB, byte_count);
4692 pSMB->ByteCount = cpu_to_le16(byte_count);
4694 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4695 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4696 if (rc) {
4697 cFYI(1, "error %d in QueryInternalInfo", rc);
4698 } else {
4699 /* decode response */
4700 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4701 /* BB also check enough total bytes returned */
4702 if (rc || get_bcc(&pSMBr->hdr) < 2)
4703 /* If rc should we check for EOPNOSUPP and
4704 disable the srvino flag? or in caller? */
4705 rc = -EIO; /* bad smb */
4706 else {
4707 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4708 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
4709 struct file_internal_info *pfinfo;
4710 /* BB Do we need a cast or hash here ? */
4711 if (count < 8) {
4712 cFYI(1, "Illegal size ret in QryIntrnlInf");
4713 rc = -EIO;
4714 goto GetInodeNumOut;
4716 pfinfo = (struct file_internal_info *)
4717 (data_offset + (char *) &pSMBr->hdr.Protocol);
4718 *inode_number = le64_to_cpu(pfinfo->UniqueId);
4721 GetInodeNumOut:
4722 cifs_buf_release(pSMB);
4723 if (rc == -EAGAIN)
4724 goto GetInodeNumberRetry;
4725 return rc;
4728 /* parses DFS refferal V3 structure
4729 * caller is responsible for freeing target_nodes
4730 * returns:
4731 * on success - 0
4732 * on failure - errno
4734 static int
4735 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
4736 unsigned int *num_of_nodes,
4737 struct dfs_info3_param **target_nodes,
4738 const struct nls_table *nls_codepage, int remap,
4739 const char *searchName)
4741 int i, rc = 0;
4742 char *data_end;
4743 bool is_unicode;
4744 struct dfs_referral_level_3 *ref;
4746 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4747 is_unicode = true;
4748 else
4749 is_unicode = false;
4750 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4752 if (*num_of_nodes < 1) {
4753 cERROR(1, "num_referrals: must be at least > 0,"
4754 "but we get num_referrals = %d\n", *num_of_nodes);
4755 rc = -EINVAL;
4756 goto parse_DFS_referrals_exit;
4759 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
4760 if (ref->VersionNumber != cpu_to_le16(3)) {
4761 cERROR(1, "Referrals of V%d version are not supported,"
4762 "should be V3", le16_to_cpu(ref->VersionNumber));
4763 rc = -EINVAL;
4764 goto parse_DFS_referrals_exit;
4767 /* get the upper boundary of the resp buffer */
4768 data_end = (char *)(&(pSMBr->PathConsumed)) +
4769 le16_to_cpu(pSMBr->t2.DataCount);
4771 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
4772 *num_of_nodes,
4773 le32_to_cpu(pSMBr->DFSFlags));
4775 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4776 *num_of_nodes, GFP_KERNEL);
4777 if (*target_nodes == NULL) {
4778 cERROR(1, "Failed to allocate buffer for target_nodes\n");
4779 rc = -ENOMEM;
4780 goto parse_DFS_referrals_exit;
4783 /* collect necessary data from referrals */
4784 for (i = 0; i < *num_of_nodes; i++) {
4785 char *temp;
4786 int max_len;
4787 struct dfs_info3_param *node = (*target_nodes)+i;
4789 node->flags = le32_to_cpu(pSMBr->DFSFlags);
4790 if (is_unicode) {
4791 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4792 GFP_KERNEL);
4793 if (tmp == NULL) {
4794 rc = -ENOMEM;
4795 goto parse_DFS_referrals_exit;
4797 cifsConvertToUCS((__le16 *) tmp, searchName,
4798 PATH_MAX, nls_codepage, remap);
4799 node->path_consumed = cifs_ucs2_bytes(tmp,
4800 le16_to_cpu(pSMBr->PathConsumed),
4801 nls_codepage);
4802 kfree(tmp);
4803 } else
4804 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4806 node->server_type = le16_to_cpu(ref->ServerType);
4807 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4809 /* copy DfsPath */
4810 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4811 max_len = data_end - temp;
4812 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4813 is_unicode, nls_codepage);
4814 if (!node->path_name) {
4815 rc = -ENOMEM;
4816 goto parse_DFS_referrals_exit;
4819 /* copy link target UNC */
4820 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4821 max_len = data_end - temp;
4822 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4823 is_unicode, nls_codepage);
4824 if (!node->node_name)
4825 rc = -ENOMEM;
4828 parse_DFS_referrals_exit:
4829 if (rc) {
4830 free_dfs_info_array(*target_nodes, *num_of_nodes);
4831 *target_nodes = NULL;
4832 *num_of_nodes = 0;
4834 return rc;
4838 CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
4839 const unsigned char *searchName,
4840 struct dfs_info3_param **target_nodes,
4841 unsigned int *num_of_nodes,
4842 const struct nls_table *nls_codepage, int remap)
4844 /* TRANS2_GET_DFS_REFERRAL */
4845 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4846 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4847 int rc = 0;
4848 int bytes_returned;
4849 int name_len;
4850 __u16 params, byte_count;
4851 *num_of_nodes = 0;
4852 *target_nodes = NULL;
4854 cFYI(1, "In GetDFSRefer the path %s", searchName);
4855 if (ses == NULL)
4856 return -ENODEV;
4857 getDFSRetry:
4858 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4859 (void **) &pSMBr);
4860 if (rc)
4861 return rc;
4863 /* server pointer checked in called function,
4864 but should never be null here anyway */
4865 pSMB->hdr.Mid = GetNextMid(ses->server);
4866 pSMB->hdr.Tid = ses->ipc_tid;
4867 pSMB->hdr.Uid = ses->Suid;
4868 if (ses->capabilities & CAP_STATUS32)
4869 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4870 if (ses->capabilities & CAP_DFS)
4871 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4873 if (ses->capabilities & CAP_UNICODE) {
4874 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4875 name_len =
4876 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4877 searchName, PATH_MAX, nls_codepage, remap);
4878 name_len++; /* trailing null */
4879 name_len *= 2;
4880 } else { /* BB improve the check for buffer overruns BB */
4881 name_len = strnlen(searchName, PATH_MAX);
4882 name_len++; /* trailing null */
4883 strncpy(pSMB->RequestFileName, searchName, name_len);
4886 if (ses->server) {
4887 if (ses->server->sec_mode &
4888 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4889 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4892 pSMB->hdr.Uid = ses->Suid;
4894 params = 2 /* level */ + name_len /*includes null */ ;
4895 pSMB->TotalDataCount = 0;
4896 pSMB->DataCount = 0;
4897 pSMB->DataOffset = 0;
4898 pSMB->MaxParameterCount = 0;
4899 /* BB find exact max SMB PDU from sess structure BB */
4900 pSMB->MaxDataCount = cpu_to_le16(4000);
4901 pSMB->MaxSetupCount = 0;
4902 pSMB->Reserved = 0;
4903 pSMB->Flags = 0;
4904 pSMB->Timeout = 0;
4905 pSMB->Reserved2 = 0;
4906 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4907 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4908 pSMB->SetupCount = 1;
4909 pSMB->Reserved3 = 0;
4910 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4911 byte_count = params + 3 /* pad */ ;
4912 pSMB->ParameterCount = cpu_to_le16(params);
4913 pSMB->TotalParameterCount = pSMB->ParameterCount;
4914 pSMB->MaxReferralLevel = cpu_to_le16(3);
4915 inc_rfc1001_len(pSMB, byte_count);
4916 pSMB->ByteCount = cpu_to_le16(byte_count);
4918 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4919 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4920 if (rc) {
4921 cFYI(1, "Send error in GetDFSRefer = %d", rc);
4922 goto GetDFSRefExit;
4924 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4926 /* BB Also check if enough total bytes returned? */
4927 if (rc || get_bcc(&pSMBr->hdr) < 17) {
4928 rc = -EIO; /* bad smb */
4929 goto GetDFSRefExit;
4932 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
4933 get_bcc(&pSMBr->hdr),
4934 le16_to_cpu(pSMBr->t2.DataOffset));
4936 /* parse returned result into more usable form */
4937 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4938 target_nodes, nls_codepage, remap,
4939 searchName);
4941 GetDFSRefExit:
4942 cifs_buf_release(pSMB);
4944 if (rc == -EAGAIN)
4945 goto getDFSRetry;
4947 return rc;
4950 /* Query File System Info such as free space to old servers such as Win 9x */
4952 SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
4954 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4955 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4956 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4957 FILE_SYSTEM_ALLOC_INFO *response_data;
4958 int rc = 0;
4959 int bytes_returned = 0;
4960 __u16 params, byte_count;
4962 cFYI(1, "OldQFSInfo");
4963 oldQFSInfoRetry:
4964 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4965 (void **) &pSMBr);
4966 if (rc)
4967 return rc;
4969 params = 2; /* level */
4970 pSMB->TotalDataCount = 0;
4971 pSMB->MaxParameterCount = cpu_to_le16(2);
4972 pSMB->MaxDataCount = cpu_to_le16(1000);
4973 pSMB->MaxSetupCount = 0;
4974 pSMB->Reserved = 0;
4975 pSMB->Flags = 0;
4976 pSMB->Timeout = 0;
4977 pSMB->Reserved2 = 0;
4978 byte_count = params + 1 /* pad */ ;
4979 pSMB->TotalParameterCount = cpu_to_le16(params);
4980 pSMB->ParameterCount = pSMB->TotalParameterCount;
4981 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4982 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4983 pSMB->DataCount = 0;
4984 pSMB->DataOffset = 0;
4985 pSMB->SetupCount = 1;
4986 pSMB->Reserved3 = 0;
4987 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4988 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4989 inc_rfc1001_len(pSMB, byte_count);
4990 pSMB->ByteCount = cpu_to_le16(byte_count);
4992 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4993 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4994 if (rc) {
4995 cFYI(1, "Send error in QFSInfo = %d", rc);
4996 } else { /* decode response */
4997 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4999 if (rc || get_bcc(&pSMBr->hdr) < 18)
5000 rc = -EIO; /* bad smb */
5001 else {
5002 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5003 cFYI(1, "qfsinf resp BCC: %d Offset %d",
5004 get_bcc(&pSMBr->hdr), data_offset);
5006 response_data = (FILE_SYSTEM_ALLOC_INFO *)
5007 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5008 FSData->f_bsize =
5009 le16_to_cpu(response_data->BytesPerSector) *
5010 le32_to_cpu(response_data->
5011 SectorsPerAllocationUnit);
5012 FSData->f_blocks =
5013 le32_to_cpu(response_data->TotalAllocationUnits);
5014 FSData->f_bfree = FSData->f_bavail =
5015 le32_to_cpu(response_data->FreeAllocationUnits);
5016 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5017 (unsigned long long)FSData->f_blocks,
5018 (unsigned long long)FSData->f_bfree,
5019 FSData->f_bsize);
5022 cifs_buf_release(pSMB);
5024 if (rc == -EAGAIN)
5025 goto oldQFSInfoRetry;
5027 return rc;
5031 CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
5033 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5034 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5035 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5036 FILE_SYSTEM_INFO *response_data;
5037 int rc = 0;
5038 int bytes_returned = 0;
5039 __u16 params, byte_count;
5041 cFYI(1, "In QFSInfo");
5042 QFSInfoRetry:
5043 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5044 (void **) &pSMBr);
5045 if (rc)
5046 return rc;
5048 params = 2; /* level */
5049 pSMB->TotalDataCount = 0;
5050 pSMB->MaxParameterCount = cpu_to_le16(2);
5051 pSMB->MaxDataCount = cpu_to_le16(1000);
5052 pSMB->MaxSetupCount = 0;
5053 pSMB->Reserved = 0;
5054 pSMB->Flags = 0;
5055 pSMB->Timeout = 0;
5056 pSMB->Reserved2 = 0;
5057 byte_count = params + 1 /* pad */ ;
5058 pSMB->TotalParameterCount = cpu_to_le16(params);
5059 pSMB->ParameterCount = pSMB->TotalParameterCount;
5060 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5061 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5062 pSMB->DataCount = 0;
5063 pSMB->DataOffset = 0;
5064 pSMB->SetupCount = 1;
5065 pSMB->Reserved3 = 0;
5066 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5067 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
5068 inc_rfc1001_len(pSMB, byte_count);
5069 pSMB->ByteCount = cpu_to_le16(byte_count);
5071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5073 if (rc) {
5074 cFYI(1, "Send error in QFSInfo = %d", rc);
5075 } else { /* decode response */
5076 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5078 if (rc || get_bcc(&pSMBr->hdr) < 24)
5079 rc = -EIO; /* bad smb */
5080 else {
5081 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5083 response_data =
5084 (FILE_SYSTEM_INFO
5085 *) (((char *) &pSMBr->hdr.Protocol) +
5086 data_offset);
5087 FSData->f_bsize =
5088 le32_to_cpu(response_data->BytesPerSector) *
5089 le32_to_cpu(response_data->
5090 SectorsPerAllocationUnit);
5091 FSData->f_blocks =
5092 le64_to_cpu(response_data->TotalAllocationUnits);
5093 FSData->f_bfree = FSData->f_bavail =
5094 le64_to_cpu(response_data->FreeAllocationUnits);
5095 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5096 (unsigned long long)FSData->f_blocks,
5097 (unsigned long long)FSData->f_bfree,
5098 FSData->f_bsize);
5101 cifs_buf_release(pSMB);
5103 if (rc == -EAGAIN)
5104 goto QFSInfoRetry;
5106 return rc;
5110 CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
5112 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5113 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5114 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5115 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5116 int rc = 0;
5117 int bytes_returned = 0;
5118 __u16 params, byte_count;
5120 cFYI(1, "In QFSAttributeInfo");
5121 QFSAttributeRetry:
5122 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5123 (void **) &pSMBr);
5124 if (rc)
5125 return rc;
5127 params = 2; /* level */
5128 pSMB->TotalDataCount = 0;
5129 pSMB->MaxParameterCount = cpu_to_le16(2);
5130 /* BB find exact max SMB PDU from sess structure BB */
5131 pSMB->MaxDataCount = cpu_to_le16(1000);
5132 pSMB->MaxSetupCount = 0;
5133 pSMB->Reserved = 0;
5134 pSMB->Flags = 0;
5135 pSMB->Timeout = 0;
5136 pSMB->Reserved2 = 0;
5137 byte_count = params + 1 /* pad */ ;
5138 pSMB->TotalParameterCount = cpu_to_le16(params);
5139 pSMB->ParameterCount = pSMB->TotalParameterCount;
5140 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5141 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5142 pSMB->DataCount = 0;
5143 pSMB->DataOffset = 0;
5144 pSMB->SetupCount = 1;
5145 pSMB->Reserved3 = 0;
5146 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5147 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
5148 inc_rfc1001_len(pSMB, byte_count);
5149 pSMB->ByteCount = cpu_to_le16(byte_count);
5151 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5152 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5153 if (rc) {
5154 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
5155 } else { /* decode response */
5156 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5158 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5159 /* BB also check if enough bytes returned */
5160 rc = -EIO; /* bad smb */
5161 } else {
5162 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5163 response_data =
5164 (FILE_SYSTEM_ATTRIBUTE_INFO
5165 *) (((char *) &pSMBr->hdr.Protocol) +
5166 data_offset);
5167 memcpy(&tcon->fsAttrInfo, response_data,
5168 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
5171 cifs_buf_release(pSMB);
5173 if (rc == -EAGAIN)
5174 goto QFSAttributeRetry;
5176 return rc;
5180 CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
5182 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5183 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5184 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5185 FILE_SYSTEM_DEVICE_INFO *response_data;
5186 int rc = 0;
5187 int bytes_returned = 0;
5188 __u16 params, byte_count;
5190 cFYI(1, "In QFSDeviceInfo");
5191 QFSDeviceRetry:
5192 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5193 (void **) &pSMBr);
5194 if (rc)
5195 return rc;
5197 params = 2; /* level */
5198 pSMB->TotalDataCount = 0;
5199 pSMB->MaxParameterCount = cpu_to_le16(2);
5200 /* BB find exact max SMB PDU from sess structure BB */
5201 pSMB->MaxDataCount = cpu_to_le16(1000);
5202 pSMB->MaxSetupCount = 0;
5203 pSMB->Reserved = 0;
5204 pSMB->Flags = 0;
5205 pSMB->Timeout = 0;
5206 pSMB->Reserved2 = 0;
5207 byte_count = params + 1 /* pad */ ;
5208 pSMB->TotalParameterCount = cpu_to_le16(params);
5209 pSMB->ParameterCount = pSMB->TotalParameterCount;
5210 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5211 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5213 pSMB->DataCount = 0;
5214 pSMB->DataOffset = 0;
5215 pSMB->SetupCount = 1;
5216 pSMB->Reserved3 = 0;
5217 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5218 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
5219 inc_rfc1001_len(pSMB, byte_count);
5220 pSMB->ByteCount = cpu_to_le16(byte_count);
5222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5223 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5224 if (rc) {
5225 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
5226 } else { /* decode response */
5227 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5229 if (rc || get_bcc(&pSMBr->hdr) <
5230 sizeof(FILE_SYSTEM_DEVICE_INFO))
5231 rc = -EIO; /* bad smb */
5232 else {
5233 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5234 response_data =
5235 (FILE_SYSTEM_DEVICE_INFO *)
5236 (((char *) &pSMBr->hdr.Protocol) +
5237 data_offset);
5238 memcpy(&tcon->fsDevInfo, response_data,
5239 sizeof(FILE_SYSTEM_DEVICE_INFO));
5242 cifs_buf_release(pSMB);
5244 if (rc == -EAGAIN)
5245 goto QFSDeviceRetry;
5247 return rc;
5251 CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
5253 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5254 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5255 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5256 FILE_SYSTEM_UNIX_INFO *response_data;
5257 int rc = 0;
5258 int bytes_returned = 0;
5259 __u16 params, byte_count;
5261 cFYI(1, "In QFSUnixInfo");
5262 QFSUnixRetry:
5263 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5264 (void **) &pSMB, (void **) &pSMBr);
5265 if (rc)
5266 return rc;
5268 params = 2; /* level */
5269 pSMB->TotalDataCount = 0;
5270 pSMB->DataCount = 0;
5271 pSMB->DataOffset = 0;
5272 pSMB->MaxParameterCount = cpu_to_le16(2);
5273 /* BB find exact max SMB PDU from sess structure BB */
5274 pSMB->MaxDataCount = cpu_to_le16(100);
5275 pSMB->MaxSetupCount = 0;
5276 pSMB->Reserved = 0;
5277 pSMB->Flags = 0;
5278 pSMB->Timeout = 0;
5279 pSMB->Reserved2 = 0;
5280 byte_count = params + 1 /* pad */ ;
5281 pSMB->ParameterCount = cpu_to_le16(params);
5282 pSMB->TotalParameterCount = pSMB->ParameterCount;
5283 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5284 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5285 pSMB->SetupCount = 1;
5286 pSMB->Reserved3 = 0;
5287 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5288 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
5289 inc_rfc1001_len(pSMB, byte_count);
5290 pSMB->ByteCount = cpu_to_le16(byte_count);
5292 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5293 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5294 if (rc) {
5295 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
5296 } else { /* decode response */
5297 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5299 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5300 rc = -EIO; /* bad smb */
5301 } else {
5302 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5303 response_data =
5304 (FILE_SYSTEM_UNIX_INFO
5305 *) (((char *) &pSMBr->hdr.Protocol) +
5306 data_offset);
5307 memcpy(&tcon->fsUnixInfo, response_data,
5308 sizeof(FILE_SYSTEM_UNIX_INFO));
5311 cifs_buf_release(pSMB);
5313 if (rc == -EAGAIN)
5314 goto QFSUnixRetry;
5317 return rc;
5321 CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
5323 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5324 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5325 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5326 int rc = 0;
5327 int bytes_returned = 0;
5328 __u16 params, param_offset, offset, byte_count;
5330 cFYI(1, "In SETFSUnixInfo");
5331 SETFSUnixRetry:
5332 /* BB switch to small buf init to save memory */
5333 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5334 (void **) &pSMB, (void **) &pSMBr);
5335 if (rc)
5336 return rc;
5338 params = 4; /* 2 bytes zero followed by info level. */
5339 pSMB->MaxSetupCount = 0;
5340 pSMB->Reserved = 0;
5341 pSMB->Flags = 0;
5342 pSMB->Timeout = 0;
5343 pSMB->Reserved2 = 0;
5344 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5345 - 4;
5346 offset = param_offset + params;
5348 pSMB->MaxParameterCount = cpu_to_le16(4);
5349 /* BB find exact max SMB PDU from sess structure BB */
5350 pSMB->MaxDataCount = cpu_to_le16(100);
5351 pSMB->SetupCount = 1;
5352 pSMB->Reserved3 = 0;
5353 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5354 byte_count = 1 /* pad */ + params + 12;
5356 pSMB->DataCount = cpu_to_le16(12);
5357 pSMB->ParameterCount = cpu_to_le16(params);
5358 pSMB->TotalDataCount = pSMB->DataCount;
5359 pSMB->TotalParameterCount = pSMB->ParameterCount;
5360 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5361 pSMB->DataOffset = cpu_to_le16(offset);
5363 /* Params. */
5364 pSMB->FileNum = 0;
5365 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5367 /* Data. */
5368 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5369 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5370 pSMB->ClientUnixCap = cpu_to_le64(cap);
5372 inc_rfc1001_len(pSMB, byte_count);
5373 pSMB->ByteCount = cpu_to_le16(byte_count);
5375 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5376 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5377 if (rc) {
5378 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
5379 } else { /* decode response */
5380 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5381 if (rc)
5382 rc = -EIO; /* bad smb */
5384 cifs_buf_release(pSMB);
5386 if (rc == -EAGAIN)
5387 goto SETFSUnixRetry;
5389 return rc;
5395 CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
5396 struct kstatfs *FSData)
5398 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5399 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5400 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5401 FILE_SYSTEM_POSIX_INFO *response_data;
5402 int rc = 0;
5403 int bytes_returned = 0;
5404 __u16 params, byte_count;
5406 cFYI(1, "In QFSPosixInfo");
5407 QFSPosixRetry:
5408 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5409 (void **) &pSMBr);
5410 if (rc)
5411 return rc;
5413 params = 2; /* level */
5414 pSMB->TotalDataCount = 0;
5415 pSMB->DataCount = 0;
5416 pSMB->DataOffset = 0;
5417 pSMB->MaxParameterCount = cpu_to_le16(2);
5418 /* BB find exact max SMB PDU from sess structure BB */
5419 pSMB->MaxDataCount = cpu_to_le16(100);
5420 pSMB->MaxSetupCount = 0;
5421 pSMB->Reserved = 0;
5422 pSMB->Flags = 0;
5423 pSMB->Timeout = 0;
5424 pSMB->Reserved2 = 0;
5425 byte_count = params + 1 /* pad */ ;
5426 pSMB->ParameterCount = cpu_to_le16(params);
5427 pSMB->TotalParameterCount = pSMB->ParameterCount;
5428 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5429 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5430 pSMB->SetupCount = 1;
5431 pSMB->Reserved3 = 0;
5432 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5433 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
5434 inc_rfc1001_len(pSMB, byte_count);
5435 pSMB->ByteCount = cpu_to_le16(byte_count);
5437 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5438 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5439 if (rc) {
5440 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
5441 } else { /* decode response */
5442 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5444 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5445 rc = -EIO; /* bad smb */
5446 } else {
5447 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5448 response_data =
5449 (FILE_SYSTEM_POSIX_INFO
5450 *) (((char *) &pSMBr->hdr.Protocol) +
5451 data_offset);
5452 FSData->f_bsize =
5453 le32_to_cpu(response_data->BlockSize);
5454 FSData->f_blocks =
5455 le64_to_cpu(response_data->TotalBlocks);
5456 FSData->f_bfree =
5457 le64_to_cpu(response_data->BlocksAvail);
5458 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
5459 FSData->f_bavail = FSData->f_bfree;
5460 } else {
5461 FSData->f_bavail =
5462 le64_to_cpu(response_data->UserBlocksAvail);
5464 if (response_data->TotalFileNodes != cpu_to_le64(-1))
5465 FSData->f_files =
5466 le64_to_cpu(response_data->TotalFileNodes);
5467 if (response_data->FreeFileNodes != cpu_to_le64(-1))
5468 FSData->f_ffree =
5469 le64_to_cpu(response_data->FreeFileNodes);
5472 cifs_buf_release(pSMB);
5474 if (rc == -EAGAIN)
5475 goto QFSPosixRetry;
5477 return rc;
5481 /* We can not use write of zero bytes trick to
5482 set file size due to need for large file support. Also note that
5483 this SetPathInfo is preferred to SetFileInfo based method in next
5484 routine which is only needed to work around a sharing violation bug
5485 in Samba which this routine can run into */
5488 CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
5489 __u64 size, bool SetAllocation,
5490 const struct nls_table *nls_codepage, int remap)
5492 struct smb_com_transaction2_spi_req *pSMB = NULL;
5493 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5494 struct file_end_of_file_info *parm_data;
5495 int name_len;
5496 int rc = 0;
5497 int bytes_returned = 0;
5498 __u16 params, byte_count, data_count, param_offset, offset;
5500 cFYI(1, "In SetEOF");
5501 SetEOFRetry:
5502 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5503 (void **) &pSMBr);
5504 if (rc)
5505 return rc;
5507 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5508 name_len =
5509 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5510 PATH_MAX, nls_codepage, remap);
5511 name_len++; /* trailing null */
5512 name_len *= 2;
5513 } else { /* BB improve the check for buffer overruns BB */
5514 name_len = strnlen(fileName, PATH_MAX);
5515 name_len++; /* trailing null */
5516 strncpy(pSMB->FileName, fileName, name_len);
5518 params = 6 + name_len;
5519 data_count = sizeof(struct file_end_of_file_info);
5520 pSMB->MaxParameterCount = cpu_to_le16(2);
5521 pSMB->MaxDataCount = cpu_to_le16(4100);
5522 pSMB->MaxSetupCount = 0;
5523 pSMB->Reserved = 0;
5524 pSMB->Flags = 0;
5525 pSMB->Timeout = 0;
5526 pSMB->Reserved2 = 0;
5527 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5528 InformationLevel) - 4;
5529 offset = param_offset + params;
5530 if (SetAllocation) {
5531 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5532 pSMB->InformationLevel =
5533 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5534 else
5535 pSMB->InformationLevel =
5536 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5537 } else /* Set File Size */ {
5538 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5539 pSMB->InformationLevel =
5540 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
5541 else
5542 pSMB->InformationLevel =
5543 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
5546 parm_data =
5547 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5548 offset);
5549 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5550 pSMB->DataOffset = cpu_to_le16(offset);
5551 pSMB->SetupCount = 1;
5552 pSMB->Reserved3 = 0;
5553 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5554 byte_count = 3 /* pad */ + params + data_count;
5555 pSMB->DataCount = cpu_to_le16(data_count);
5556 pSMB->TotalDataCount = pSMB->DataCount;
5557 pSMB->ParameterCount = cpu_to_le16(params);
5558 pSMB->TotalParameterCount = pSMB->ParameterCount;
5559 pSMB->Reserved4 = 0;
5560 inc_rfc1001_len(pSMB, byte_count);
5561 parm_data->FileSize = cpu_to_le64(size);
5562 pSMB->ByteCount = cpu_to_le16(byte_count);
5563 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5564 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5565 if (rc)
5566 cFYI(1, "SetPathInfo (file size) returned %d", rc);
5568 cifs_buf_release(pSMB);
5570 if (rc == -EAGAIN)
5571 goto SetEOFRetry;
5573 return rc;
5577 CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
5578 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
5580 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5581 struct file_end_of_file_info *parm_data;
5582 int rc = 0;
5583 __u16 params, param_offset, offset, byte_count, count;
5585 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5586 (long long)size);
5587 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5589 if (rc)
5590 return rc;
5592 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5593 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5595 params = 6;
5596 pSMB->MaxSetupCount = 0;
5597 pSMB->Reserved = 0;
5598 pSMB->Flags = 0;
5599 pSMB->Timeout = 0;
5600 pSMB->Reserved2 = 0;
5601 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5602 offset = param_offset + params;
5604 count = sizeof(struct file_end_of_file_info);
5605 pSMB->MaxParameterCount = cpu_to_le16(2);
5606 /* BB find exact max SMB PDU from sess structure BB */
5607 pSMB->MaxDataCount = cpu_to_le16(1000);
5608 pSMB->SetupCount = 1;
5609 pSMB->Reserved3 = 0;
5610 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5611 byte_count = 3 /* pad */ + params + count;
5612 pSMB->DataCount = cpu_to_le16(count);
5613 pSMB->ParameterCount = cpu_to_le16(params);
5614 pSMB->TotalDataCount = pSMB->DataCount;
5615 pSMB->TotalParameterCount = pSMB->ParameterCount;
5616 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5617 parm_data =
5618 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5619 + offset);
5620 pSMB->DataOffset = cpu_to_le16(offset);
5621 parm_data->FileSize = cpu_to_le64(size);
5622 pSMB->Fid = fid;
5623 if (SetAllocation) {
5624 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5625 pSMB->InformationLevel =
5626 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5627 else
5628 pSMB->InformationLevel =
5629 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5630 } else /* Set File Size */ {
5631 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5632 pSMB->InformationLevel =
5633 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
5634 else
5635 pSMB->InformationLevel =
5636 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
5638 pSMB->Reserved4 = 0;
5639 inc_rfc1001_len(pSMB, byte_count);
5640 pSMB->ByteCount = cpu_to_le16(byte_count);
5641 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5642 if (rc) {
5643 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
5646 /* Note: On -EAGAIN error only caller can retry on handle based calls
5647 since file handle passed in no longer valid */
5649 return rc;
5652 /* Some legacy servers such as NT4 require that the file times be set on
5653 an open handle, rather than by pathname - this is awkward due to
5654 potential access conflicts on the open, but it is unavoidable for these
5655 old servers since the only other choice is to go from 100 nanosecond DCE
5656 time and resort to the original setpathinfo level which takes the ancient
5657 DOS time format with 2 second granularity */
5659 CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
5660 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
5662 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5663 char *data_offset;
5664 int rc = 0;
5665 __u16 params, param_offset, offset, byte_count, count;
5667 cFYI(1, "Set Times (via SetFileInfo)");
5668 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5670 if (rc)
5671 return rc;
5673 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5674 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5676 params = 6;
5677 pSMB->MaxSetupCount = 0;
5678 pSMB->Reserved = 0;
5679 pSMB->Flags = 0;
5680 pSMB->Timeout = 0;
5681 pSMB->Reserved2 = 0;
5682 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5683 offset = param_offset + params;
5685 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5687 count = sizeof(FILE_BASIC_INFO);
5688 pSMB->MaxParameterCount = cpu_to_le16(2);
5689 /* BB find max SMB PDU from sess */
5690 pSMB->MaxDataCount = cpu_to_le16(1000);
5691 pSMB->SetupCount = 1;
5692 pSMB->Reserved3 = 0;
5693 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5694 byte_count = 3 /* pad */ + params + count;
5695 pSMB->DataCount = cpu_to_le16(count);
5696 pSMB->ParameterCount = cpu_to_le16(params);
5697 pSMB->TotalDataCount = pSMB->DataCount;
5698 pSMB->TotalParameterCount = pSMB->ParameterCount;
5699 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5700 pSMB->DataOffset = cpu_to_le16(offset);
5701 pSMB->Fid = fid;
5702 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5703 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5704 else
5705 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5706 pSMB->Reserved4 = 0;
5707 inc_rfc1001_len(pSMB, byte_count);
5708 pSMB->ByteCount = cpu_to_le16(byte_count);
5709 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5710 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5711 if (rc)
5712 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
5714 /* Note: On -EAGAIN error only caller can retry on handle based calls
5715 since file handle passed in no longer valid */
5717 return rc;
5721 CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
5722 bool delete_file, __u16 fid, __u32 pid_of_opener)
5724 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5725 char *data_offset;
5726 int rc = 0;
5727 __u16 params, param_offset, offset, byte_count, count;
5729 cFYI(1, "Set File Disposition (via SetFileInfo)");
5730 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5732 if (rc)
5733 return rc;
5735 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5736 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5738 params = 6;
5739 pSMB->MaxSetupCount = 0;
5740 pSMB->Reserved = 0;
5741 pSMB->Flags = 0;
5742 pSMB->Timeout = 0;
5743 pSMB->Reserved2 = 0;
5744 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5745 offset = param_offset + params;
5747 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5749 count = 1;
5750 pSMB->MaxParameterCount = cpu_to_le16(2);
5751 /* BB find max SMB PDU from sess */
5752 pSMB->MaxDataCount = cpu_to_le16(1000);
5753 pSMB->SetupCount = 1;
5754 pSMB->Reserved3 = 0;
5755 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5756 byte_count = 3 /* pad */ + params + count;
5757 pSMB->DataCount = cpu_to_le16(count);
5758 pSMB->ParameterCount = cpu_to_le16(params);
5759 pSMB->TotalDataCount = pSMB->DataCount;
5760 pSMB->TotalParameterCount = pSMB->ParameterCount;
5761 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5762 pSMB->DataOffset = cpu_to_le16(offset);
5763 pSMB->Fid = fid;
5764 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5765 pSMB->Reserved4 = 0;
5766 inc_rfc1001_len(pSMB, byte_count);
5767 pSMB->ByteCount = cpu_to_le16(byte_count);
5768 *data_offset = delete_file ? 1 : 0;
5769 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5770 if (rc)
5771 cFYI(1, "Send error in SetFileDisposition = %d", rc);
5773 return rc;
5777 CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
5778 const char *fileName, const FILE_BASIC_INFO *data,
5779 const struct nls_table *nls_codepage, int remap)
5781 TRANSACTION2_SPI_REQ *pSMB = NULL;
5782 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5783 int name_len;
5784 int rc = 0;
5785 int bytes_returned = 0;
5786 char *data_offset;
5787 __u16 params, param_offset, offset, byte_count, count;
5789 cFYI(1, "In SetTimes");
5791 SetTimesRetry:
5792 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5793 (void **) &pSMBr);
5794 if (rc)
5795 return rc;
5797 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5798 name_len =
5799 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5800 PATH_MAX, nls_codepage, remap);
5801 name_len++; /* trailing null */
5802 name_len *= 2;
5803 } else { /* BB improve the check for buffer overruns BB */
5804 name_len = strnlen(fileName, PATH_MAX);
5805 name_len++; /* trailing null */
5806 strncpy(pSMB->FileName, fileName, name_len);
5809 params = 6 + name_len;
5810 count = sizeof(FILE_BASIC_INFO);
5811 pSMB->MaxParameterCount = cpu_to_le16(2);
5812 /* BB find max SMB PDU from sess structure BB */
5813 pSMB->MaxDataCount = cpu_to_le16(1000);
5814 pSMB->MaxSetupCount = 0;
5815 pSMB->Reserved = 0;
5816 pSMB->Flags = 0;
5817 pSMB->Timeout = 0;
5818 pSMB->Reserved2 = 0;
5819 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5820 InformationLevel) - 4;
5821 offset = param_offset + params;
5822 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5823 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5824 pSMB->DataOffset = cpu_to_le16(offset);
5825 pSMB->SetupCount = 1;
5826 pSMB->Reserved3 = 0;
5827 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5828 byte_count = 3 /* pad */ + params + count;
5830 pSMB->DataCount = cpu_to_le16(count);
5831 pSMB->ParameterCount = cpu_to_le16(params);
5832 pSMB->TotalDataCount = pSMB->DataCount;
5833 pSMB->TotalParameterCount = pSMB->ParameterCount;
5834 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5835 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5836 else
5837 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5838 pSMB->Reserved4 = 0;
5839 inc_rfc1001_len(pSMB, byte_count);
5840 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5841 pSMB->ByteCount = cpu_to_le16(byte_count);
5842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5843 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5844 if (rc)
5845 cFYI(1, "SetPathInfo (times) returned %d", rc);
5847 cifs_buf_release(pSMB);
5849 if (rc == -EAGAIN)
5850 goto SetTimesRetry;
5852 return rc;
5855 /* Can not be used to set time stamps yet (due to old DOS time format) */
5856 /* Can be used to set attributes */
5857 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5858 handling it anyway and NT4 was what we thought it would be needed for
5859 Do not delete it until we prove whether needed for Win9x though */
5861 CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
5862 __u16 dos_attrs, const struct nls_table *nls_codepage)
5864 SETATTR_REQ *pSMB = NULL;
5865 SETATTR_RSP *pSMBr = NULL;
5866 int rc = 0;
5867 int bytes_returned;
5868 int name_len;
5870 cFYI(1, "In SetAttrLegacy");
5872 SetAttrLgcyRetry:
5873 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5874 (void **) &pSMBr);
5875 if (rc)
5876 return rc;
5878 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5879 name_len =
5880 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
5881 PATH_MAX, nls_codepage);
5882 name_len++; /* trailing null */
5883 name_len *= 2;
5884 } else { /* BB improve the check for buffer overruns BB */
5885 name_len = strnlen(fileName, PATH_MAX);
5886 name_len++; /* trailing null */
5887 strncpy(pSMB->fileName, fileName, name_len);
5889 pSMB->attr = cpu_to_le16(dos_attrs);
5890 pSMB->BufferFormat = 0x04;
5891 inc_rfc1001_len(pSMB, name_len + 1);
5892 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5895 if (rc)
5896 cFYI(1, "Error in LegacySetAttr = %d", rc);
5898 cifs_buf_release(pSMB);
5900 if (rc == -EAGAIN)
5901 goto SetAttrLgcyRetry;
5903 return rc;
5905 #endif /* temporarily unneeded SetAttr legacy function */
5907 static void
5908 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5909 const struct cifs_unix_set_info_args *args)
5911 u64 mode = args->mode;
5914 * Samba server ignores set of file size to zero due to bugs in some
5915 * older clients, but we should be precise - we use SetFileSize to
5916 * set file size and do not want to truncate file size to zero
5917 * accidentally as happened on one Samba server beta by putting
5918 * zero instead of -1 here
5920 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5921 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5922 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5923 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5924 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5925 data_offset->Uid = cpu_to_le64(args->uid);
5926 data_offset->Gid = cpu_to_le64(args->gid);
5927 /* better to leave device as zero when it is */
5928 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5929 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5930 data_offset->Permissions = cpu_to_le64(mode);
5932 if (S_ISREG(mode))
5933 data_offset->Type = cpu_to_le32(UNIX_FILE);
5934 else if (S_ISDIR(mode))
5935 data_offset->Type = cpu_to_le32(UNIX_DIR);
5936 else if (S_ISLNK(mode))
5937 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5938 else if (S_ISCHR(mode))
5939 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5940 else if (S_ISBLK(mode))
5941 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5942 else if (S_ISFIFO(mode))
5943 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5944 else if (S_ISSOCK(mode))
5945 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5949 CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
5950 const struct cifs_unix_set_info_args *args,
5951 u16 fid, u32 pid_of_opener)
5953 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5954 FILE_UNIX_BASIC_INFO *data_offset;
5955 int rc = 0;
5956 u16 params, param_offset, offset, byte_count, count;
5958 cFYI(1, "Set Unix Info (via SetFileInfo)");
5959 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5961 if (rc)
5962 return rc;
5964 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5965 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5967 params = 6;
5968 pSMB->MaxSetupCount = 0;
5969 pSMB->Reserved = 0;
5970 pSMB->Flags = 0;
5971 pSMB->Timeout = 0;
5972 pSMB->Reserved2 = 0;
5973 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5974 offset = param_offset + params;
5976 data_offset = (FILE_UNIX_BASIC_INFO *)
5977 ((char *)(&pSMB->hdr.Protocol) + offset);
5978 count = sizeof(FILE_UNIX_BASIC_INFO);
5980 pSMB->MaxParameterCount = cpu_to_le16(2);
5981 /* BB find max SMB PDU from sess */
5982 pSMB->MaxDataCount = cpu_to_le16(1000);
5983 pSMB->SetupCount = 1;
5984 pSMB->Reserved3 = 0;
5985 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5986 byte_count = 3 /* pad */ + params + count;
5987 pSMB->DataCount = cpu_to_le16(count);
5988 pSMB->ParameterCount = cpu_to_le16(params);
5989 pSMB->TotalDataCount = pSMB->DataCount;
5990 pSMB->TotalParameterCount = pSMB->ParameterCount;
5991 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5992 pSMB->DataOffset = cpu_to_le16(offset);
5993 pSMB->Fid = fid;
5994 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5995 pSMB->Reserved4 = 0;
5996 inc_rfc1001_len(pSMB, byte_count);
5997 pSMB->ByteCount = cpu_to_le16(byte_count);
5999 cifs_fill_unix_set_info(data_offset, args);
6001 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
6002 if (rc)
6003 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
6005 /* Note: On -EAGAIN error only caller can retry on handle based calls
6006 since file handle passed in no longer valid */
6008 return rc;
6012 CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
6013 const struct cifs_unix_set_info_args *args,
6014 const struct nls_table *nls_codepage, int remap)
6016 TRANSACTION2_SPI_REQ *pSMB = NULL;
6017 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6018 int name_len;
6019 int rc = 0;
6020 int bytes_returned = 0;
6021 FILE_UNIX_BASIC_INFO *data_offset;
6022 __u16 params, param_offset, offset, count, byte_count;
6024 cFYI(1, "In SetUID/GID/Mode");
6025 setPermsRetry:
6026 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6027 (void **) &pSMBr);
6028 if (rc)
6029 return rc;
6031 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6032 name_len =
6033 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
6034 PATH_MAX, nls_codepage, remap);
6035 name_len++; /* trailing null */
6036 name_len *= 2;
6037 } else { /* BB improve the check for buffer overruns BB */
6038 name_len = strnlen(fileName, PATH_MAX);
6039 name_len++; /* trailing null */
6040 strncpy(pSMB->FileName, fileName, name_len);
6043 params = 6 + name_len;
6044 count = sizeof(FILE_UNIX_BASIC_INFO);
6045 pSMB->MaxParameterCount = cpu_to_le16(2);
6046 /* BB find max SMB PDU from sess structure BB */
6047 pSMB->MaxDataCount = cpu_to_le16(1000);
6048 pSMB->MaxSetupCount = 0;
6049 pSMB->Reserved = 0;
6050 pSMB->Flags = 0;
6051 pSMB->Timeout = 0;
6052 pSMB->Reserved2 = 0;
6053 param_offset = offsetof(struct smb_com_transaction2_spi_req,
6054 InformationLevel) - 4;
6055 offset = param_offset + params;
6056 data_offset =
6057 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6058 offset);
6059 memset(data_offset, 0, count);
6060 pSMB->DataOffset = cpu_to_le16(offset);
6061 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6062 pSMB->SetupCount = 1;
6063 pSMB->Reserved3 = 0;
6064 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6065 byte_count = 3 /* pad */ + params + count;
6066 pSMB->ParameterCount = cpu_to_le16(params);
6067 pSMB->DataCount = cpu_to_le16(count);
6068 pSMB->TotalParameterCount = pSMB->ParameterCount;
6069 pSMB->TotalDataCount = pSMB->DataCount;
6070 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6071 pSMB->Reserved4 = 0;
6072 inc_rfc1001_len(pSMB, byte_count);
6074 cifs_fill_unix_set_info(data_offset, args);
6076 pSMB->ByteCount = cpu_to_le16(byte_count);
6077 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6078 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6079 if (rc)
6080 cFYI(1, "SetPathInfo (perms) returned %d", rc);
6082 cifs_buf_release(pSMB);
6083 if (rc == -EAGAIN)
6084 goto setPermsRetry;
6085 return rc;
6088 #ifdef CONFIG_CIFS_XATTR
6090 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6091 * function used by listxattr and getxattr type calls. When ea_name is set,
6092 * it looks for that attribute name and stuffs that value into the EAData
6093 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6094 * buffer. In both cases, the return value is either the length of the
6095 * resulting data or a negative error code. If EAData is a NULL pointer then
6096 * the data isn't copied to it, but the length is returned.
6098 ssize_t
6099 CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
6100 const unsigned char *searchName, const unsigned char *ea_name,
6101 char *EAData, size_t buf_size,
6102 const struct nls_table *nls_codepage, int remap)
6104 /* BB assumes one setup word */
6105 TRANSACTION2_QPI_REQ *pSMB = NULL;
6106 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6107 int rc = 0;
6108 int bytes_returned;
6109 int list_len;
6110 struct fealist *ea_response_data;
6111 struct fea *temp_fea;
6112 char *temp_ptr;
6113 char *end_of_smb;
6114 __u16 params, byte_count, data_offset;
6115 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
6117 cFYI(1, "In Query All EAs path %s", searchName);
6118 QAllEAsRetry:
6119 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6120 (void **) &pSMBr);
6121 if (rc)
6122 return rc;
6124 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6125 list_len =
6126 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
6127 PATH_MAX, nls_codepage, remap);
6128 list_len++; /* trailing null */
6129 list_len *= 2;
6130 } else { /* BB improve the check for buffer overruns BB */
6131 list_len = strnlen(searchName, PATH_MAX);
6132 list_len++; /* trailing null */
6133 strncpy(pSMB->FileName, searchName, list_len);
6136 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
6137 pSMB->TotalDataCount = 0;
6138 pSMB->MaxParameterCount = cpu_to_le16(2);
6139 /* BB find exact max SMB PDU from sess structure BB */
6140 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
6141 pSMB->MaxSetupCount = 0;
6142 pSMB->Reserved = 0;
6143 pSMB->Flags = 0;
6144 pSMB->Timeout = 0;
6145 pSMB->Reserved2 = 0;
6146 pSMB->ParameterOffset = cpu_to_le16(offsetof(
6147 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
6148 pSMB->DataCount = 0;
6149 pSMB->DataOffset = 0;
6150 pSMB->SetupCount = 1;
6151 pSMB->Reserved3 = 0;
6152 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6153 byte_count = params + 1 /* pad */ ;
6154 pSMB->TotalParameterCount = cpu_to_le16(params);
6155 pSMB->ParameterCount = pSMB->TotalParameterCount;
6156 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6157 pSMB->Reserved4 = 0;
6158 inc_rfc1001_len(pSMB, byte_count);
6159 pSMB->ByteCount = cpu_to_le16(byte_count);
6161 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6162 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6163 if (rc) {
6164 cFYI(1, "Send error in QueryAllEAs = %d", rc);
6165 goto QAllEAsOut;
6169 /* BB also check enough total bytes returned */
6170 /* BB we need to improve the validity checking
6171 of these trans2 responses */
6173 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
6174 if (rc || get_bcc(&pSMBr->hdr) < 4) {
6175 rc = -EIO; /* bad smb */
6176 goto QAllEAsOut;
6179 /* check that length of list is not more than bcc */
6180 /* check that each entry does not go beyond length
6181 of list */
6182 /* check that each element of each entry does not
6183 go beyond end of list */
6184 /* validate_trans2_offsets() */
6185 /* BB check if start of smb + data_offset > &bcc+ bcc */
6187 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6188 ea_response_data = (struct fealist *)
6189 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6191 list_len = le32_to_cpu(ea_response_data->list_len);
6192 cFYI(1, "ea length %d", list_len);
6193 if (list_len <= 8) {
6194 cFYI(1, "empty EA list returned from server");
6195 goto QAllEAsOut;
6198 /* make sure list_len doesn't go past end of SMB */
6199 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
6200 if ((char *)ea_response_data + list_len > end_of_smb) {
6201 cFYI(1, "EA list appears to go beyond SMB");
6202 rc = -EIO;
6203 goto QAllEAsOut;
6206 /* account for ea list len */
6207 list_len -= 4;
6208 temp_fea = ea_response_data->list;
6209 temp_ptr = (char *)temp_fea;
6210 while (list_len > 0) {
6211 unsigned int name_len;
6212 __u16 value_len;
6214 list_len -= 4;
6215 temp_ptr += 4;
6216 /* make sure we can read name_len and value_len */
6217 if (list_len < 0) {
6218 cFYI(1, "EA entry goes beyond length of list");
6219 rc = -EIO;
6220 goto QAllEAsOut;
6223 name_len = temp_fea->name_len;
6224 value_len = le16_to_cpu(temp_fea->value_len);
6225 list_len -= name_len + 1 + value_len;
6226 if (list_len < 0) {
6227 cFYI(1, "EA entry goes beyond length of list");
6228 rc = -EIO;
6229 goto QAllEAsOut;
6232 if (ea_name) {
6233 if (ea_name_len == name_len &&
6234 memcmp(ea_name, temp_ptr, name_len) == 0) {
6235 temp_ptr += name_len + 1;
6236 rc = value_len;
6237 if (buf_size == 0)
6238 goto QAllEAsOut;
6239 if ((size_t)value_len > buf_size) {
6240 rc = -ERANGE;
6241 goto QAllEAsOut;
6243 memcpy(EAData, temp_ptr, value_len);
6244 goto QAllEAsOut;
6246 } else {
6247 /* account for prefix user. and trailing null */
6248 rc += (5 + 1 + name_len);
6249 if (rc < (int) buf_size) {
6250 memcpy(EAData, "user.", 5);
6251 EAData += 5;
6252 memcpy(EAData, temp_ptr, name_len);
6253 EAData += name_len;
6254 /* null terminate name */
6255 *EAData = 0;
6256 ++EAData;
6257 } else if (buf_size == 0) {
6258 /* skip copy - calc size only */
6259 } else {
6260 /* stop before overrun buffer */
6261 rc = -ERANGE;
6262 break;
6265 temp_ptr += name_len + 1 + value_len;
6266 temp_fea = (struct fea *)temp_ptr;
6269 /* didn't find the named attribute */
6270 if (ea_name)
6271 rc = -ENODATA;
6273 QAllEAsOut:
6274 cifs_buf_release(pSMB);
6275 if (rc == -EAGAIN)
6276 goto QAllEAsRetry;
6278 return (ssize_t)rc;
6282 CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
6283 const char *ea_name, const void *ea_value,
6284 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6285 int remap)
6287 struct smb_com_transaction2_spi_req *pSMB = NULL;
6288 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6289 struct fealist *parm_data;
6290 int name_len;
6291 int rc = 0;
6292 int bytes_returned = 0;
6293 __u16 params, param_offset, byte_count, offset, count;
6295 cFYI(1, "In SetEA");
6296 SetEARetry:
6297 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6298 (void **) &pSMBr);
6299 if (rc)
6300 return rc;
6302 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6303 name_len =
6304 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
6305 PATH_MAX, nls_codepage, remap);
6306 name_len++; /* trailing null */
6307 name_len *= 2;
6308 } else { /* BB improve the check for buffer overruns BB */
6309 name_len = strnlen(fileName, PATH_MAX);
6310 name_len++; /* trailing null */
6311 strncpy(pSMB->FileName, fileName, name_len);
6314 params = 6 + name_len;
6316 /* done calculating parms using name_len of file name,
6317 now use name_len to calculate length of ea name
6318 we are going to create in the inode xattrs */
6319 if (ea_name == NULL)
6320 name_len = 0;
6321 else
6322 name_len = strnlen(ea_name, 255);
6324 count = sizeof(*parm_data) + ea_value_len + name_len;
6325 pSMB->MaxParameterCount = cpu_to_le16(2);
6326 /* BB find max SMB PDU from sess */
6327 pSMB->MaxDataCount = cpu_to_le16(1000);
6328 pSMB->MaxSetupCount = 0;
6329 pSMB->Reserved = 0;
6330 pSMB->Flags = 0;
6331 pSMB->Timeout = 0;
6332 pSMB->Reserved2 = 0;
6333 param_offset = offsetof(struct smb_com_transaction2_spi_req,
6334 InformationLevel) - 4;
6335 offset = param_offset + params;
6336 pSMB->InformationLevel =
6337 cpu_to_le16(SMB_SET_FILE_EA);
6339 parm_data =
6340 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6341 offset);
6342 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6343 pSMB->DataOffset = cpu_to_le16(offset);
6344 pSMB->SetupCount = 1;
6345 pSMB->Reserved3 = 0;
6346 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6347 byte_count = 3 /* pad */ + params + count;
6348 pSMB->DataCount = cpu_to_le16(count);
6349 parm_data->list_len = cpu_to_le32(count);
6350 parm_data->list[0].EA_flags = 0;
6351 /* we checked above that name len is less than 255 */
6352 parm_data->list[0].name_len = (__u8)name_len;
6353 /* EA names are always ASCII */
6354 if (ea_name)
6355 strncpy(parm_data->list[0].name, ea_name, name_len);
6356 parm_data->list[0].name[name_len] = 0;
6357 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6358 /* caller ensures that ea_value_len is less than 64K but
6359 we need to ensure that it fits within the smb */
6361 /*BB add length check to see if it would fit in
6362 negotiated SMB buffer size BB */
6363 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6364 if (ea_value_len)
6365 memcpy(parm_data->list[0].name+name_len+1,
6366 ea_value, ea_value_len);
6368 pSMB->TotalDataCount = pSMB->DataCount;
6369 pSMB->ParameterCount = cpu_to_le16(params);
6370 pSMB->TotalParameterCount = pSMB->ParameterCount;
6371 pSMB->Reserved4 = 0;
6372 inc_rfc1001_len(pSMB, byte_count);
6373 pSMB->ByteCount = cpu_to_le16(byte_count);
6374 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6375 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6376 if (rc)
6377 cFYI(1, "SetPathInfo (EA) returned %d", rc);
6379 cifs_buf_release(pSMB);
6381 if (rc == -EAGAIN)
6382 goto SetEARetry;
6384 return rc;
6386 #endif
6388 #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6390 * Years ago the kernel added a "dnotify" function for Samba server,
6391 * to allow network clients (such as Windows) to display updated
6392 * lists of files in directory listings automatically when
6393 * files are added by one user when another user has the
6394 * same directory open on their desktop. The Linux cifs kernel
6395 * client hooked into the kernel side of this interface for
6396 * the same reason, but ironically when the VFS moved from
6397 * "dnotify" to "inotify" it became harder to plug in Linux
6398 * network file system clients (the most obvious use case
6399 * for notify interfaces is when multiple users can update
6400 * the contents of the same directory - exactly what network
6401 * file systems can do) although the server (Samba) could
6402 * still use it. For the short term we leave the worker
6403 * function ifdeffed out (below) until inotify is fixed
6404 * in the VFS to make it easier to plug in network file
6405 * system clients. If inotify turns out to be permanently
6406 * incompatible for network fs clients, we could instead simply
6407 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6409 int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
6410 const int notify_subdirs, const __u16 netfid,
6411 __u32 filter, struct file *pfile, int multishot,
6412 const struct nls_table *nls_codepage)
6414 int rc = 0;
6415 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6416 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6417 struct dir_notify_req *dnotify_req;
6418 int bytes_returned;
6420 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6421 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6422 (void **) &pSMBr);
6423 if (rc)
6424 return rc;
6426 pSMB->TotalParameterCount = 0 ;
6427 pSMB->TotalDataCount = 0;
6428 pSMB->MaxParameterCount = cpu_to_le32(2);
6429 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
6430 pSMB->MaxSetupCount = 4;
6431 pSMB->Reserved = 0;
6432 pSMB->ParameterOffset = 0;
6433 pSMB->DataCount = 0;
6434 pSMB->DataOffset = 0;
6435 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6436 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6437 pSMB->ParameterCount = pSMB->TotalParameterCount;
6438 if (notify_subdirs)
6439 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6440 pSMB->Reserved2 = 0;
6441 pSMB->CompletionFilter = cpu_to_le32(filter);
6442 pSMB->Fid = netfid; /* file handle always le */
6443 pSMB->ByteCount = 0;
6445 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6446 (struct smb_hdr *)pSMBr, &bytes_returned,
6447 CIFS_ASYNC_OP);
6448 if (rc) {
6449 cFYI(1, "Error in Notify = %d", rc);
6450 } else {
6451 /* Add file to outstanding requests */
6452 /* BB change to kmem cache alloc */
6453 dnotify_req = kmalloc(
6454 sizeof(struct dir_notify_req),
6455 GFP_KERNEL);
6456 if (dnotify_req) {
6457 dnotify_req->Pid = pSMB->hdr.Pid;
6458 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6459 dnotify_req->Mid = pSMB->hdr.Mid;
6460 dnotify_req->Tid = pSMB->hdr.Tid;
6461 dnotify_req->Uid = pSMB->hdr.Uid;
6462 dnotify_req->netfid = netfid;
6463 dnotify_req->pfile = pfile;
6464 dnotify_req->filter = filter;
6465 dnotify_req->multishot = multishot;
6466 spin_lock(&GlobalMid_Lock);
6467 list_add_tail(&dnotify_req->lhead,
6468 &GlobalDnotifyReqList);
6469 spin_unlock(&GlobalMid_Lock);
6470 } else
6471 rc = -ENOMEM;
6473 cifs_buf_release(pSMB);
6474 return rc;
6476 #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */