x86, relocs: Remove an unused variable
[zen-stable.git] / fs / cifs / cifssmb.c
blob1250bbae3287d8fe26dce7c161a14009d60ca43a
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 = min_t(unsigned int,
462 le16_to_cpu(rsp->MaxMpxCount),
463 cifs_max_pending);
464 server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
465 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
466 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
467 /* even though we do not use raw we might as well set this
468 accurately, in case we ever find a need for it */
469 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
470 server->max_rw = 0xFF00;
471 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
472 } else {
473 server->max_rw = 0;/* do not need to use raw anyway */
474 server->capabilities = CAP_MPX_MODE;
476 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
477 if (tmp == -1) {
478 /* OS/2 often does not set timezone therefore
479 * we must use server time to calc time zone.
480 * Could deviate slightly from the right zone.
481 * Smallest defined timezone difference is 15 minutes
482 * (i.e. Nepal). Rounding up/down is done to match
483 * this requirement.
485 int val, seconds, remain, result;
486 struct timespec ts, utc;
487 utc = CURRENT_TIME;
488 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
489 rsp->SrvTime.Time, 0);
490 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
491 (int)ts.tv_sec, (int)utc.tv_sec,
492 (int)(utc.tv_sec - ts.tv_sec));
493 val = (int)(utc.tv_sec - ts.tv_sec);
494 seconds = abs(val);
495 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
496 remain = seconds % MIN_TZ_ADJ;
497 if (remain >= (MIN_TZ_ADJ / 2))
498 result += MIN_TZ_ADJ;
499 if (val < 0)
500 result = -result;
501 server->timeAdj = result;
502 } else {
503 server->timeAdj = (int)tmp;
504 server->timeAdj *= 60; /* also in seconds */
506 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
509 /* BB get server time for time conversions and add
510 code to use it and timezone since this is not UTC */
512 if (rsp->EncryptionKeyLength ==
513 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
514 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
515 CIFS_CRYPTO_KEY_SIZE);
516 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
517 rc = -EIO; /* need cryptkey unless plain text */
518 goto neg_err_exit;
521 cFYI(1, "LANMAN negotiated");
522 /* we will not end up setting signing flags - as no signing
523 was in LANMAN and server did not return the flags on */
524 goto signing_check;
525 #else /* weak security disabled */
526 } else if (pSMBr->hdr.WordCount == 13) {
527 cERROR(1, "mount failed, cifs module not built "
528 "with CIFS_WEAK_PW_HASH support");
529 rc = -EOPNOTSUPP;
530 #endif /* WEAK_PW_HASH */
531 goto neg_err_exit;
532 } else if (pSMBr->hdr.WordCount != 17) {
533 /* unknown wct */
534 rc = -EOPNOTSUPP;
535 goto neg_err_exit;
537 /* else wct == 17 NTLM */
538 server->sec_mode = pSMBr->SecurityMode;
539 if ((server->sec_mode & SECMODE_USER) == 0)
540 cFYI(1, "share mode security");
542 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
543 #ifdef CONFIG_CIFS_WEAK_PW_HASH
544 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
545 #endif /* CIFS_WEAK_PW_HASH */
546 cERROR(1, "Server requests plain text password"
547 " but client support disabled");
549 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
550 server->secType = NTLMv2;
551 else if (secFlags & CIFSSEC_MAY_NTLM)
552 server->secType = NTLM;
553 else if (secFlags & CIFSSEC_MAY_NTLMV2)
554 server->secType = NTLMv2;
555 else if (secFlags & CIFSSEC_MAY_KRB5)
556 server->secType = Kerberos;
557 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
558 server->secType = RawNTLMSSP;
559 else if (secFlags & CIFSSEC_MAY_LANMAN)
560 server->secType = LANMAN;
561 else {
562 rc = -EOPNOTSUPP;
563 cERROR(1, "Invalid security type");
564 goto neg_err_exit;
566 /* else ... any others ...? */
568 /* one byte, so no need to convert this or EncryptionKeyLen from
569 little endian */
570 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
571 cifs_max_pending);
572 server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
573 /* probably no need to store and check maxvcs */
574 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
575 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
576 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
577 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
578 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
579 server->timeAdj *= 60;
580 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
581 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
582 CIFS_CRYPTO_KEY_SIZE);
583 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
584 server->capabilities & CAP_EXTENDED_SECURITY) &&
585 (pSMBr->EncryptionKeyLength == 0)) {
586 /* decode security blob */
587 count = get_bcc(&pSMBr->hdr);
588 if (count < 16) {
589 rc = -EIO;
590 goto neg_err_exit;
592 spin_lock(&cifs_tcp_ses_lock);
593 if (server->srv_count > 1) {
594 spin_unlock(&cifs_tcp_ses_lock);
595 if (memcmp(server->server_GUID,
596 pSMBr->u.extended_response.
597 GUID, 16) != 0) {
598 cFYI(1, "server UID changed");
599 memcpy(server->server_GUID,
600 pSMBr->u.extended_response.GUID,
601 16);
603 } else {
604 spin_unlock(&cifs_tcp_ses_lock);
605 memcpy(server->server_GUID,
606 pSMBr->u.extended_response.GUID, 16);
609 if (count == 16) {
610 server->secType = RawNTLMSSP;
611 } else {
612 rc = decode_negTokenInit(pSMBr->u.extended_response.
613 SecurityBlob, count - 16,
614 server);
615 if (rc == 1)
616 rc = 0;
617 else
618 rc = -EINVAL;
619 if (server->secType == Kerberos) {
620 if (!server->sec_kerberos &&
621 !server->sec_mskerberos)
622 rc = -EOPNOTSUPP;
623 } else if (server->secType == RawNTLMSSP) {
624 if (!server->sec_ntlmssp)
625 rc = -EOPNOTSUPP;
626 } else
627 rc = -EOPNOTSUPP;
629 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
630 rc = -EIO; /* no crypt key only if plain text pwd */
631 goto neg_err_exit;
632 } else
633 server->capabilities &= ~CAP_EXTENDED_SECURITY;
635 #ifdef CONFIG_CIFS_WEAK_PW_HASH
636 signing_check:
637 #endif
638 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
639 /* MUST_SIGN already includes the MAY_SIGN FLAG
640 so if this is zero it means that signing is disabled */
641 cFYI(1, "Signing disabled");
642 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
643 cERROR(1, "Server requires "
644 "packet signing to be enabled in "
645 "/proc/fs/cifs/SecurityFlags.");
646 rc = -EOPNOTSUPP;
648 server->sec_mode &=
649 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
650 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
651 /* signing required */
652 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
653 if ((server->sec_mode &
654 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
655 cERROR(1, "signing required but server lacks support");
656 rc = -EOPNOTSUPP;
657 } else
658 server->sec_mode |= SECMODE_SIGN_REQUIRED;
659 } else {
660 /* signing optional ie CIFSSEC_MAY_SIGN */
661 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
662 server->sec_mode &=
663 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
666 neg_err_exit:
667 cifs_buf_release(pSMB);
669 cFYI(1, "negprot rc %d", rc);
670 return rc;
674 CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
676 struct smb_hdr *smb_buffer;
677 int rc = 0;
679 cFYI(1, "In tree disconnect");
681 /* BB: do we need to check this? These should never be NULL. */
682 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
683 return -EIO;
686 * No need to return error on this operation if tid invalidated and
687 * closed on server already e.g. due to tcp session crashing. Also,
688 * the tcon is no longer on the list, so no need to take lock before
689 * checking this.
691 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
692 return 0;
694 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
695 (void **)&smb_buffer);
696 if (rc)
697 return rc;
699 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
700 if (rc)
701 cFYI(1, "Tree disconnect failed %d", rc);
703 /* No need to return error on this operation if tid invalidated and
704 closed on server already e.g. due to tcp session crashing */
705 if (rc == -EAGAIN)
706 rc = 0;
708 return rc;
712 * This is a no-op for now. We're not really interested in the reply, but
713 * rather in the fact that the server sent one and that server->lstrp
714 * gets updated.
716 * FIXME: maybe we should consider checking that the reply matches request?
718 static void
719 cifs_echo_callback(struct mid_q_entry *mid)
721 struct TCP_Server_Info *server = mid->callback_data;
723 DeleteMidQEntry(mid);
724 atomic_dec(&server->inFlight);
725 wake_up(&server->request_q);
729 CIFSSMBEcho(struct TCP_Server_Info *server)
731 ECHO_REQ *smb;
732 int rc = 0;
733 struct kvec iov;
735 cFYI(1, "In echo request");
737 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
738 if (rc)
739 return rc;
741 /* set up echo request */
742 smb->hdr.Tid = 0xffff;
743 smb->hdr.WordCount = 1;
744 put_unaligned_le16(1, &smb->EchoCount);
745 put_bcc(1, &smb->hdr);
746 smb->Data[0] = 'a';
747 inc_rfc1001_len(smb, 3);
748 iov.iov_base = smb;
749 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
751 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
752 server, true);
753 if (rc)
754 cFYI(1, "Echo request failed: %d", rc);
756 cifs_small_buf_release(smb);
758 return rc;
762 CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
764 LOGOFF_ANDX_REQ *pSMB;
765 int rc = 0;
767 cFYI(1, "In SMBLogoff for session disconnect");
770 * BB: do we need to check validity of ses and server? They should
771 * always be valid since we have an active reference. If not, that
772 * should probably be a BUG()
774 if (!ses || !ses->server)
775 return -EIO;
777 mutex_lock(&ses->session_mutex);
778 if (ses->need_reconnect)
779 goto session_already_dead; /* no need to send SMBlogoff if uid
780 already closed due to reconnect */
781 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
782 if (rc) {
783 mutex_unlock(&ses->session_mutex);
784 return rc;
787 pSMB->hdr.Mid = GetNextMid(ses->server);
789 if (ses->server->sec_mode &
790 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
791 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
793 pSMB->hdr.Uid = ses->Suid;
795 pSMB->AndXCommand = 0xFF;
796 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
797 session_already_dead:
798 mutex_unlock(&ses->session_mutex);
800 /* if session dead then we do not need to do ulogoff,
801 since server closed smb session, no sense reporting
802 error */
803 if (rc == -EAGAIN)
804 rc = 0;
805 return rc;
809 CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
810 __u16 type, const struct nls_table *nls_codepage, int remap)
812 TRANSACTION2_SPI_REQ *pSMB = NULL;
813 TRANSACTION2_SPI_RSP *pSMBr = NULL;
814 struct unlink_psx_rq *pRqD;
815 int name_len;
816 int rc = 0;
817 int bytes_returned = 0;
818 __u16 params, param_offset, offset, byte_count;
820 cFYI(1, "In POSIX delete");
821 PsxDelete:
822 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
823 (void **) &pSMBr);
824 if (rc)
825 return rc;
827 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
828 name_len =
829 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
830 PATH_MAX, nls_codepage, remap);
831 name_len++; /* trailing null */
832 name_len *= 2;
833 } else { /* BB add path length overrun check */
834 name_len = strnlen(fileName, PATH_MAX);
835 name_len++; /* trailing null */
836 strncpy(pSMB->FileName, fileName, name_len);
839 params = 6 + name_len;
840 pSMB->MaxParameterCount = cpu_to_le16(2);
841 pSMB->MaxDataCount = 0; /* BB double check this with jra */
842 pSMB->MaxSetupCount = 0;
843 pSMB->Reserved = 0;
844 pSMB->Flags = 0;
845 pSMB->Timeout = 0;
846 pSMB->Reserved2 = 0;
847 param_offset = offsetof(struct smb_com_transaction2_spi_req,
848 InformationLevel) - 4;
849 offset = param_offset + params;
851 /* Setup pointer to Request Data (inode type) */
852 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
853 pRqD->type = cpu_to_le16(type);
854 pSMB->ParameterOffset = cpu_to_le16(param_offset);
855 pSMB->DataOffset = cpu_to_le16(offset);
856 pSMB->SetupCount = 1;
857 pSMB->Reserved3 = 0;
858 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
859 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
861 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
862 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
863 pSMB->ParameterCount = cpu_to_le16(params);
864 pSMB->TotalParameterCount = pSMB->ParameterCount;
865 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
866 pSMB->Reserved4 = 0;
867 inc_rfc1001_len(pSMB, byte_count);
868 pSMB->ByteCount = cpu_to_le16(byte_count);
869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
871 if (rc)
872 cFYI(1, "Posix delete returned %d", rc);
873 cifs_buf_release(pSMB);
875 cifs_stats_inc(&tcon->num_deletes);
877 if (rc == -EAGAIN)
878 goto PsxDelete;
880 return rc;
884 CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
885 const struct nls_table *nls_codepage, int remap)
887 DELETE_FILE_REQ *pSMB = NULL;
888 DELETE_FILE_RSP *pSMBr = NULL;
889 int rc = 0;
890 int bytes_returned;
891 int name_len;
893 DelFileRetry:
894 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
895 (void **) &pSMBr);
896 if (rc)
897 return rc;
899 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
900 name_len =
901 cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
902 PATH_MAX, nls_codepage, remap);
903 name_len++; /* trailing null */
904 name_len *= 2;
905 } else { /* BB improve check for buffer overruns BB */
906 name_len = strnlen(fileName, PATH_MAX);
907 name_len++; /* trailing null */
908 strncpy(pSMB->fileName, fileName, name_len);
910 pSMB->SearchAttributes =
911 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
912 pSMB->BufferFormat = 0x04;
913 inc_rfc1001_len(pSMB, name_len + 1);
914 pSMB->ByteCount = cpu_to_le16(name_len + 1);
915 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
916 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
917 cifs_stats_inc(&tcon->num_deletes);
918 if (rc)
919 cFYI(1, "Error in RMFile = %d", rc);
921 cifs_buf_release(pSMB);
922 if (rc == -EAGAIN)
923 goto DelFileRetry;
925 return rc;
929 CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
930 const struct nls_table *nls_codepage, int remap)
932 DELETE_DIRECTORY_REQ *pSMB = NULL;
933 DELETE_DIRECTORY_RSP *pSMBr = NULL;
934 int rc = 0;
935 int bytes_returned;
936 int name_len;
938 cFYI(1, "In CIFSSMBRmDir");
939 RmDirRetry:
940 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
941 (void **) &pSMBr);
942 if (rc)
943 return rc;
945 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
946 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName,
947 PATH_MAX, nls_codepage, remap);
948 name_len++; /* trailing null */
949 name_len *= 2;
950 } else { /* BB improve check for buffer overruns BB */
951 name_len = strnlen(dirName, PATH_MAX);
952 name_len++; /* trailing null */
953 strncpy(pSMB->DirName, dirName, name_len);
956 pSMB->BufferFormat = 0x04;
957 inc_rfc1001_len(pSMB, name_len + 1);
958 pSMB->ByteCount = cpu_to_le16(name_len + 1);
959 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
960 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
961 cifs_stats_inc(&tcon->num_rmdirs);
962 if (rc)
963 cFYI(1, "Error in RMDir = %d", rc);
965 cifs_buf_release(pSMB);
966 if (rc == -EAGAIN)
967 goto RmDirRetry;
968 return rc;
972 CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
973 const char *name, const struct nls_table *nls_codepage, int remap)
975 int rc = 0;
976 CREATE_DIRECTORY_REQ *pSMB = NULL;
977 CREATE_DIRECTORY_RSP *pSMBr = NULL;
978 int bytes_returned;
979 int name_len;
981 cFYI(1, "In CIFSSMBMkDir");
982 MkDirRetry:
983 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
984 (void **) &pSMBr);
985 if (rc)
986 return rc;
988 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
989 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
990 PATH_MAX, nls_codepage, remap);
991 name_len++; /* trailing null */
992 name_len *= 2;
993 } else { /* BB improve check for buffer overruns BB */
994 name_len = strnlen(name, PATH_MAX);
995 name_len++; /* trailing null */
996 strncpy(pSMB->DirName, name, name_len);
999 pSMB->BufferFormat = 0x04;
1000 inc_rfc1001_len(pSMB, name_len + 1);
1001 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1002 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1004 cifs_stats_inc(&tcon->num_mkdirs);
1005 if (rc)
1006 cFYI(1, "Error in Mkdir = %d", rc);
1008 cifs_buf_release(pSMB);
1009 if (rc == -EAGAIN)
1010 goto MkDirRetry;
1011 return rc;
1015 CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
1016 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
1017 __u32 *pOplock, const char *name,
1018 const struct nls_table *nls_codepage, int remap)
1020 TRANSACTION2_SPI_REQ *pSMB = NULL;
1021 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1022 int name_len;
1023 int rc = 0;
1024 int bytes_returned = 0;
1025 __u16 params, param_offset, offset, byte_count, count;
1026 OPEN_PSX_REQ *pdata;
1027 OPEN_PSX_RSP *psx_rsp;
1029 cFYI(1, "In POSIX Create");
1030 PsxCreat:
1031 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1032 (void **) &pSMBr);
1033 if (rc)
1034 return rc;
1036 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1037 name_len =
1038 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1039 PATH_MAX, nls_codepage, remap);
1040 name_len++; /* trailing null */
1041 name_len *= 2;
1042 } else { /* BB improve the check for buffer overruns BB */
1043 name_len = strnlen(name, PATH_MAX);
1044 name_len++; /* trailing null */
1045 strncpy(pSMB->FileName, name, name_len);
1048 params = 6 + name_len;
1049 count = sizeof(OPEN_PSX_REQ);
1050 pSMB->MaxParameterCount = cpu_to_le16(2);
1051 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1052 pSMB->MaxSetupCount = 0;
1053 pSMB->Reserved = 0;
1054 pSMB->Flags = 0;
1055 pSMB->Timeout = 0;
1056 pSMB->Reserved2 = 0;
1057 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1058 InformationLevel) - 4;
1059 offset = param_offset + params;
1060 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1061 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1062 pdata->Permissions = cpu_to_le64(mode);
1063 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1064 pdata->OpenFlags = cpu_to_le32(*pOplock);
1065 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1066 pSMB->DataOffset = cpu_to_le16(offset);
1067 pSMB->SetupCount = 1;
1068 pSMB->Reserved3 = 0;
1069 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1070 byte_count = 3 /* pad */ + params + count;
1072 pSMB->DataCount = cpu_to_le16(count);
1073 pSMB->ParameterCount = cpu_to_le16(params);
1074 pSMB->TotalDataCount = pSMB->DataCount;
1075 pSMB->TotalParameterCount = pSMB->ParameterCount;
1076 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1077 pSMB->Reserved4 = 0;
1078 inc_rfc1001_len(pSMB, byte_count);
1079 pSMB->ByteCount = cpu_to_le16(byte_count);
1080 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1081 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1082 if (rc) {
1083 cFYI(1, "Posix create returned %d", rc);
1084 goto psx_create_err;
1087 cFYI(1, "copying inode info");
1088 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1090 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
1091 rc = -EIO; /* bad smb */
1092 goto psx_create_err;
1095 /* copy return information to pRetData */
1096 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1097 + le16_to_cpu(pSMBr->t2.DataOffset));
1099 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1100 if (netfid)
1101 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1102 /* Let caller know file was created so we can set the mode. */
1103 /* Do we care about the CreateAction in any other cases? */
1104 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1105 *pOplock |= CIFS_CREATE_ACTION;
1106 /* check to make sure response data is there */
1107 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1108 pRetData->Type = cpu_to_le32(-1); /* unknown */
1109 cFYI(DBG2, "unknown type");
1110 } else {
1111 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
1112 + sizeof(FILE_UNIX_BASIC_INFO)) {
1113 cERROR(1, "Open response data too small");
1114 pRetData->Type = cpu_to_le32(-1);
1115 goto psx_create_err;
1117 memcpy((char *) pRetData,
1118 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1119 sizeof(FILE_UNIX_BASIC_INFO));
1122 psx_create_err:
1123 cifs_buf_release(pSMB);
1125 if (posix_flags & SMB_O_DIRECTORY)
1126 cifs_stats_inc(&tcon->num_posixmkdirs);
1127 else
1128 cifs_stats_inc(&tcon->num_posixopens);
1130 if (rc == -EAGAIN)
1131 goto PsxCreat;
1133 return rc;
1136 static __u16 convert_disposition(int disposition)
1138 __u16 ofun = 0;
1140 switch (disposition) {
1141 case FILE_SUPERSEDE:
1142 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1143 break;
1144 case FILE_OPEN:
1145 ofun = SMBOPEN_OAPPEND;
1146 break;
1147 case FILE_CREATE:
1148 ofun = SMBOPEN_OCREATE;
1149 break;
1150 case FILE_OPEN_IF:
1151 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1152 break;
1153 case FILE_OVERWRITE:
1154 ofun = SMBOPEN_OTRUNC;
1155 break;
1156 case FILE_OVERWRITE_IF:
1157 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1158 break;
1159 default:
1160 cFYI(1, "unknown disposition %d", disposition);
1161 ofun = SMBOPEN_OAPPEND; /* regular open */
1163 return ofun;
1166 static int
1167 access_flags_to_smbopen_mode(const int access_flags)
1169 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1171 if (masked_flags == GENERIC_READ)
1172 return SMBOPEN_READ;
1173 else if (masked_flags == GENERIC_WRITE)
1174 return SMBOPEN_WRITE;
1176 /* just go for read/write */
1177 return SMBOPEN_READWRITE;
1181 SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
1182 const char *fileName, const int openDisposition,
1183 const int access_flags, const int create_options, __u16 *netfid,
1184 int *pOplock, FILE_ALL_INFO *pfile_info,
1185 const struct nls_table *nls_codepage, int remap)
1187 int rc = -EACCES;
1188 OPENX_REQ *pSMB = NULL;
1189 OPENX_RSP *pSMBr = NULL;
1190 int bytes_returned;
1191 int name_len;
1192 __u16 count;
1194 OldOpenRetry:
1195 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1196 (void **) &pSMBr);
1197 if (rc)
1198 return rc;
1200 pSMB->AndXCommand = 0xFF; /* none */
1202 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1203 count = 1; /* account for one byte pad to word boundary */
1204 name_len =
1205 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1206 fileName, PATH_MAX, nls_codepage, remap);
1207 name_len++; /* trailing null */
1208 name_len *= 2;
1209 } else { /* BB improve check for buffer overruns BB */
1210 count = 0; /* no pad */
1211 name_len = strnlen(fileName, PATH_MAX);
1212 name_len++; /* trailing null */
1213 strncpy(pSMB->fileName, fileName, name_len);
1215 if (*pOplock & REQ_OPLOCK)
1216 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1217 else if (*pOplock & REQ_BATCHOPLOCK)
1218 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1220 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1221 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1222 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1223 /* set file as system file if special file such
1224 as fifo and server expecting SFU style and
1225 no Unix extensions */
1227 if (create_options & CREATE_OPTION_SPECIAL)
1228 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1229 else /* BB FIXME BB */
1230 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1232 if (create_options & CREATE_OPTION_READONLY)
1233 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1235 /* BB FIXME BB */
1236 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1237 CREATE_OPTIONS_MASK); */
1238 /* BB FIXME END BB */
1240 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1241 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1242 count += name_len;
1243 inc_rfc1001_len(pSMB, count);
1245 pSMB->ByteCount = cpu_to_le16(count);
1246 /* long_op set to 1 to allow for oplock break timeouts */
1247 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1248 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1249 cifs_stats_inc(&tcon->num_opens);
1250 if (rc) {
1251 cFYI(1, "Error in Open = %d", rc);
1252 } else {
1253 /* BB verify if wct == 15 */
1255 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1257 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1258 /* Let caller know file was created so we can set the mode. */
1259 /* Do we care about the CreateAction in any other cases? */
1260 /* BB FIXME BB */
1261 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1262 *pOplock |= CIFS_CREATE_ACTION; */
1263 /* BB FIXME END */
1265 if (pfile_info) {
1266 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1267 pfile_info->LastAccessTime = 0; /* BB fixme */
1268 pfile_info->LastWriteTime = 0; /* BB fixme */
1269 pfile_info->ChangeTime = 0; /* BB fixme */
1270 pfile_info->Attributes =
1271 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1272 /* the file_info buf is endian converted by caller */
1273 pfile_info->AllocationSize =
1274 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1275 pfile_info->EndOfFile = pfile_info->AllocationSize;
1276 pfile_info->NumberOfLinks = cpu_to_le32(1);
1277 pfile_info->DeletePending = 0;
1281 cifs_buf_release(pSMB);
1282 if (rc == -EAGAIN)
1283 goto OldOpenRetry;
1284 return rc;
1288 CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
1289 const char *fileName, const int openDisposition,
1290 const int access_flags, const int create_options, __u16 *netfid,
1291 int *pOplock, FILE_ALL_INFO *pfile_info,
1292 const struct nls_table *nls_codepage, int remap)
1294 int rc = -EACCES;
1295 OPEN_REQ *pSMB = NULL;
1296 OPEN_RSP *pSMBr = NULL;
1297 int bytes_returned;
1298 int name_len;
1299 __u16 count;
1301 openRetry:
1302 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1303 (void **) &pSMBr);
1304 if (rc)
1305 return rc;
1307 pSMB->AndXCommand = 0xFF; /* none */
1309 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1310 count = 1; /* account for one byte pad to word boundary */
1311 name_len =
1312 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1313 fileName, PATH_MAX, nls_codepage, remap);
1314 name_len++; /* trailing null */
1315 name_len *= 2;
1316 pSMB->NameLength = cpu_to_le16(name_len);
1317 } else { /* BB improve check for buffer overruns BB */
1318 count = 0; /* no pad */
1319 name_len = strnlen(fileName, PATH_MAX);
1320 name_len++; /* trailing null */
1321 pSMB->NameLength = cpu_to_le16(name_len);
1322 strncpy(pSMB->fileName, fileName, name_len);
1324 if (*pOplock & REQ_OPLOCK)
1325 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1326 else if (*pOplock & REQ_BATCHOPLOCK)
1327 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1328 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1329 pSMB->AllocationSize = 0;
1330 /* set file as system file if special file such
1331 as fifo and server expecting SFU style and
1332 no Unix extensions */
1333 if (create_options & CREATE_OPTION_SPECIAL)
1334 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1335 else
1336 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1338 /* XP does not handle ATTR_POSIX_SEMANTICS */
1339 /* but it helps speed up case sensitive checks for other
1340 servers such as Samba */
1341 if (tcon->ses->capabilities & CAP_UNIX)
1342 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1344 if (create_options & CREATE_OPTION_READONLY)
1345 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1347 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1348 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1349 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1350 /* BB Expirement with various impersonation levels and verify */
1351 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1352 pSMB->SecurityFlags =
1353 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1355 count += name_len;
1356 inc_rfc1001_len(pSMB, count);
1358 pSMB->ByteCount = cpu_to_le16(count);
1359 /* long_op set to 1 to allow for oplock break timeouts */
1360 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1361 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1362 cifs_stats_inc(&tcon->num_opens);
1363 if (rc) {
1364 cFYI(1, "Error in Open = %d", rc);
1365 } else {
1366 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1367 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1368 /* Let caller know file was created so we can set the mode. */
1369 /* Do we care about the CreateAction in any other cases? */
1370 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1371 *pOplock |= CIFS_CREATE_ACTION;
1372 if (pfile_info) {
1373 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1374 36 /* CreationTime to Attributes */);
1375 /* the file_info buf is endian converted by caller */
1376 pfile_info->AllocationSize = pSMBr->AllocationSize;
1377 pfile_info->EndOfFile = pSMBr->EndOfFile;
1378 pfile_info->NumberOfLinks = cpu_to_le32(1);
1379 pfile_info->DeletePending = 0;
1383 cifs_buf_release(pSMB);
1384 if (rc == -EAGAIN)
1385 goto openRetry;
1386 return rc;
1389 struct cifs_readdata *
1390 cifs_readdata_alloc(unsigned int nr_pages)
1392 struct cifs_readdata *rdata;
1394 /* readdata + 1 kvec for each page */
1395 rdata = kzalloc(sizeof(*rdata) +
1396 sizeof(struct kvec) * nr_pages, GFP_KERNEL);
1397 if (rdata != NULL) {
1398 INIT_WORK(&rdata->work, cifs_readv_complete);
1399 INIT_LIST_HEAD(&rdata->pages);
1401 return rdata;
1404 void
1405 cifs_readdata_free(struct cifs_readdata *rdata)
1407 cifsFileInfo_put(rdata->cfile);
1408 kfree(rdata);
1412 * Discard any remaining data in the current SMB. To do this, we borrow the
1413 * current bigbuf.
1415 static int
1416 cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1418 READ_RSP *rsp = (READ_RSP *)server->smallbuf;
1419 unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length);
1420 int remaining = rfclen + 4 - server->total_read;
1421 struct cifs_readdata *rdata = mid->callback_data;
1423 while (remaining > 0) {
1424 int length;
1426 length = cifs_read_from_socket(server, server->bigbuf,
1427 min_t(unsigned int, remaining,
1428 CIFSMaxBufSize + MAX_CIFS_HDR_SIZE));
1429 if (length < 0)
1430 return length;
1431 server->total_read += length;
1432 remaining -= length;
1435 dequeue_mid(mid, rdata->result);
1436 return 0;
1439 static int
1440 cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1442 int length, len;
1443 unsigned int data_offset, remaining, data_len;
1444 struct cifs_readdata *rdata = mid->callback_data;
1445 READ_RSP *rsp = (READ_RSP *)server->smallbuf;
1446 unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length) + 4;
1447 u64 eof;
1448 pgoff_t eof_index;
1449 struct page *page, *tpage;
1451 cFYI(1, "%s: mid=%u offset=%llu bytes=%u", __func__,
1452 mid->mid, rdata->offset, rdata->bytes);
1455 * read the rest of READ_RSP header (sans Data array), or whatever we
1456 * can if there's not enough data. At this point, we've read down to
1457 * the Mid.
1459 len = min_t(unsigned int, rfclen, sizeof(*rsp)) -
1460 sizeof(struct smb_hdr) + 1;
1462 rdata->iov[0].iov_base = server->smallbuf + sizeof(struct smb_hdr) - 1;
1463 rdata->iov[0].iov_len = len;
1465 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1466 if (length < 0)
1467 return length;
1468 server->total_read += length;
1470 /* Was the SMB read successful? */
1471 rdata->result = map_smb_to_linux_error(&rsp->hdr, false);
1472 if (rdata->result != 0) {
1473 cFYI(1, "%s: server returned error %d", __func__,
1474 rdata->result);
1475 return cifs_readv_discard(server, mid);
1478 /* Is there enough to get to the rest of the READ_RSP header? */
1479 if (server->total_read < sizeof(READ_RSP)) {
1480 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
1481 __func__, server->total_read, sizeof(READ_RSP));
1482 rdata->result = -EIO;
1483 return cifs_readv_discard(server, mid);
1486 data_offset = le16_to_cpu(rsp->DataOffset) + 4;
1487 if (data_offset < server->total_read) {
1489 * win2k8 sometimes sends an offset of 0 when the read
1490 * is beyond the EOF. Treat it as if the data starts just after
1491 * the header.
1493 cFYI(1, "%s: data offset (%u) inside read response header",
1494 __func__, data_offset);
1495 data_offset = server->total_read;
1496 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1497 /* data_offset is beyond the end of smallbuf */
1498 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1499 __func__, data_offset);
1500 rdata->result = -EIO;
1501 return cifs_readv_discard(server, mid);
1504 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1505 server->total_read, data_offset);
1507 len = data_offset - server->total_read;
1508 if (len > 0) {
1509 /* read any junk before data into the rest of smallbuf */
1510 rdata->iov[0].iov_base = server->smallbuf + server->total_read;
1511 rdata->iov[0].iov_len = len;
1512 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1513 if (length < 0)
1514 return length;
1515 server->total_read += length;
1518 /* set up first iov for signature check */
1519 rdata->iov[0].iov_base = server->smallbuf;
1520 rdata->iov[0].iov_len = server->total_read;
1521 cFYI(1, "0: iov_base=%p iov_len=%zu",
1522 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1524 /* how much data is in the response? */
1525 data_len = le16_to_cpu(rsp->DataLengthHigh) << 16;
1526 data_len += le16_to_cpu(rsp->DataLength);
1527 if (data_offset + data_len > rfclen) {
1528 /* data_len is corrupt -- discard frame */
1529 rdata->result = -EIO;
1530 return cifs_readv_discard(server, mid);
1533 /* marshal up the page array */
1534 len = 0;
1535 remaining = data_len;
1536 rdata->nr_iov = 1;
1538 /* determine the eof that the server (probably) has */
1539 eof = CIFS_I(rdata->mapping->host)->server_eof;
1540 eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
1541 cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
1543 list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
1544 if (remaining >= PAGE_CACHE_SIZE) {
1545 /* enough data to fill the page */
1546 rdata->iov[rdata->nr_iov].iov_base = kmap(page);
1547 rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE;
1548 cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
1549 rdata->nr_iov, page->index,
1550 rdata->iov[rdata->nr_iov].iov_base,
1551 rdata->iov[rdata->nr_iov].iov_len);
1552 ++rdata->nr_iov;
1553 len += PAGE_CACHE_SIZE;
1554 remaining -= PAGE_CACHE_SIZE;
1555 } else if (remaining > 0) {
1556 /* enough for partial page, fill and zero the rest */
1557 rdata->iov[rdata->nr_iov].iov_base = kmap(page);
1558 rdata->iov[rdata->nr_iov].iov_len = remaining;
1559 cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
1560 rdata->nr_iov, page->index,
1561 rdata->iov[rdata->nr_iov].iov_base,
1562 rdata->iov[rdata->nr_iov].iov_len);
1563 memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
1564 '\0', PAGE_CACHE_SIZE - remaining);
1565 ++rdata->nr_iov;
1566 len += remaining;
1567 remaining = 0;
1568 } else if (page->index > eof_index) {
1570 * The VFS will not try to do readahead past the
1571 * i_size, but it's possible that we have outstanding
1572 * writes with gaps in the middle and the i_size hasn't
1573 * caught up yet. Populate those with zeroed out pages
1574 * to prevent the VFS from repeatedly attempting to
1575 * fill them until the writes are flushed.
1577 zero_user(page, 0, PAGE_CACHE_SIZE);
1578 list_del(&page->lru);
1579 lru_cache_add_file(page);
1580 flush_dcache_page(page);
1581 SetPageUptodate(page);
1582 unlock_page(page);
1583 page_cache_release(page);
1584 } else {
1585 /* no need to hold page hostage */
1586 list_del(&page->lru);
1587 lru_cache_add_file(page);
1588 unlock_page(page);
1589 page_cache_release(page);
1593 /* issue the read if we have any iovecs left to fill */
1594 if (rdata->nr_iov > 1) {
1595 length = cifs_readv_from_socket(server, &rdata->iov[1],
1596 rdata->nr_iov - 1, len);
1597 if (length < 0)
1598 return length;
1599 server->total_read += length;
1600 } else {
1601 length = 0;
1604 rdata->bytes = length;
1606 cFYI(1, "total_read=%u rfclen=%u remaining=%u", server->total_read,
1607 rfclen, remaining);
1609 /* discard anything left over */
1610 if (server->total_read < rfclen)
1611 return cifs_readv_discard(server, mid);
1613 dequeue_mid(mid, false);
1614 return length;
1617 static void
1618 cifs_readv_complete(struct work_struct *work)
1620 struct cifs_readdata *rdata = container_of(work,
1621 struct cifs_readdata, work);
1622 struct page *page, *tpage;
1624 list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
1625 list_del(&page->lru);
1626 lru_cache_add_file(page);
1628 if (rdata->result == 0) {
1629 kunmap(page);
1630 flush_dcache_page(page);
1631 SetPageUptodate(page);
1634 unlock_page(page);
1636 if (rdata->result == 0)
1637 cifs_readpage_to_fscache(rdata->mapping->host, page);
1639 page_cache_release(page);
1641 cifs_readdata_free(rdata);
1644 static void
1645 cifs_readv_callback(struct mid_q_entry *mid)
1647 struct cifs_readdata *rdata = mid->callback_data;
1648 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1649 struct TCP_Server_Info *server = tcon->ses->server;
1651 cFYI(1, "%s: mid=%u state=%d result=%d bytes=%u", __func__,
1652 mid->mid, mid->midState, rdata->result, rdata->bytes);
1654 switch (mid->midState) {
1655 case MID_RESPONSE_RECEIVED:
1656 /* result already set, check signature */
1657 if (server->sec_mode &
1658 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1659 if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
1660 server, mid->sequence_number + 1))
1661 cERROR(1, "Unexpected SMB signature");
1663 /* FIXME: should this be counted toward the initiating task? */
1664 task_io_account_read(rdata->bytes);
1665 cifs_stats_bytes_read(tcon, rdata->bytes);
1666 break;
1667 case MID_REQUEST_SUBMITTED:
1668 case MID_RETRY_NEEDED:
1669 rdata->result = -EAGAIN;
1670 break;
1671 default:
1672 rdata->result = -EIO;
1675 queue_work(system_nrt_wq, &rdata->work);
1676 DeleteMidQEntry(mid);
1677 atomic_dec(&server->inFlight);
1678 wake_up(&server->request_q);
1681 /* cifs_async_readv - send an async write, and set up mid to handle result */
1683 cifs_async_readv(struct cifs_readdata *rdata)
1685 int rc;
1686 READ_REQ *smb = NULL;
1687 int wct;
1688 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1690 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1691 rdata->offset, rdata->bytes);
1693 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1694 wct = 12;
1695 else {
1696 wct = 10; /* old style read */
1697 if ((rdata->offset >> 32) > 0) {
1698 /* can not handle this big offset for old */
1699 return -EIO;
1703 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1704 if (rc)
1705 return rc;
1707 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1708 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1710 smb->AndXCommand = 0xFF; /* none */
1711 smb->Fid = rdata->cfile->netfid;
1712 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1713 if (wct == 12)
1714 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1715 smb->Remaining = 0;
1716 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1717 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1718 if (wct == 12)
1719 smb->ByteCount = 0;
1720 else {
1721 /* old style read */
1722 struct smb_com_readx_req *smbr =
1723 (struct smb_com_readx_req *)smb;
1724 smbr->ByteCount = 0;
1727 /* 4 for RFC1001 length + 1 for BCC */
1728 rdata->iov[0].iov_base = smb;
1729 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1731 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1732 cifs_readv_receive, cifs_readv_callback,
1733 rdata, false);
1735 if (rc == 0)
1736 cifs_stats_inc(&tcon->num_reads);
1738 cifs_small_buf_release(smb);
1739 return rc;
1743 CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
1744 char **buf, int *pbuf_type)
1746 int rc = -EACCES;
1747 READ_REQ *pSMB = NULL;
1748 READ_RSP *pSMBr = NULL;
1749 char *pReadData = NULL;
1750 int wct;
1751 int resp_buf_type = 0;
1752 struct kvec iov[1];
1753 __u32 pid = io_parms->pid;
1754 __u16 netfid = io_parms->netfid;
1755 __u64 offset = io_parms->offset;
1756 struct cifs_tcon *tcon = io_parms->tcon;
1757 unsigned int count = io_parms->length;
1759 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
1760 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1761 wct = 12;
1762 else {
1763 wct = 10; /* old style read */
1764 if ((offset >> 32) > 0) {
1765 /* can not handle this big offset for old */
1766 return -EIO;
1770 *nbytes = 0;
1771 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1772 if (rc)
1773 return rc;
1775 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1776 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1778 /* tcon and ses pointer are checked in smb_init */
1779 if (tcon->ses->server == NULL)
1780 return -ECONNABORTED;
1782 pSMB->AndXCommand = 0xFF; /* none */
1783 pSMB->Fid = netfid;
1784 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1785 if (wct == 12)
1786 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1788 pSMB->Remaining = 0;
1789 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1790 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1791 if (wct == 12)
1792 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1793 else {
1794 /* old style read */
1795 struct smb_com_readx_req *pSMBW =
1796 (struct smb_com_readx_req *)pSMB;
1797 pSMBW->ByteCount = 0;
1800 iov[0].iov_base = (char *)pSMB;
1801 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
1802 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1803 &resp_buf_type, CIFS_LOG_ERROR);
1804 cifs_stats_inc(&tcon->num_reads);
1805 pSMBr = (READ_RSP *)iov[0].iov_base;
1806 if (rc) {
1807 cERROR(1, "Send error in read = %d", rc);
1808 } else {
1809 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1810 data_length = data_length << 16;
1811 data_length += le16_to_cpu(pSMBr->DataLength);
1812 *nbytes = data_length;
1814 /*check that DataLength would not go beyond end of SMB */
1815 if ((data_length > CIFSMaxBufSize)
1816 || (data_length > count)) {
1817 cFYI(1, "bad length %d for count %d",
1818 data_length, count);
1819 rc = -EIO;
1820 *nbytes = 0;
1821 } else {
1822 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1823 le16_to_cpu(pSMBr->DataOffset);
1824 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1825 cERROR(1, "Faulting on read rc = %d",rc);
1826 rc = -EFAULT;
1827 }*/ /* can not use copy_to_user when using page cache*/
1828 if (*buf)
1829 memcpy(*buf, pReadData, data_length);
1833 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1834 if (*buf) {
1835 if (resp_buf_type == CIFS_SMALL_BUFFER)
1836 cifs_small_buf_release(iov[0].iov_base);
1837 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1838 cifs_buf_release(iov[0].iov_base);
1839 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1840 /* return buffer to caller to free */
1841 *buf = iov[0].iov_base;
1842 if (resp_buf_type == CIFS_SMALL_BUFFER)
1843 *pbuf_type = CIFS_SMALL_BUFFER;
1844 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1845 *pbuf_type = CIFS_LARGE_BUFFER;
1846 } /* else no valid buffer on return - leave as null */
1848 /* Note: On -EAGAIN error only caller can retry on handle based calls
1849 since file handle passed in no longer valid */
1850 return rc;
1855 CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1856 unsigned int *nbytes, const char *buf,
1857 const char __user *ubuf, const int long_op)
1859 int rc = -EACCES;
1860 WRITE_REQ *pSMB = NULL;
1861 WRITE_RSP *pSMBr = NULL;
1862 int bytes_returned, wct;
1863 __u32 bytes_sent;
1864 __u16 byte_count;
1865 __u32 pid = io_parms->pid;
1866 __u16 netfid = io_parms->netfid;
1867 __u64 offset = io_parms->offset;
1868 struct cifs_tcon *tcon = io_parms->tcon;
1869 unsigned int count = io_parms->length;
1871 *nbytes = 0;
1873 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
1874 if (tcon->ses == NULL)
1875 return -ECONNABORTED;
1877 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1878 wct = 14;
1879 else {
1880 wct = 12;
1881 if ((offset >> 32) > 0) {
1882 /* can not handle big offset for old srv */
1883 return -EIO;
1887 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1888 (void **) &pSMBr);
1889 if (rc)
1890 return rc;
1892 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1893 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1895 /* tcon and ses pointer are checked in smb_init */
1896 if (tcon->ses->server == NULL)
1897 return -ECONNABORTED;
1899 pSMB->AndXCommand = 0xFF; /* none */
1900 pSMB->Fid = netfid;
1901 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1902 if (wct == 14)
1903 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1905 pSMB->Reserved = 0xFFFFFFFF;
1906 pSMB->WriteMode = 0;
1907 pSMB->Remaining = 0;
1909 /* Can increase buffer size if buffer is big enough in some cases ie we
1910 can send more if LARGE_WRITE_X capability returned by the server and if
1911 our buffer is big enough or if we convert to iovecs on socket writes
1912 and eliminate the copy to the CIFS buffer */
1913 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1914 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1915 } else {
1916 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1917 & ~0xFF;
1920 if (bytes_sent > count)
1921 bytes_sent = count;
1922 pSMB->DataOffset =
1923 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1924 if (buf)
1925 memcpy(pSMB->Data, buf, bytes_sent);
1926 else if (ubuf) {
1927 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1928 cifs_buf_release(pSMB);
1929 return -EFAULT;
1931 } else if (count != 0) {
1932 /* No buffer */
1933 cifs_buf_release(pSMB);
1934 return -EINVAL;
1935 } /* else setting file size with write of zero bytes */
1936 if (wct == 14)
1937 byte_count = bytes_sent + 1; /* pad */
1938 else /* wct == 12 */
1939 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1941 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1942 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1943 inc_rfc1001_len(pSMB, byte_count);
1945 if (wct == 14)
1946 pSMB->ByteCount = cpu_to_le16(byte_count);
1947 else { /* old style write has byte count 4 bytes earlier
1948 so 4 bytes pad */
1949 struct smb_com_writex_req *pSMBW =
1950 (struct smb_com_writex_req *)pSMB;
1951 pSMBW->ByteCount = cpu_to_le16(byte_count);
1954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1955 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1956 cifs_stats_inc(&tcon->num_writes);
1957 if (rc) {
1958 cFYI(1, "Send error in write = %d", rc);
1959 } else {
1960 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1961 *nbytes = (*nbytes) << 16;
1962 *nbytes += le16_to_cpu(pSMBr->Count);
1965 * Mask off high 16 bits when bytes written as returned by the
1966 * server is greater than bytes requested by the client. Some
1967 * OS/2 servers are known to set incorrect CountHigh values.
1969 if (*nbytes > count)
1970 *nbytes &= 0xFFFF;
1973 cifs_buf_release(pSMB);
1975 /* Note: On -EAGAIN error only caller can retry on handle based calls
1976 since file handle passed in no longer valid */
1978 return rc;
1981 void
1982 cifs_writedata_release(struct kref *refcount)
1984 struct cifs_writedata *wdata = container_of(refcount,
1985 struct cifs_writedata, refcount);
1987 if (wdata->cfile)
1988 cifsFileInfo_put(wdata->cfile);
1990 kfree(wdata);
1994 * Write failed with a retryable error. Resend the write request. It's also
1995 * possible that the page was redirtied so re-clean the page.
1997 static void
1998 cifs_writev_requeue(struct cifs_writedata *wdata)
2000 int i, rc;
2001 struct inode *inode = wdata->cfile->dentry->d_inode;
2003 for (i = 0; i < wdata->nr_pages; i++) {
2004 lock_page(wdata->pages[i]);
2005 clear_page_dirty_for_io(wdata->pages[i]);
2008 do {
2009 rc = cifs_async_writev(wdata);
2010 } while (rc == -EAGAIN);
2012 for (i = 0; i < wdata->nr_pages; i++) {
2013 if (rc != 0)
2014 SetPageError(wdata->pages[i]);
2015 unlock_page(wdata->pages[i]);
2018 mapping_set_error(inode->i_mapping, rc);
2019 kref_put(&wdata->refcount, cifs_writedata_release);
2022 static void
2023 cifs_writev_complete(struct work_struct *work)
2025 struct cifs_writedata *wdata = container_of(work,
2026 struct cifs_writedata, work);
2027 struct inode *inode = wdata->cfile->dentry->d_inode;
2028 int i = 0;
2030 if (wdata->result == 0) {
2031 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
2032 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2033 wdata->bytes);
2034 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2035 return cifs_writev_requeue(wdata);
2037 for (i = 0; i < wdata->nr_pages; i++) {
2038 struct page *page = wdata->pages[i];
2039 if (wdata->result == -EAGAIN)
2040 __set_page_dirty_nobuffers(page);
2041 else if (wdata->result < 0)
2042 SetPageError(page);
2043 end_page_writeback(page);
2044 page_cache_release(page);
2046 if (wdata->result != -EAGAIN)
2047 mapping_set_error(inode->i_mapping, wdata->result);
2048 kref_put(&wdata->refcount, cifs_writedata_release);
2051 struct cifs_writedata *
2052 cifs_writedata_alloc(unsigned int nr_pages)
2054 struct cifs_writedata *wdata;
2056 /* this would overflow */
2057 if (nr_pages == 0) {
2058 cERROR(1, "%s: called with nr_pages == 0!", __func__);
2059 return NULL;
2062 /* writedata + number of page pointers */
2063 wdata = kzalloc(sizeof(*wdata) +
2064 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
2065 if (wdata != NULL) {
2066 INIT_WORK(&wdata->work, cifs_writev_complete);
2067 kref_init(&wdata->refcount);
2069 return wdata;
2073 * Check the midState and signature on received buffer (if any), and queue the
2074 * workqueue completion task.
2076 static void
2077 cifs_writev_callback(struct mid_q_entry *mid)
2079 struct cifs_writedata *wdata = mid->callback_data;
2080 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
2081 unsigned int written;
2082 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2084 switch (mid->midState) {
2085 case MID_RESPONSE_RECEIVED:
2086 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2087 if (wdata->result != 0)
2088 break;
2090 written = le16_to_cpu(smb->CountHigh);
2091 written <<= 16;
2092 written += le16_to_cpu(smb->Count);
2094 * Mask off high 16 bits when bytes written as returned
2095 * by the server is greater than bytes requested by the
2096 * client. OS/2 servers are known to set incorrect
2097 * CountHigh values.
2099 if (written > wdata->bytes)
2100 written &= 0xFFFF;
2102 if (written < wdata->bytes)
2103 wdata->result = -ENOSPC;
2104 else
2105 wdata->bytes = written;
2106 break;
2107 case MID_REQUEST_SUBMITTED:
2108 case MID_RETRY_NEEDED:
2109 wdata->result = -EAGAIN;
2110 break;
2111 default:
2112 wdata->result = -EIO;
2113 break;
2116 queue_work(system_nrt_wq, &wdata->work);
2117 DeleteMidQEntry(mid);
2118 atomic_dec(&tcon->ses->server->inFlight);
2119 wake_up(&tcon->ses->server->request_q);
2122 /* cifs_async_writev - send an async write, and set up mid to handle result */
2124 cifs_async_writev(struct cifs_writedata *wdata)
2126 int i, rc = -EACCES;
2127 WRITE_REQ *smb = NULL;
2128 int wct;
2129 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
2130 struct inode *inode = wdata->cfile->dentry->d_inode;
2131 struct kvec *iov = NULL;
2133 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2134 wct = 14;
2135 } else {
2136 wct = 12;
2137 if (wdata->offset >> 32 > 0) {
2138 /* can not handle big offset for old srv */
2139 return -EIO;
2143 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2144 if (rc)
2145 goto async_writev_out;
2147 /* 1 iov per page + 1 for header */
2148 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2149 if (iov == NULL) {
2150 rc = -ENOMEM;
2151 goto async_writev_out;
2154 smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
2155 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
2157 smb->AndXCommand = 0xFF; /* none */
2158 smb->Fid = wdata->cfile->netfid;
2159 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2160 if (wct == 14)
2161 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2162 smb->Reserved = 0xFFFFFFFF;
2163 smb->WriteMode = 0;
2164 smb->Remaining = 0;
2166 smb->DataOffset =
2167 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2169 /* 4 for RFC1001 length + 1 for BCC */
2170 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2171 iov[0].iov_base = smb;
2173 /* marshal up the pages into iov array */
2174 wdata->bytes = 0;
2175 for (i = 0; i < wdata->nr_pages; i++) {
2176 iov[i + 1].iov_len = min(inode->i_size -
2177 page_offset(wdata->pages[i]),
2178 (loff_t)PAGE_CACHE_SIZE);
2179 iov[i + 1].iov_base = kmap(wdata->pages[i]);
2180 wdata->bytes += iov[i + 1].iov_len;
2183 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2185 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2186 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2188 if (wct == 14) {
2189 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2190 put_bcc(wdata->bytes + 1, &smb->hdr);
2191 } else {
2192 /* wct == 12 */
2193 struct smb_com_writex_req *smbw =
2194 (struct smb_com_writex_req *)smb;
2195 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2196 put_bcc(wdata->bytes + 5, &smbw->hdr);
2197 iov[0].iov_len += 4; /* pad bigger by four bytes */
2200 kref_get(&wdata->refcount);
2201 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
2202 NULL, cifs_writev_callback, wdata, false);
2204 if (rc == 0)
2205 cifs_stats_inc(&tcon->num_writes);
2206 else
2207 kref_put(&wdata->refcount, cifs_writedata_release);
2209 /* send is done, unmap pages */
2210 for (i = 0; i < wdata->nr_pages; i++)
2211 kunmap(wdata->pages[i]);
2213 async_writev_out:
2214 cifs_small_buf_release(smb);
2215 kfree(iov);
2216 return rc;
2220 CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
2221 unsigned int *nbytes, struct kvec *iov, int n_vec,
2222 const int long_op)
2224 int rc = -EACCES;
2225 WRITE_REQ *pSMB = NULL;
2226 int wct;
2227 int smb_hdr_len;
2228 int resp_buf_type = 0;
2229 __u32 pid = io_parms->pid;
2230 __u16 netfid = io_parms->netfid;
2231 __u64 offset = io_parms->offset;
2232 struct cifs_tcon *tcon = io_parms->tcon;
2233 unsigned int count = io_parms->length;
2235 *nbytes = 0;
2237 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
2239 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2240 wct = 14;
2241 } else {
2242 wct = 12;
2243 if ((offset >> 32) > 0) {
2244 /* can not handle big offset for old srv */
2245 return -EIO;
2248 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
2249 if (rc)
2250 return rc;
2252 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2253 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2255 /* tcon and ses pointer are checked in smb_init */
2256 if (tcon->ses->server == NULL)
2257 return -ECONNABORTED;
2259 pSMB->AndXCommand = 0xFF; /* none */
2260 pSMB->Fid = netfid;
2261 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
2262 if (wct == 14)
2263 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
2264 pSMB->Reserved = 0xFFFFFFFF;
2265 pSMB->WriteMode = 0;
2266 pSMB->Remaining = 0;
2268 pSMB->DataOffset =
2269 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2271 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2272 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
2273 /* header + 1 byte pad */
2274 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
2275 if (wct == 14)
2276 inc_rfc1001_len(pSMB, count + 1);
2277 else /* wct == 12 */
2278 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
2279 if (wct == 14)
2280 pSMB->ByteCount = cpu_to_le16(count + 1);
2281 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
2282 struct smb_com_writex_req *pSMBW =
2283 (struct smb_com_writex_req *)pSMB;
2284 pSMBW->ByteCount = cpu_to_le16(count + 5);
2286 iov[0].iov_base = pSMB;
2287 if (wct == 14)
2288 iov[0].iov_len = smb_hdr_len + 4;
2289 else /* wct == 12 pad bigger by four bytes */
2290 iov[0].iov_len = smb_hdr_len + 8;
2293 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
2294 long_op);
2295 cifs_stats_inc(&tcon->num_writes);
2296 if (rc) {
2297 cFYI(1, "Send error Write2 = %d", rc);
2298 } else if (resp_buf_type == 0) {
2299 /* presumably this can not happen, but best to be safe */
2300 rc = -EIO;
2301 } else {
2302 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
2303 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2304 *nbytes = (*nbytes) << 16;
2305 *nbytes += le16_to_cpu(pSMBr->Count);
2308 * Mask off high 16 bits when bytes written as returned by the
2309 * server is greater than bytes requested by the client. OS/2
2310 * servers are known to set incorrect CountHigh values.
2312 if (*nbytes > count)
2313 *nbytes &= 0xFFFF;
2316 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2317 if (resp_buf_type == CIFS_SMALL_BUFFER)
2318 cifs_small_buf_release(iov[0].iov_base);
2319 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2320 cifs_buf_release(iov[0].iov_base);
2322 /* Note: On -EAGAIN error only caller can retry on handle based calls
2323 since file handle passed in no longer valid */
2325 return rc;
2328 int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
2329 const __u8 lock_type, const __u32 num_unlock,
2330 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2332 int rc = 0;
2333 LOCK_REQ *pSMB = NULL;
2334 struct kvec iov[2];
2335 int resp_buf_type;
2336 __u16 count;
2338 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2340 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2341 if (rc)
2342 return rc;
2344 pSMB->Timeout = 0;
2345 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2346 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2347 pSMB->LockType = lock_type;
2348 pSMB->AndXCommand = 0xFF; /* none */
2349 pSMB->Fid = netfid; /* netfid stays le */
2351 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2352 inc_rfc1001_len(pSMB, count);
2353 pSMB->ByteCount = cpu_to_le16(count);
2355 iov[0].iov_base = (char *)pSMB;
2356 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2357 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2358 iov[1].iov_base = (char *)buf;
2359 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2361 cifs_stats_inc(&tcon->num_locks);
2362 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2363 if (rc)
2364 cFYI(1, "Send error in cifs_lockv = %d", rc);
2366 return rc;
2370 CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
2371 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
2372 const __u64 offset, const __u32 numUnlock,
2373 const __u32 numLock, const __u8 lockType,
2374 const bool waitFlag, const __u8 oplock_level)
2376 int rc = 0;
2377 LOCK_REQ *pSMB = NULL;
2378 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
2379 int bytes_returned;
2380 int timeout = 0;
2381 __u16 count;
2383 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
2384 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2386 if (rc)
2387 return rc;
2389 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
2390 timeout = CIFS_ASYNC_OP; /* no response expected */
2391 pSMB->Timeout = 0;
2392 } else if (waitFlag) {
2393 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2394 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2395 } else {
2396 pSMB->Timeout = 0;
2399 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2400 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2401 pSMB->LockType = lockType;
2402 pSMB->OplockLevel = oplock_level;
2403 pSMB->AndXCommand = 0xFF; /* none */
2404 pSMB->Fid = smb_file_id; /* netfid stays le */
2406 if ((numLock != 0) || (numUnlock != 0)) {
2407 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
2408 /* BB where to store pid high? */
2409 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2410 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2411 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2412 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2413 count = sizeof(LOCKING_ANDX_RANGE);
2414 } else {
2415 /* oplock break */
2416 count = 0;
2418 inc_rfc1001_len(pSMB, count);
2419 pSMB->ByteCount = cpu_to_le16(count);
2421 if (waitFlag) {
2422 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2423 (struct smb_hdr *) pSMB, &bytes_returned);
2424 cifs_small_buf_release(pSMB);
2425 } else {
2426 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
2427 timeout);
2428 /* SMB buffer freed by function above */
2430 cifs_stats_inc(&tcon->num_locks);
2431 if (rc)
2432 cFYI(1, "Send error in Lock = %d", rc);
2434 /* Note: On -EAGAIN error only caller can retry on handle based calls
2435 since file handle passed in no longer valid */
2436 return rc;
2440 CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
2441 const __u16 smb_file_id, const __u32 netpid, const int get_flag,
2442 const __u64 len, struct file_lock *pLockData,
2443 const __u16 lock_type, const bool waitFlag)
2445 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2446 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2447 struct cifs_posix_lock *parm_data;
2448 int rc = 0;
2449 int timeout = 0;
2450 int bytes_returned = 0;
2451 int resp_buf_type = 0;
2452 __u16 params, param_offset, offset, byte_count, count;
2453 struct kvec iov[1];
2455 cFYI(1, "Posix Lock");
2457 if (pLockData == NULL)
2458 return -EINVAL;
2460 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2462 if (rc)
2463 return rc;
2465 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2467 params = 6;
2468 pSMB->MaxSetupCount = 0;
2469 pSMB->Reserved = 0;
2470 pSMB->Flags = 0;
2471 pSMB->Reserved2 = 0;
2472 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2473 offset = param_offset + params;
2475 count = sizeof(struct cifs_posix_lock);
2476 pSMB->MaxParameterCount = cpu_to_le16(2);
2477 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2478 pSMB->SetupCount = 1;
2479 pSMB->Reserved3 = 0;
2480 if (get_flag)
2481 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2482 else
2483 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2484 byte_count = 3 /* pad */ + params + count;
2485 pSMB->DataCount = cpu_to_le16(count);
2486 pSMB->ParameterCount = cpu_to_le16(params);
2487 pSMB->TotalDataCount = pSMB->DataCount;
2488 pSMB->TotalParameterCount = pSMB->ParameterCount;
2489 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2490 parm_data = (struct cifs_posix_lock *)
2491 (((char *) &pSMB->hdr.Protocol) + offset);
2493 parm_data->lock_type = cpu_to_le16(lock_type);
2494 if (waitFlag) {
2495 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2496 parm_data->lock_flags = cpu_to_le16(1);
2497 pSMB->Timeout = cpu_to_le32(-1);
2498 } else
2499 pSMB->Timeout = 0;
2501 parm_data->pid = cpu_to_le32(netpid);
2502 parm_data->start = cpu_to_le64(pLockData->fl_start);
2503 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
2505 pSMB->DataOffset = cpu_to_le16(offset);
2506 pSMB->Fid = smb_file_id;
2507 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2508 pSMB->Reserved4 = 0;
2509 inc_rfc1001_len(pSMB, byte_count);
2510 pSMB->ByteCount = cpu_to_le16(byte_count);
2511 if (waitFlag) {
2512 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2513 (struct smb_hdr *) pSMBr, &bytes_returned);
2514 } else {
2515 iov[0].iov_base = (char *)pSMB;
2516 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
2517 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2518 &resp_buf_type, timeout);
2519 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2520 not try to free it twice below on exit */
2521 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
2524 if (rc) {
2525 cFYI(1, "Send error in Posix Lock = %d", rc);
2526 } else if (get_flag) {
2527 /* lock structure can be returned on get */
2528 __u16 data_offset;
2529 __u16 data_count;
2530 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2532 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
2533 rc = -EIO; /* bad smb */
2534 goto plk_err_exit;
2536 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2537 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2538 if (data_count < sizeof(struct cifs_posix_lock)) {
2539 rc = -EIO;
2540 goto plk_err_exit;
2542 parm_data = (struct cifs_posix_lock *)
2543 ((char *)&pSMBr->hdr.Protocol + data_offset);
2544 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
2545 pLockData->fl_type = F_UNLCK;
2546 else {
2547 if (parm_data->lock_type ==
2548 __constant_cpu_to_le16(CIFS_RDLCK))
2549 pLockData->fl_type = F_RDLCK;
2550 else if (parm_data->lock_type ==
2551 __constant_cpu_to_le16(CIFS_WRLCK))
2552 pLockData->fl_type = F_WRLCK;
2554 pLockData->fl_start = le64_to_cpu(parm_data->start);
2555 pLockData->fl_end = pLockData->fl_start +
2556 le64_to_cpu(parm_data->length) - 1;
2557 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
2561 plk_err_exit:
2562 if (pSMB)
2563 cifs_small_buf_release(pSMB);
2565 if (resp_buf_type == CIFS_SMALL_BUFFER)
2566 cifs_small_buf_release(iov[0].iov_base);
2567 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2568 cifs_buf_release(iov[0].iov_base);
2570 /* Note: On -EAGAIN error only caller can retry on handle based calls
2571 since file handle passed in no longer valid */
2573 return rc;
2578 CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
2580 int rc = 0;
2581 CLOSE_REQ *pSMB = NULL;
2582 cFYI(1, "In CIFSSMBClose");
2584 /* do not retry on dead session on close */
2585 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
2586 if (rc == -EAGAIN)
2587 return 0;
2588 if (rc)
2589 return rc;
2591 pSMB->FileID = (__u16) smb_file_id;
2592 pSMB->LastWriteTime = 0xFFFFFFFF;
2593 pSMB->ByteCount = 0;
2594 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2595 cifs_stats_inc(&tcon->num_closes);
2596 if (rc) {
2597 if (rc != -EINTR) {
2598 /* EINTR is expected when user ctl-c to kill app */
2599 cERROR(1, "Send error in Close = %d", rc);
2603 /* Since session is dead, file will be closed on server already */
2604 if (rc == -EAGAIN)
2605 rc = 0;
2607 return rc;
2611 CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
2613 int rc = 0;
2614 FLUSH_REQ *pSMB = NULL;
2615 cFYI(1, "In CIFSSMBFlush");
2617 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2618 if (rc)
2619 return rc;
2621 pSMB->FileID = (__u16) smb_file_id;
2622 pSMB->ByteCount = 0;
2623 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2624 cifs_stats_inc(&tcon->num_flushes);
2625 if (rc)
2626 cERROR(1, "Send error in Flush = %d", rc);
2628 return rc;
2632 CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
2633 const char *fromName, const char *toName,
2634 const struct nls_table *nls_codepage, int remap)
2636 int rc = 0;
2637 RENAME_REQ *pSMB = NULL;
2638 RENAME_RSP *pSMBr = NULL;
2639 int bytes_returned;
2640 int name_len, name_len2;
2641 __u16 count;
2643 cFYI(1, "In CIFSSMBRename");
2644 renameRetry:
2645 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2646 (void **) &pSMBr);
2647 if (rc)
2648 return rc;
2650 pSMB->BufferFormat = 0x04;
2651 pSMB->SearchAttributes =
2652 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2653 ATTR_DIRECTORY);
2655 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2656 name_len =
2657 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2658 PATH_MAX, nls_codepage, remap);
2659 name_len++; /* trailing null */
2660 name_len *= 2;
2661 pSMB->OldFileName[name_len] = 0x04; /* pad */
2662 /* protocol requires ASCII signature byte on Unicode string */
2663 pSMB->OldFileName[name_len + 1] = 0x00;
2664 name_len2 =
2665 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2666 toName, PATH_MAX, nls_codepage, remap);
2667 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2668 name_len2 *= 2; /* convert to bytes */
2669 } else { /* BB improve the check for buffer overruns BB */
2670 name_len = strnlen(fromName, PATH_MAX);
2671 name_len++; /* trailing null */
2672 strncpy(pSMB->OldFileName, fromName, name_len);
2673 name_len2 = strnlen(toName, PATH_MAX);
2674 name_len2++; /* trailing null */
2675 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2676 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2677 name_len2++; /* trailing null */
2678 name_len2++; /* signature byte */
2681 count = 1 /* 1st signature byte */ + name_len + name_len2;
2682 inc_rfc1001_len(pSMB, count);
2683 pSMB->ByteCount = cpu_to_le16(count);
2685 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2686 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2687 cifs_stats_inc(&tcon->num_renames);
2688 if (rc)
2689 cFYI(1, "Send error in rename = %d", rc);
2691 cifs_buf_release(pSMB);
2693 if (rc == -EAGAIN)
2694 goto renameRetry;
2696 return rc;
2699 int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
2700 int netfid, const char *target_name,
2701 const struct nls_table *nls_codepage, int remap)
2703 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2704 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2705 struct set_file_rename *rename_info;
2706 char *data_offset;
2707 char dummy_string[30];
2708 int rc = 0;
2709 int bytes_returned = 0;
2710 int len_of_str;
2711 __u16 params, param_offset, offset, count, byte_count;
2713 cFYI(1, "Rename to File by handle");
2714 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2715 (void **) &pSMBr);
2716 if (rc)
2717 return rc;
2719 params = 6;
2720 pSMB->MaxSetupCount = 0;
2721 pSMB->Reserved = 0;
2722 pSMB->Flags = 0;
2723 pSMB->Timeout = 0;
2724 pSMB->Reserved2 = 0;
2725 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2726 offset = param_offset + params;
2728 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2729 rename_info = (struct set_file_rename *) data_offset;
2730 pSMB->MaxParameterCount = cpu_to_le16(2);
2731 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2732 pSMB->SetupCount = 1;
2733 pSMB->Reserved3 = 0;
2734 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2735 byte_count = 3 /* pad */ + params;
2736 pSMB->ParameterCount = cpu_to_le16(params);
2737 pSMB->TotalParameterCount = pSMB->ParameterCount;
2738 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2739 pSMB->DataOffset = cpu_to_le16(offset);
2740 /* construct random name ".cifs_tmp<inodenum><mid>" */
2741 rename_info->overwrite = cpu_to_le32(1);
2742 rename_info->root_fid = 0;
2743 /* unicode only call */
2744 if (target_name == NULL) {
2745 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2746 len_of_str =
2747 cifsConvertToUTF16((__le16 *)rename_info->target_name,
2748 dummy_string, 24, nls_codepage, remap);
2749 } else {
2750 len_of_str =
2751 cifsConvertToUTF16((__le16 *)rename_info->target_name,
2752 target_name, PATH_MAX, nls_codepage,
2753 remap);
2755 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2756 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2757 byte_count += count;
2758 pSMB->DataCount = cpu_to_le16(count);
2759 pSMB->TotalDataCount = pSMB->DataCount;
2760 pSMB->Fid = netfid;
2761 pSMB->InformationLevel =
2762 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2763 pSMB->Reserved4 = 0;
2764 inc_rfc1001_len(pSMB, byte_count);
2765 pSMB->ByteCount = cpu_to_le16(byte_count);
2766 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2767 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2768 cifs_stats_inc(&pTcon->num_t2renames);
2769 if (rc)
2770 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
2772 cifs_buf_release(pSMB);
2774 /* Note: On -EAGAIN error only caller can retry on handle based calls
2775 since file handle passed in no longer valid */
2777 return rc;
2781 CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
2782 const __u16 target_tid, const char *toName, const int flags,
2783 const struct nls_table *nls_codepage, int remap)
2785 int rc = 0;
2786 COPY_REQ *pSMB = NULL;
2787 COPY_RSP *pSMBr = NULL;
2788 int bytes_returned;
2789 int name_len, name_len2;
2790 __u16 count;
2792 cFYI(1, "In CIFSSMBCopy");
2793 copyRetry:
2794 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2795 (void **) &pSMBr);
2796 if (rc)
2797 return rc;
2799 pSMB->BufferFormat = 0x04;
2800 pSMB->Tid2 = target_tid;
2802 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2804 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2805 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2806 fromName, PATH_MAX, nls_codepage,
2807 remap);
2808 name_len++; /* trailing null */
2809 name_len *= 2;
2810 pSMB->OldFileName[name_len] = 0x04; /* pad */
2811 /* protocol requires ASCII signature byte on Unicode string */
2812 pSMB->OldFileName[name_len + 1] = 0x00;
2813 name_len2 =
2814 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2815 toName, PATH_MAX, nls_codepage, remap);
2816 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2817 name_len2 *= 2; /* convert to bytes */
2818 } else { /* BB improve the check for buffer overruns BB */
2819 name_len = strnlen(fromName, PATH_MAX);
2820 name_len++; /* trailing null */
2821 strncpy(pSMB->OldFileName, fromName, name_len);
2822 name_len2 = strnlen(toName, PATH_MAX);
2823 name_len2++; /* trailing null */
2824 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2825 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2826 name_len2++; /* trailing null */
2827 name_len2++; /* signature byte */
2830 count = 1 /* 1st signature byte */ + name_len + name_len2;
2831 inc_rfc1001_len(pSMB, count);
2832 pSMB->ByteCount = cpu_to_le16(count);
2834 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2835 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2836 if (rc) {
2837 cFYI(1, "Send error in copy = %d with %d files copied",
2838 rc, le16_to_cpu(pSMBr->CopyCount));
2840 cifs_buf_release(pSMB);
2842 if (rc == -EAGAIN)
2843 goto copyRetry;
2845 return rc;
2849 CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
2850 const char *fromName, const char *toName,
2851 const struct nls_table *nls_codepage)
2853 TRANSACTION2_SPI_REQ *pSMB = NULL;
2854 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2855 char *data_offset;
2856 int name_len;
2857 int name_len_target;
2858 int rc = 0;
2859 int bytes_returned = 0;
2860 __u16 params, param_offset, offset, byte_count;
2862 cFYI(1, "In Symlink Unix style");
2863 createSymLinkRetry:
2864 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2865 (void **) &pSMBr);
2866 if (rc)
2867 return rc;
2869 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2870 name_len =
2871 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2872 /* find define for this maxpathcomponent */
2873 PATH_MAX, nls_codepage);
2874 name_len++; /* trailing null */
2875 name_len *= 2;
2877 } else { /* BB improve the check for buffer overruns BB */
2878 name_len = strnlen(fromName, PATH_MAX);
2879 name_len++; /* trailing null */
2880 strncpy(pSMB->FileName, fromName, name_len);
2882 params = 6 + name_len;
2883 pSMB->MaxSetupCount = 0;
2884 pSMB->Reserved = 0;
2885 pSMB->Flags = 0;
2886 pSMB->Timeout = 0;
2887 pSMB->Reserved2 = 0;
2888 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2889 InformationLevel) - 4;
2890 offset = param_offset + params;
2892 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2893 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2894 name_len_target =
2895 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2896 /* find define for this maxpathcomponent */
2897 , nls_codepage);
2898 name_len_target++; /* trailing null */
2899 name_len_target *= 2;
2900 } else { /* BB improve the check for buffer overruns BB */
2901 name_len_target = strnlen(toName, PATH_MAX);
2902 name_len_target++; /* trailing null */
2903 strncpy(data_offset, toName, name_len_target);
2906 pSMB->MaxParameterCount = cpu_to_le16(2);
2907 /* BB find exact max on data count below from sess */
2908 pSMB->MaxDataCount = cpu_to_le16(1000);
2909 pSMB->SetupCount = 1;
2910 pSMB->Reserved3 = 0;
2911 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2912 byte_count = 3 /* pad */ + params + name_len_target;
2913 pSMB->DataCount = cpu_to_le16(name_len_target);
2914 pSMB->ParameterCount = cpu_to_le16(params);
2915 pSMB->TotalDataCount = pSMB->DataCount;
2916 pSMB->TotalParameterCount = pSMB->ParameterCount;
2917 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2918 pSMB->DataOffset = cpu_to_le16(offset);
2919 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2920 pSMB->Reserved4 = 0;
2921 inc_rfc1001_len(pSMB, byte_count);
2922 pSMB->ByteCount = cpu_to_le16(byte_count);
2923 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2925 cifs_stats_inc(&tcon->num_symlinks);
2926 if (rc)
2927 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
2929 cifs_buf_release(pSMB);
2931 if (rc == -EAGAIN)
2932 goto createSymLinkRetry;
2934 return rc;
2938 CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
2939 const char *fromName, const char *toName,
2940 const struct nls_table *nls_codepage, int remap)
2942 TRANSACTION2_SPI_REQ *pSMB = NULL;
2943 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2944 char *data_offset;
2945 int name_len;
2946 int name_len_target;
2947 int rc = 0;
2948 int bytes_returned = 0;
2949 __u16 params, param_offset, offset, byte_count;
2951 cFYI(1, "In Create Hard link Unix style");
2952 createHardLinkRetry:
2953 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2954 (void **) &pSMBr);
2955 if (rc)
2956 return rc;
2958 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2959 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2960 PATH_MAX, nls_codepage, remap);
2961 name_len++; /* trailing null */
2962 name_len *= 2;
2964 } else { /* BB improve the check for buffer overruns BB */
2965 name_len = strnlen(toName, PATH_MAX);
2966 name_len++; /* trailing null */
2967 strncpy(pSMB->FileName, toName, name_len);
2969 params = 6 + name_len;
2970 pSMB->MaxSetupCount = 0;
2971 pSMB->Reserved = 0;
2972 pSMB->Flags = 0;
2973 pSMB->Timeout = 0;
2974 pSMB->Reserved2 = 0;
2975 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2976 InformationLevel) - 4;
2977 offset = param_offset + params;
2979 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2980 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2981 name_len_target =
2982 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2983 PATH_MAX, nls_codepage, remap);
2984 name_len_target++; /* trailing null */
2985 name_len_target *= 2;
2986 } else { /* BB improve the check for buffer overruns BB */
2987 name_len_target = strnlen(fromName, PATH_MAX);
2988 name_len_target++; /* trailing null */
2989 strncpy(data_offset, fromName, name_len_target);
2992 pSMB->MaxParameterCount = cpu_to_le16(2);
2993 /* BB find exact max on data count below from sess*/
2994 pSMB->MaxDataCount = cpu_to_le16(1000);
2995 pSMB->SetupCount = 1;
2996 pSMB->Reserved3 = 0;
2997 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2998 byte_count = 3 /* pad */ + params + name_len_target;
2999 pSMB->ParameterCount = cpu_to_le16(params);
3000 pSMB->TotalParameterCount = pSMB->ParameterCount;
3001 pSMB->DataCount = cpu_to_le16(name_len_target);
3002 pSMB->TotalDataCount = pSMB->DataCount;
3003 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3004 pSMB->DataOffset = cpu_to_le16(offset);
3005 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3006 pSMB->Reserved4 = 0;
3007 inc_rfc1001_len(pSMB, byte_count);
3008 pSMB->ByteCount = cpu_to_le16(byte_count);
3009 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3010 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3011 cifs_stats_inc(&tcon->num_hardlinks);
3012 if (rc)
3013 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
3015 cifs_buf_release(pSMB);
3016 if (rc == -EAGAIN)
3017 goto createHardLinkRetry;
3019 return rc;
3023 CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
3024 const char *fromName, const char *toName,
3025 const struct nls_table *nls_codepage, int remap)
3027 int rc = 0;
3028 NT_RENAME_REQ *pSMB = NULL;
3029 RENAME_RSP *pSMBr = NULL;
3030 int bytes_returned;
3031 int name_len, name_len2;
3032 __u16 count;
3034 cFYI(1, "In CIFSCreateHardLink");
3035 winCreateHardLinkRetry:
3037 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3038 (void **) &pSMBr);
3039 if (rc)
3040 return rc;
3042 pSMB->SearchAttributes =
3043 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3044 ATTR_DIRECTORY);
3045 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3046 pSMB->ClusterCount = 0;
3048 pSMB->BufferFormat = 0x04;
3050 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3051 name_len =
3052 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
3053 PATH_MAX, nls_codepage, remap);
3054 name_len++; /* trailing null */
3055 name_len *= 2;
3057 /* protocol specifies ASCII buffer format (0x04) for unicode */
3058 pSMB->OldFileName[name_len] = 0x04;
3059 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
3060 name_len2 =
3061 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
3062 toName, PATH_MAX, nls_codepage, remap);
3063 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3064 name_len2 *= 2; /* convert to bytes */
3065 } else { /* BB improve the check for buffer overruns BB */
3066 name_len = strnlen(fromName, PATH_MAX);
3067 name_len++; /* trailing null */
3068 strncpy(pSMB->OldFileName, fromName, name_len);
3069 name_len2 = strnlen(toName, PATH_MAX);
3070 name_len2++; /* trailing null */
3071 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
3072 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
3073 name_len2++; /* trailing null */
3074 name_len2++; /* signature byte */
3077 count = 1 /* string type byte */ + name_len + name_len2;
3078 inc_rfc1001_len(pSMB, count);
3079 pSMB->ByteCount = cpu_to_le16(count);
3081 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3082 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3083 cifs_stats_inc(&tcon->num_hardlinks);
3084 if (rc)
3085 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
3087 cifs_buf_release(pSMB);
3088 if (rc == -EAGAIN)
3089 goto winCreateHardLinkRetry;
3091 return rc;
3095 CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
3096 const unsigned char *searchName, char **symlinkinfo,
3097 const struct nls_table *nls_codepage)
3099 /* SMB_QUERY_FILE_UNIX_LINK */
3100 TRANSACTION2_QPI_REQ *pSMB = NULL;
3101 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3102 int rc = 0;
3103 int bytes_returned;
3104 int name_len;
3105 __u16 params, byte_count;
3106 char *data_start;
3108 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
3110 querySymLinkRetry:
3111 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3112 (void **) &pSMBr);
3113 if (rc)
3114 return rc;
3116 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3117 name_len =
3118 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3119 PATH_MAX, nls_codepage);
3120 name_len++; /* trailing null */
3121 name_len *= 2;
3122 } else { /* BB improve the check for buffer overruns BB */
3123 name_len = strnlen(searchName, PATH_MAX);
3124 name_len++; /* trailing null */
3125 strncpy(pSMB->FileName, searchName, name_len);
3128 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3129 pSMB->TotalDataCount = 0;
3130 pSMB->MaxParameterCount = cpu_to_le16(2);
3131 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3132 pSMB->MaxSetupCount = 0;
3133 pSMB->Reserved = 0;
3134 pSMB->Flags = 0;
3135 pSMB->Timeout = 0;
3136 pSMB->Reserved2 = 0;
3137 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3138 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3139 pSMB->DataCount = 0;
3140 pSMB->DataOffset = 0;
3141 pSMB->SetupCount = 1;
3142 pSMB->Reserved3 = 0;
3143 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3144 byte_count = params + 1 /* pad */ ;
3145 pSMB->TotalParameterCount = cpu_to_le16(params);
3146 pSMB->ParameterCount = pSMB->TotalParameterCount;
3147 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3148 pSMB->Reserved4 = 0;
3149 inc_rfc1001_len(pSMB, byte_count);
3150 pSMB->ByteCount = cpu_to_le16(byte_count);
3152 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3153 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3154 if (rc) {
3155 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
3156 } else {
3157 /* decode response */
3159 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3160 /* BB also check enough total bytes returned */
3161 if (rc || get_bcc(&pSMBr->hdr) < 2)
3162 rc = -EIO;
3163 else {
3164 bool is_unicode;
3165 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3167 data_start = ((char *) &pSMBr->hdr.Protocol) +
3168 le16_to_cpu(pSMBr->t2.DataOffset);
3170 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3171 is_unicode = true;
3172 else
3173 is_unicode = false;
3175 /* BB FIXME investigate remapping reserved chars here */
3176 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3177 count, is_unicode, nls_codepage);
3178 if (!*symlinkinfo)
3179 rc = -ENOMEM;
3182 cifs_buf_release(pSMB);
3183 if (rc == -EAGAIN)
3184 goto querySymLinkRetry;
3185 return rc;
3188 #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3190 * Recent Windows versions now create symlinks more frequently
3191 * and they use the "reparse point" mechanism below. We can of course
3192 * do symlinks nicely to Samba and other servers which support the
3193 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3194 * "MF" symlinks optionally, but for recent Windows we really need to
3195 * reenable the code below and fix the cifs_symlink callers to handle this.
3196 * In the interim this code has been moved to its own config option so
3197 * it is not compiled in by default until callers fixed up and more tested.
3200 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
3201 const unsigned char *searchName,
3202 char *symlinkinfo, const int buflen, __u16 fid,
3203 const struct nls_table *nls_codepage)
3205 int rc = 0;
3206 int bytes_returned;
3207 struct smb_com_transaction_ioctl_req *pSMB;
3208 struct smb_com_transaction_ioctl_rsp *pSMBr;
3210 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
3211 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3212 (void **) &pSMBr);
3213 if (rc)
3214 return rc;
3216 pSMB->TotalParameterCount = 0 ;
3217 pSMB->TotalDataCount = 0;
3218 pSMB->MaxParameterCount = cpu_to_le32(2);
3219 /* BB find exact data count max from sess structure BB */
3220 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
3221 pSMB->MaxSetupCount = 4;
3222 pSMB->Reserved = 0;
3223 pSMB->ParameterOffset = 0;
3224 pSMB->DataCount = 0;
3225 pSMB->DataOffset = 0;
3226 pSMB->SetupCount = 4;
3227 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3228 pSMB->ParameterCount = pSMB->TotalParameterCount;
3229 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3230 pSMB->IsFsctl = 1; /* FSCTL */
3231 pSMB->IsRootFlag = 0;
3232 pSMB->Fid = fid; /* file handle always le */
3233 pSMB->ByteCount = 0;
3235 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3236 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3237 if (rc) {
3238 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
3239 } else { /* decode response */
3240 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3241 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
3242 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3243 /* BB also check enough total bytes returned */
3244 rc = -EIO; /* bad smb */
3245 goto qreparse_out;
3247 if (data_count && (data_count < 2048)) {
3248 char *end_of_smb = 2 /* sizeof byte count */ +
3249 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
3251 struct reparse_data *reparse_buf =
3252 (struct reparse_data *)
3253 ((char *)&pSMBr->hdr.Protocol
3254 + data_offset);
3255 if ((char *)reparse_buf >= end_of_smb) {
3256 rc = -EIO;
3257 goto qreparse_out;
3259 if ((reparse_buf->LinkNamesBuf +
3260 reparse_buf->TargetNameOffset +
3261 reparse_buf->TargetNameLen) > end_of_smb) {
3262 cFYI(1, "reparse buf beyond SMB");
3263 rc = -EIO;
3264 goto qreparse_out;
3267 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3268 cifs_from_ucs2(symlinkinfo, (__le16 *)
3269 (reparse_buf->LinkNamesBuf +
3270 reparse_buf->TargetNameOffset),
3271 buflen,
3272 reparse_buf->TargetNameLen,
3273 nls_codepage, 0);
3274 } else { /* ASCII names */
3275 strncpy(symlinkinfo,
3276 reparse_buf->LinkNamesBuf +
3277 reparse_buf->TargetNameOffset,
3278 min_t(const int, buflen,
3279 reparse_buf->TargetNameLen));
3281 } else {
3282 rc = -EIO;
3283 cFYI(1, "Invalid return data count on "
3284 "get reparse info ioctl");
3286 symlinkinfo[buflen] = 0; /* just in case so the caller
3287 does not go off the end of the buffer */
3288 cFYI(1, "readlink result - %s", symlinkinfo);
3291 qreparse_out:
3292 cifs_buf_release(pSMB);
3294 /* Note: On -EAGAIN error only caller can retry on handle based calls
3295 since file handle passed in no longer valid */
3297 return rc;
3299 #endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
3301 #ifdef CONFIG_CIFS_POSIX
3303 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
3304 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3305 struct cifs_posix_ace *cifs_ace)
3307 /* u8 cifs fields do not need le conversion */
3308 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3309 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3310 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
3311 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
3313 return;
3316 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
3317 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3318 const int acl_type, const int size_of_data_area)
3320 int size = 0;
3321 int i;
3322 __u16 count;
3323 struct cifs_posix_ace *pACE;
3324 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3325 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
3327 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3328 return -EOPNOTSUPP;
3330 if (acl_type & ACL_TYPE_ACCESS) {
3331 count = le16_to_cpu(cifs_acl->access_entry_count);
3332 pACE = &cifs_acl->ace_array[0];
3333 size = sizeof(struct cifs_posix_acl);
3334 size += sizeof(struct cifs_posix_ace) * count;
3335 /* check if we would go beyond end of SMB */
3336 if (size_of_data_area < size) {
3337 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3338 size_of_data_area, size);
3339 return -EINVAL;
3341 } else if (acl_type & ACL_TYPE_DEFAULT) {
3342 count = le16_to_cpu(cifs_acl->access_entry_count);
3343 size = sizeof(struct cifs_posix_acl);
3344 size += sizeof(struct cifs_posix_ace) * count;
3345 /* skip past access ACEs to get to default ACEs */
3346 pACE = &cifs_acl->ace_array[count];
3347 count = le16_to_cpu(cifs_acl->default_entry_count);
3348 size += sizeof(struct cifs_posix_ace) * count;
3349 /* check if we would go beyond end of SMB */
3350 if (size_of_data_area < size)
3351 return -EINVAL;
3352 } else {
3353 /* illegal type */
3354 return -EINVAL;
3357 size = posix_acl_xattr_size(count);
3358 if ((buflen == 0) || (local_acl == NULL)) {
3359 /* used to query ACL EA size */
3360 } else if (size > buflen) {
3361 return -ERANGE;
3362 } else /* buffer big enough */ {
3363 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
3364 for (i = 0; i < count ; i++) {
3365 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3366 pACE++;
3369 return size;
3372 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3373 const posix_acl_xattr_entry *local_ace)
3375 __u16 rc = 0; /* 0 = ACL converted ok */
3377 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3378 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
3379 /* BB is there a better way to handle the large uid? */
3380 if (local_ace->e_id == cpu_to_le32(-1)) {
3381 /* Probably no need to le convert -1 on any arch but can not hurt */
3382 cifs_ace->cifs_uid = cpu_to_le64(-1);
3383 } else
3384 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
3385 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
3386 return rc;
3389 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
3390 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3391 const int buflen, const int acl_type)
3393 __u16 rc = 0;
3394 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3395 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
3396 int count;
3397 int i;
3399 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
3400 return 0;
3402 count = posix_acl_xattr_count((size_t)buflen);
3403 cFYI(1, "setting acl with %d entries from buf of length %d and "
3404 "version of %d",
3405 count, buflen, le32_to_cpu(local_acl->a_version));
3406 if (le32_to_cpu(local_acl->a_version) != 2) {
3407 cFYI(1, "unknown POSIX ACL version %d",
3408 le32_to_cpu(local_acl->a_version));
3409 return 0;
3411 cifs_acl->version = cpu_to_le16(1);
3412 if (acl_type == ACL_TYPE_ACCESS)
3413 cifs_acl->access_entry_count = cpu_to_le16(count);
3414 else if (acl_type == ACL_TYPE_DEFAULT)
3415 cifs_acl->default_entry_count = cpu_to_le16(count);
3416 else {
3417 cFYI(1, "unknown ACL type %d", acl_type);
3418 return 0;
3420 for (i = 0; i < count; i++) {
3421 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3422 &local_acl->a_entries[i]);
3423 if (rc != 0) {
3424 /* ACE not converted */
3425 break;
3428 if (rc == 0) {
3429 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3430 rc += sizeof(struct cifs_posix_acl);
3431 /* BB add check to make sure ACL does not overflow SMB */
3433 return rc;
3437 CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
3438 const unsigned char *searchName,
3439 char *acl_inf, const int buflen, const int acl_type,
3440 const struct nls_table *nls_codepage, int remap)
3442 /* SMB_QUERY_POSIX_ACL */
3443 TRANSACTION2_QPI_REQ *pSMB = NULL;
3444 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3445 int rc = 0;
3446 int bytes_returned;
3447 int name_len;
3448 __u16 params, byte_count;
3450 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
3452 queryAclRetry:
3453 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3454 (void **) &pSMBr);
3455 if (rc)
3456 return rc;
3458 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3459 name_len =
3460 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3461 searchName, PATH_MAX, nls_codepage,
3462 remap);
3463 name_len++; /* trailing null */
3464 name_len *= 2;
3465 pSMB->FileName[name_len] = 0;
3466 pSMB->FileName[name_len+1] = 0;
3467 } else { /* BB improve the check for buffer overruns BB */
3468 name_len = strnlen(searchName, PATH_MAX);
3469 name_len++; /* trailing null */
3470 strncpy(pSMB->FileName, searchName, name_len);
3473 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3474 pSMB->TotalDataCount = 0;
3475 pSMB->MaxParameterCount = cpu_to_le16(2);
3476 /* BB find exact max data count below from sess structure BB */
3477 pSMB->MaxDataCount = cpu_to_le16(4000);
3478 pSMB->MaxSetupCount = 0;
3479 pSMB->Reserved = 0;
3480 pSMB->Flags = 0;
3481 pSMB->Timeout = 0;
3482 pSMB->Reserved2 = 0;
3483 pSMB->ParameterOffset = cpu_to_le16(
3484 offsetof(struct smb_com_transaction2_qpi_req,
3485 InformationLevel) - 4);
3486 pSMB->DataCount = 0;
3487 pSMB->DataOffset = 0;
3488 pSMB->SetupCount = 1;
3489 pSMB->Reserved3 = 0;
3490 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3491 byte_count = params + 1 /* pad */ ;
3492 pSMB->TotalParameterCount = cpu_to_le16(params);
3493 pSMB->ParameterCount = pSMB->TotalParameterCount;
3494 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3495 pSMB->Reserved4 = 0;
3496 inc_rfc1001_len(pSMB, byte_count);
3497 pSMB->ByteCount = cpu_to_le16(byte_count);
3499 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3501 cifs_stats_inc(&tcon->num_acl_get);
3502 if (rc) {
3503 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
3504 } else {
3505 /* decode response */
3507 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3508 /* BB also check enough total bytes returned */
3509 if (rc || get_bcc(&pSMBr->hdr) < 2)
3510 rc = -EIO; /* bad smb */
3511 else {
3512 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3513 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3514 rc = cifs_copy_posix_acl(acl_inf,
3515 (char *)&pSMBr->hdr.Protocol+data_offset,
3516 buflen, acl_type, count);
3519 cifs_buf_release(pSMB);
3520 if (rc == -EAGAIN)
3521 goto queryAclRetry;
3522 return rc;
3526 CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
3527 const unsigned char *fileName,
3528 const char *local_acl, const int buflen,
3529 const int acl_type,
3530 const struct nls_table *nls_codepage, int remap)
3532 struct smb_com_transaction2_spi_req *pSMB = NULL;
3533 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3534 char *parm_data;
3535 int name_len;
3536 int rc = 0;
3537 int bytes_returned = 0;
3538 __u16 params, byte_count, data_count, param_offset, offset;
3540 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
3541 setAclRetry:
3542 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3543 (void **) &pSMBr);
3544 if (rc)
3545 return rc;
3546 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3547 name_len =
3548 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3549 PATH_MAX, nls_codepage, remap);
3550 name_len++; /* trailing null */
3551 name_len *= 2;
3552 } else { /* BB improve the check for buffer overruns BB */
3553 name_len = strnlen(fileName, PATH_MAX);
3554 name_len++; /* trailing null */
3555 strncpy(pSMB->FileName, fileName, name_len);
3557 params = 6 + name_len;
3558 pSMB->MaxParameterCount = cpu_to_le16(2);
3559 /* BB find max SMB size from sess */
3560 pSMB->MaxDataCount = cpu_to_le16(1000);
3561 pSMB->MaxSetupCount = 0;
3562 pSMB->Reserved = 0;
3563 pSMB->Flags = 0;
3564 pSMB->Timeout = 0;
3565 pSMB->Reserved2 = 0;
3566 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3567 InformationLevel) - 4;
3568 offset = param_offset + params;
3569 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3570 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3572 /* convert to on the wire format for POSIX ACL */
3573 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
3575 if (data_count == 0) {
3576 rc = -EOPNOTSUPP;
3577 goto setACLerrorExit;
3579 pSMB->DataOffset = cpu_to_le16(offset);
3580 pSMB->SetupCount = 1;
3581 pSMB->Reserved3 = 0;
3582 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3583 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3584 byte_count = 3 /* pad */ + params + data_count;
3585 pSMB->DataCount = cpu_to_le16(data_count);
3586 pSMB->TotalDataCount = pSMB->DataCount;
3587 pSMB->ParameterCount = cpu_to_le16(params);
3588 pSMB->TotalParameterCount = pSMB->ParameterCount;
3589 pSMB->Reserved4 = 0;
3590 inc_rfc1001_len(pSMB, byte_count);
3591 pSMB->ByteCount = cpu_to_le16(byte_count);
3592 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3593 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3594 if (rc)
3595 cFYI(1, "Set POSIX ACL returned %d", rc);
3597 setACLerrorExit:
3598 cifs_buf_release(pSMB);
3599 if (rc == -EAGAIN)
3600 goto setAclRetry;
3601 return rc;
3604 /* BB fix tabs in this function FIXME BB */
3606 CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
3607 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
3609 int rc = 0;
3610 struct smb_t2_qfi_req *pSMB = NULL;
3611 struct smb_t2_qfi_rsp *pSMBr = NULL;
3612 int bytes_returned;
3613 __u16 params, byte_count;
3615 cFYI(1, "In GetExtAttr");
3616 if (tcon == NULL)
3617 return -ENODEV;
3619 GetExtAttrRetry:
3620 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3621 (void **) &pSMBr);
3622 if (rc)
3623 return rc;
3625 params = 2 /* level */ + 2 /* fid */;
3626 pSMB->t2.TotalDataCount = 0;
3627 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3628 /* BB find exact max data count below from sess structure BB */
3629 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3630 pSMB->t2.MaxSetupCount = 0;
3631 pSMB->t2.Reserved = 0;
3632 pSMB->t2.Flags = 0;
3633 pSMB->t2.Timeout = 0;
3634 pSMB->t2.Reserved2 = 0;
3635 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3636 Fid) - 4);
3637 pSMB->t2.DataCount = 0;
3638 pSMB->t2.DataOffset = 0;
3639 pSMB->t2.SetupCount = 1;
3640 pSMB->t2.Reserved3 = 0;
3641 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3642 byte_count = params + 1 /* pad */ ;
3643 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3644 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3645 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3646 pSMB->Pad = 0;
3647 pSMB->Fid = netfid;
3648 inc_rfc1001_len(pSMB, byte_count);
3649 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3651 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3652 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3653 if (rc) {
3654 cFYI(1, "error %d in GetExtAttr", rc);
3655 } else {
3656 /* decode response */
3657 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3658 /* BB also check enough total bytes returned */
3659 if (rc || get_bcc(&pSMBr->hdr) < 2)
3660 /* If rc should we check for EOPNOSUPP and
3661 disable the srvino flag? or in caller? */
3662 rc = -EIO; /* bad smb */
3663 else {
3664 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3665 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3666 struct file_chattr_info *pfinfo;
3667 /* BB Do we need a cast or hash here ? */
3668 if (count != 16) {
3669 cFYI(1, "Illegal size ret in GetExtAttr");
3670 rc = -EIO;
3671 goto GetExtAttrOut;
3673 pfinfo = (struct file_chattr_info *)
3674 (data_offset + (char *) &pSMBr->hdr.Protocol);
3675 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3676 *pMask = le64_to_cpu(pfinfo->mask);
3679 GetExtAttrOut:
3680 cifs_buf_release(pSMB);
3681 if (rc == -EAGAIN)
3682 goto GetExtAttrRetry;
3683 return rc;
3686 #endif /* CONFIG_POSIX */
3688 #ifdef CONFIG_CIFS_ACL
3690 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3691 * all NT TRANSACTS that we init here have total parm and data under about 400
3692 * bytes (to fit in small cifs buffer size), which is the case so far, it
3693 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3694 * returned setup area) and MaxParameterCount (returned parms size) must be set
3695 * by caller
3697 static int
3698 smb_init_nttransact(const __u16 sub_command, const int setup_count,
3699 const int parm_len, struct cifs_tcon *tcon,
3700 void **ret_buf)
3702 int rc;
3703 __u32 temp_offset;
3704 struct smb_com_ntransact_req *pSMB;
3706 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3707 (void **)&pSMB);
3708 if (rc)
3709 return rc;
3710 *ret_buf = (void *)pSMB;
3711 pSMB->Reserved = 0;
3712 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3713 pSMB->TotalDataCount = 0;
3714 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
3715 pSMB->ParameterCount = pSMB->TotalParameterCount;
3716 pSMB->DataCount = pSMB->TotalDataCount;
3717 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3718 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3719 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3720 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3721 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3722 pSMB->SubCommand = cpu_to_le16(sub_command);
3723 return 0;
3726 static int
3727 validate_ntransact(char *buf, char **ppparm, char **ppdata,
3728 __u32 *pparmlen, __u32 *pdatalen)
3730 char *end_of_smb;
3731 __u32 data_count, data_offset, parm_count, parm_offset;
3732 struct smb_com_ntransact_rsp *pSMBr;
3733 u16 bcc;
3735 *pdatalen = 0;
3736 *pparmlen = 0;
3738 if (buf == NULL)
3739 return -EINVAL;
3741 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3743 bcc = get_bcc(&pSMBr->hdr);
3744 end_of_smb = 2 /* sizeof byte count */ + bcc +
3745 (char *)&pSMBr->ByteCount;
3747 data_offset = le32_to_cpu(pSMBr->DataOffset);
3748 data_count = le32_to_cpu(pSMBr->DataCount);
3749 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3750 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3752 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3753 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3755 /* should we also check that parm and data areas do not overlap? */
3756 if (*ppparm > end_of_smb) {
3757 cFYI(1, "parms start after end of smb");
3758 return -EINVAL;
3759 } else if (parm_count + *ppparm > end_of_smb) {
3760 cFYI(1, "parm end after end of smb");
3761 return -EINVAL;
3762 } else if (*ppdata > end_of_smb) {
3763 cFYI(1, "data starts after end of smb");
3764 return -EINVAL;
3765 } else if (data_count + *ppdata > end_of_smb) {
3766 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3767 *ppdata, data_count, (data_count + *ppdata),
3768 end_of_smb, pSMBr);
3769 return -EINVAL;
3770 } else if (parm_count + data_count > bcc) {
3771 cFYI(1, "parm count and data count larger than SMB");
3772 return -EINVAL;
3774 *pdatalen = data_count;
3775 *pparmlen = parm_count;
3776 return 0;
3779 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3781 CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
3782 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3784 int rc = 0;
3785 int buf_type = 0;
3786 QUERY_SEC_DESC_REQ *pSMB;
3787 struct kvec iov[1];
3789 cFYI(1, "GetCifsACL");
3791 *pbuflen = 0;
3792 *acl_inf = NULL;
3794 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3795 8 /* parm len */, tcon, (void **) &pSMB);
3796 if (rc)
3797 return rc;
3799 pSMB->MaxParameterCount = cpu_to_le32(4);
3800 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3801 pSMB->MaxSetupCount = 0;
3802 pSMB->Fid = fid; /* file handle always le */
3803 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3804 CIFS_ACL_DACL);
3805 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3806 inc_rfc1001_len(pSMB, 11);
3807 iov[0].iov_base = (char *)pSMB;
3808 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
3810 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3812 cifs_stats_inc(&tcon->num_acl_get);
3813 if (rc) {
3814 cFYI(1, "Send error in QuerySecDesc = %d", rc);
3815 } else { /* decode response */
3816 __le32 *parm;
3817 __u32 parm_len;
3818 __u32 acl_len;
3819 struct smb_com_ntransact_rsp *pSMBr;
3820 char *pdata;
3822 /* validate_nttransact */
3823 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3824 &pdata, &parm_len, pbuflen);
3825 if (rc)
3826 goto qsec_out;
3827 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3829 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
3831 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3832 rc = -EIO; /* bad smb */
3833 *pbuflen = 0;
3834 goto qsec_out;
3837 /* BB check that data area is minimum length and as big as acl_len */
3839 acl_len = le32_to_cpu(*parm);
3840 if (acl_len != *pbuflen) {
3841 cERROR(1, "acl length %d does not match %d",
3842 acl_len, *pbuflen);
3843 if (*pbuflen > acl_len)
3844 *pbuflen = acl_len;
3847 /* check if buffer is big enough for the acl
3848 header followed by the smallest SID */
3849 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3850 (*pbuflen >= 64 * 1024)) {
3851 cERROR(1, "bad acl length %d", *pbuflen);
3852 rc = -EINVAL;
3853 *pbuflen = 0;
3854 } else {
3855 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3856 if (*acl_inf == NULL) {
3857 *pbuflen = 0;
3858 rc = -ENOMEM;
3860 memcpy(*acl_inf, pdata, *pbuflen);
3863 qsec_out:
3864 if (buf_type == CIFS_SMALL_BUFFER)
3865 cifs_small_buf_release(iov[0].iov_base);
3866 else if (buf_type == CIFS_LARGE_BUFFER)
3867 cifs_buf_release(iov[0].iov_base);
3868 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3869 return rc;
3873 CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
3874 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
3876 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3877 int rc = 0;
3878 int bytes_returned = 0;
3879 SET_SEC_DESC_REQ *pSMB = NULL;
3880 NTRANSACT_RSP *pSMBr = NULL;
3882 setCifsAclRetry:
3883 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3884 (void **) &pSMBr);
3885 if (rc)
3886 return (rc);
3888 pSMB->MaxSetupCount = 0;
3889 pSMB->Reserved = 0;
3891 param_count = 8;
3892 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3893 data_count = acllen;
3894 data_offset = param_offset + param_count;
3895 byte_count = 3 /* pad */ + param_count;
3897 pSMB->DataCount = cpu_to_le32(data_count);
3898 pSMB->TotalDataCount = pSMB->DataCount;
3899 pSMB->MaxParameterCount = cpu_to_le32(4);
3900 pSMB->MaxDataCount = cpu_to_le32(16384);
3901 pSMB->ParameterCount = cpu_to_le32(param_count);
3902 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3903 pSMB->TotalParameterCount = pSMB->ParameterCount;
3904 pSMB->DataOffset = cpu_to_le32(data_offset);
3905 pSMB->SetupCount = 0;
3906 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3907 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3909 pSMB->Fid = fid; /* file handle always le */
3910 pSMB->Reserved2 = 0;
3911 pSMB->AclFlags = cpu_to_le32(aclflag);
3913 if (pntsd && acllen) {
3914 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3915 (char *) pntsd,
3916 acllen);
3917 inc_rfc1001_len(pSMB, byte_count + data_count);
3918 } else
3919 inc_rfc1001_len(pSMB, byte_count);
3921 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3922 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3924 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
3925 if (rc)
3926 cFYI(1, "Set CIFS ACL returned %d", rc);
3927 cifs_buf_release(pSMB);
3929 if (rc == -EAGAIN)
3930 goto setCifsAclRetry;
3932 return (rc);
3935 #endif /* CONFIG_CIFS_ACL */
3937 /* Legacy Query Path Information call for lookup to old servers such
3938 as Win9x/WinME */
3939 int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
3940 const unsigned char *searchName,
3941 FILE_ALL_INFO *pFinfo,
3942 const struct nls_table *nls_codepage, int remap)
3944 QUERY_INFORMATION_REQ *pSMB;
3945 QUERY_INFORMATION_RSP *pSMBr;
3946 int rc = 0;
3947 int bytes_returned;
3948 int name_len;
3950 cFYI(1, "In SMBQPath path %s", searchName);
3951 QInfRetry:
3952 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3953 (void **) &pSMBr);
3954 if (rc)
3955 return rc;
3957 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3958 name_len =
3959 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3960 searchName, PATH_MAX, nls_codepage,
3961 remap);
3962 name_len++; /* trailing null */
3963 name_len *= 2;
3964 } else {
3965 name_len = strnlen(searchName, PATH_MAX);
3966 name_len++; /* trailing null */
3967 strncpy(pSMB->FileName, searchName, name_len);
3969 pSMB->BufferFormat = 0x04;
3970 name_len++; /* account for buffer type byte */
3971 inc_rfc1001_len(pSMB, (__u16)name_len);
3972 pSMB->ByteCount = cpu_to_le16(name_len);
3974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3976 if (rc) {
3977 cFYI(1, "Send error in QueryInfo = %d", rc);
3978 } else if (pFinfo) {
3979 struct timespec ts;
3980 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3982 /* decode response */
3983 /* BB FIXME - add time zone adjustment BB */
3984 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3985 ts.tv_nsec = 0;
3986 ts.tv_sec = time;
3987 /* decode time fields */
3988 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3989 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3990 pFinfo->LastAccessTime = 0;
3991 pFinfo->AllocationSize =
3992 cpu_to_le64(le32_to_cpu(pSMBr->size));
3993 pFinfo->EndOfFile = pFinfo->AllocationSize;
3994 pFinfo->Attributes =
3995 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3996 } else
3997 rc = -EIO; /* bad buffer passed in */
3999 cifs_buf_release(pSMB);
4001 if (rc == -EAGAIN)
4002 goto QInfRetry;
4004 return rc;
4008 CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
4009 u16 netfid, FILE_ALL_INFO *pFindData)
4011 struct smb_t2_qfi_req *pSMB = NULL;
4012 struct smb_t2_qfi_rsp *pSMBr = NULL;
4013 int rc = 0;
4014 int bytes_returned;
4015 __u16 params, byte_count;
4017 QFileInfoRetry:
4018 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4019 (void **) &pSMBr);
4020 if (rc)
4021 return rc;
4023 params = 2 /* level */ + 2 /* fid */;
4024 pSMB->t2.TotalDataCount = 0;
4025 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4026 /* BB find exact max data count below from sess structure BB */
4027 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4028 pSMB->t2.MaxSetupCount = 0;
4029 pSMB->t2.Reserved = 0;
4030 pSMB->t2.Flags = 0;
4031 pSMB->t2.Timeout = 0;
4032 pSMB->t2.Reserved2 = 0;
4033 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4034 Fid) - 4);
4035 pSMB->t2.DataCount = 0;
4036 pSMB->t2.DataOffset = 0;
4037 pSMB->t2.SetupCount = 1;
4038 pSMB->t2.Reserved3 = 0;
4039 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4040 byte_count = params + 1 /* pad */ ;
4041 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4042 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4043 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4044 pSMB->Pad = 0;
4045 pSMB->Fid = netfid;
4046 inc_rfc1001_len(pSMB, byte_count);
4048 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4049 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4050 if (rc) {
4051 cFYI(1, "Send error in QPathInfo = %d", rc);
4052 } else { /* decode response */
4053 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4055 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4056 rc = -EIO;
4057 else if (get_bcc(&pSMBr->hdr) < 40)
4058 rc = -EIO; /* bad smb */
4059 else if (pFindData) {
4060 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4061 memcpy((char *) pFindData,
4062 (char *) &pSMBr->hdr.Protocol +
4063 data_offset, sizeof(FILE_ALL_INFO));
4064 } else
4065 rc = -ENOMEM;
4067 cifs_buf_release(pSMB);
4068 if (rc == -EAGAIN)
4069 goto QFileInfoRetry;
4071 return rc;
4075 CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
4076 const unsigned char *searchName,
4077 FILE_ALL_INFO *pFindData,
4078 int legacy /* old style infolevel */,
4079 const struct nls_table *nls_codepage, int remap)
4081 /* level 263 SMB_QUERY_FILE_ALL_INFO */
4082 TRANSACTION2_QPI_REQ *pSMB = NULL;
4083 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4084 int rc = 0;
4085 int bytes_returned;
4086 int name_len;
4087 __u16 params, byte_count;
4089 /* cFYI(1, "In QPathInfo path %s", searchName); */
4090 QPathInfoRetry:
4091 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4092 (void **) &pSMBr);
4093 if (rc)
4094 return rc;
4096 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4097 name_len =
4098 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4099 PATH_MAX, nls_codepage, remap);
4100 name_len++; /* trailing null */
4101 name_len *= 2;
4102 } else { /* BB improve the check for buffer overruns BB */
4103 name_len = strnlen(searchName, PATH_MAX);
4104 name_len++; /* trailing null */
4105 strncpy(pSMB->FileName, searchName, name_len);
4108 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
4109 pSMB->TotalDataCount = 0;
4110 pSMB->MaxParameterCount = cpu_to_le16(2);
4111 /* BB find exact max SMB PDU from sess structure BB */
4112 pSMB->MaxDataCount = cpu_to_le16(4000);
4113 pSMB->MaxSetupCount = 0;
4114 pSMB->Reserved = 0;
4115 pSMB->Flags = 0;
4116 pSMB->Timeout = 0;
4117 pSMB->Reserved2 = 0;
4118 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4119 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4120 pSMB->DataCount = 0;
4121 pSMB->DataOffset = 0;
4122 pSMB->SetupCount = 1;
4123 pSMB->Reserved3 = 0;
4124 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4125 byte_count = params + 1 /* pad */ ;
4126 pSMB->TotalParameterCount = cpu_to_le16(params);
4127 pSMB->ParameterCount = pSMB->TotalParameterCount;
4128 if (legacy)
4129 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4130 else
4131 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4132 pSMB->Reserved4 = 0;
4133 inc_rfc1001_len(pSMB, byte_count);
4134 pSMB->ByteCount = cpu_to_le16(byte_count);
4136 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4138 if (rc) {
4139 cFYI(1, "Send error in QPathInfo = %d", rc);
4140 } else { /* decode response */
4141 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4143 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4144 rc = -EIO;
4145 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
4146 rc = -EIO; /* bad smb */
4147 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
4148 rc = -EIO; /* 24 or 26 expected but we do not read
4149 last field */
4150 else if (pFindData) {
4151 int size;
4152 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4154 /* On legacy responses we do not read the last field,
4155 EAsize, fortunately since it varies by subdialect and
4156 also note it differs on Set vs. Get, ie two bytes or 4
4157 bytes depending but we don't care here */
4158 if (legacy)
4159 size = sizeof(FILE_INFO_STANDARD);
4160 else
4161 size = sizeof(FILE_ALL_INFO);
4162 memcpy((char *) pFindData,
4163 (char *) &pSMBr->hdr.Protocol +
4164 data_offset, size);
4165 } else
4166 rc = -ENOMEM;
4168 cifs_buf_release(pSMB);
4169 if (rc == -EAGAIN)
4170 goto QPathInfoRetry;
4172 return rc;
4176 CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
4177 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4179 struct smb_t2_qfi_req *pSMB = NULL;
4180 struct smb_t2_qfi_rsp *pSMBr = NULL;
4181 int rc = 0;
4182 int bytes_returned;
4183 __u16 params, byte_count;
4185 UnixQFileInfoRetry:
4186 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4187 (void **) &pSMBr);
4188 if (rc)
4189 return rc;
4191 params = 2 /* level */ + 2 /* fid */;
4192 pSMB->t2.TotalDataCount = 0;
4193 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4194 /* BB find exact max data count below from sess structure BB */
4195 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4196 pSMB->t2.MaxSetupCount = 0;
4197 pSMB->t2.Reserved = 0;
4198 pSMB->t2.Flags = 0;
4199 pSMB->t2.Timeout = 0;
4200 pSMB->t2.Reserved2 = 0;
4201 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4202 Fid) - 4);
4203 pSMB->t2.DataCount = 0;
4204 pSMB->t2.DataOffset = 0;
4205 pSMB->t2.SetupCount = 1;
4206 pSMB->t2.Reserved3 = 0;
4207 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4208 byte_count = params + 1 /* pad */ ;
4209 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4210 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4211 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4212 pSMB->Pad = 0;
4213 pSMB->Fid = netfid;
4214 inc_rfc1001_len(pSMB, byte_count);
4216 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4217 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4218 if (rc) {
4219 cFYI(1, "Send error in QPathInfo = %d", rc);
4220 } else { /* decode response */
4221 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4223 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4224 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
4225 "Unix Extensions can be disabled on mount "
4226 "by specifying the nosfu mount option.");
4227 rc = -EIO; /* bad smb */
4228 } else {
4229 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4230 memcpy((char *) pFindData,
4231 (char *) &pSMBr->hdr.Protocol +
4232 data_offset,
4233 sizeof(FILE_UNIX_BASIC_INFO));
4237 cifs_buf_release(pSMB);
4238 if (rc == -EAGAIN)
4239 goto UnixQFileInfoRetry;
4241 return rc;
4245 CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
4246 const unsigned char *searchName,
4247 FILE_UNIX_BASIC_INFO *pFindData,
4248 const struct nls_table *nls_codepage, int remap)
4250 /* SMB_QUERY_FILE_UNIX_BASIC */
4251 TRANSACTION2_QPI_REQ *pSMB = NULL;
4252 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4253 int rc = 0;
4254 int bytes_returned = 0;
4255 int name_len;
4256 __u16 params, byte_count;
4258 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
4259 UnixQPathInfoRetry:
4260 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4261 (void **) &pSMBr);
4262 if (rc)
4263 return rc;
4265 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4266 name_len =
4267 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4268 PATH_MAX, nls_codepage, remap);
4269 name_len++; /* trailing null */
4270 name_len *= 2;
4271 } else { /* BB improve the check for buffer overruns BB */
4272 name_len = strnlen(searchName, PATH_MAX);
4273 name_len++; /* trailing null */
4274 strncpy(pSMB->FileName, searchName, name_len);
4277 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
4278 pSMB->TotalDataCount = 0;
4279 pSMB->MaxParameterCount = cpu_to_le16(2);
4280 /* BB find exact max SMB PDU from sess structure BB */
4281 pSMB->MaxDataCount = cpu_to_le16(4000);
4282 pSMB->MaxSetupCount = 0;
4283 pSMB->Reserved = 0;
4284 pSMB->Flags = 0;
4285 pSMB->Timeout = 0;
4286 pSMB->Reserved2 = 0;
4287 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4288 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4289 pSMB->DataCount = 0;
4290 pSMB->DataOffset = 0;
4291 pSMB->SetupCount = 1;
4292 pSMB->Reserved3 = 0;
4293 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4294 byte_count = params + 1 /* pad */ ;
4295 pSMB->TotalParameterCount = cpu_to_le16(params);
4296 pSMB->ParameterCount = pSMB->TotalParameterCount;
4297 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4298 pSMB->Reserved4 = 0;
4299 inc_rfc1001_len(pSMB, byte_count);
4300 pSMB->ByteCount = cpu_to_le16(byte_count);
4302 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4303 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4304 if (rc) {
4305 cFYI(1, "Send error in QPathInfo = %d", rc);
4306 } else { /* decode response */
4307 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4309 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4310 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
4311 "Unix Extensions can be disabled on mount "
4312 "by specifying the nosfu mount option.");
4313 rc = -EIO; /* bad smb */
4314 } else {
4315 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4316 memcpy((char *) pFindData,
4317 (char *) &pSMBr->hdr.Protocol +
4318 data_offset,
4319 sizeof(FILE_UNIX_BASIC_INFO));
4322 cifs_buf_release(pSMB);
4323 if (rc == -EAGAIN)
4324 goto UnixQPathInfoRetry;
4326 return rc;
4329 /* xid, tcon, searchName and codepage are input parms, rest are returned */
4331 CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
4332 const char *searchName,
4333 const struct nls_table *nls_codepage,
4334 __u16 *pnetfid,
4335 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
4337 /* level 257 SMB_ */
4338 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4339 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
4340 T2_FFIRST_RSP_PARMS *parms;
4341 int rc = 0;
4342 int bytes_returned = 0;
4343 int name_len;
4344 __u16 params, byte_count;
4346 cFYI(1, "In FindFirst for %s", searchName);
4348 findFirstRetry:
4349 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4350 (void **) &pSMBr);
4351 if (rc)
4352 return rc;
4354 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4355 name_len =
4356 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4357 PATH_MAX, nls_codepage, remap);
4358 /* We can not add the asterik earlier in case
4359 it got remapped to 0xF03A as if it were part of the
4360 directory name instead of a wildcard */
4361 name_len *= 2;
4362 pSMB->FileName[name_len] = dirsep;
4363 pSMB->FileName[name_len+1] = 0;
4364 pSMB->FileName[name_len+2] = '*';
4365 pSMB->FileName[name_len+3] = 0;
4366 name_len += 4; /* now the trailing null */
4367 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4368 pSMB->FileName[name_len+1] = 0;
4369 name_len += 2;
4370 } else { /* BB add check for overrun of SMB buf BB */
4371 name_len = strnlen(searchName, PATH_MAX);
4372 /* BB fix here and in unicode clause above ie
4373 if (name_len > buffersize-header)
4374 free buffer exit; BB */
4375 strncpy(pSMB->FileName, searchName, name_len);
4376 pSMB->FileName[name_len] = dirsep;
4377 pSMB->FileName[name_len+1] = '*';
4378 pSMB->FileName[name_len+2] = 0;
4379 name_len += 3;
4382 params = 12 + name_len /* includes null */ ;
4383 pSMB->TotalDataCount = 0; /* no EAs */
4384 pSMB->MaxParameterCount = cpu_to_le16(10);
4385 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
4386 pSMB->MaxSetupCount = 0;
4387 pSMB->Reserved = 0;
4388 pSMB->Flags = 0;
4389 pSMB->Timeout = 0;
4390 pSMB->Reserved2 = 0;
4391 byte_count = params + 1 /* pad */ ;
4392 pSMB->TotalParameterCount = cpu_to_le16(params);
4393 pSMB->ParameterCount = pSMB->TotalParameterCount;
4394 pSMB->ParameterOffset = cpu_to_le16(
4395 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4396 - 4);
4397 pSMB->DataCount = 0;
4398 pSMB->DataOffset = 0;
4399 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4400 pSMB->Reserved3 = 0;
4401 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4402 pSMB->SearchAttributes =
4403 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4404 ATTR_DIRECTORY);
4405 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4406 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
4407 CIFS_SEARCH_RETURN_RESUME);
4408 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4410 /* BB what should we set StorageType to? Does it matter? BB */
4411 pSMB->SearchStorageType = 0;
4412 inc_rfc1001_len(pSMB, byte_count);
4413 pSMB->ByteCount = cpu_to_le16(byte_count);
4415 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4416 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4417 cifs_stats_inc(&tcon->num_ffirst);
4419 if (rc) {/* BB add logic to retry regular search if Unix search
4420 rejected unexpectedly by server */
4421 /* BB Add code to handle unsupported level rc */
4422 cFYI(1, "Error in FindFirst = %d", rc);
4424 cifs_buf_release(pSMB);
4426 /* BB eventually could optimize out free and realloc of buf */
4427 /* for this case */
4428 if (rc == -EAGAIN)
4429 goto findFirstRetry;
4430 } else { /* decode response */
4431 /* BB remember to free buffer if error BB */
4432 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4433 if (rc == 0) {
4434 unsigned int lnoff;
4436 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4437 psrch_inf->unicode = true;
4438 else
4439 psrch_inf->unicode = false;
4441 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
4442 psrch_inf->smallBuf = 0;
4443 psrch_inf->srch_entries_start =
4444 (char *) &pSMBr->hdr.Protocol +
4445 le16_to_cpu(pSMBr->t2.DataOffset);
4446 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4447 le16_to_cpu(pSMBr->t2.ParameterOffset));
4449 if (parms->EndofSearch)
4450 psrch_inf->endOfSearch = true;
4451 else
4452 psrch_inf->endOfSearch = false;
4454 psrch_inf->entries_in_buffer =
4455 le16_to_cpu(parms->SearchCount);
4456 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
4457 psrch_inf->entries_in_buffer;
4458 lnoff = le16_to_cpu(parms->LastNameOffset);
4459 if (CIFSMaxBufSize < lnoff) {
4460 cERROR(1, "ignoring corrupt resume name");
4461 psrch_inf->last_entry = NULL;
4462 return rc;
4465 psrch_inf->last_entry = psrch_inf->srch_entries_start +
4466 lnoff;
4468 *pnetfid = parms->SearchHandle;
4469 } else {
4470 cifs_buf_release(pSMB);
4474 return rc;
4477 int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
4478 __u16 searchHandle, struct cifs_search_info *psrch_inf)
4480 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4481 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
4482 T2_FNEXT_RSP_PARMS *parms;
4483 char *response_data;
4484 int rc = 0;
4485 int bytes_returned;
4486 unsigned int name_len;
4487 __u16 params, byte_count;
4489 cFYI(1, "In FindNext");
4491 if (psrch_inf->endOfSearch)
4492 return -ENOENT;
4494 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4495 (void **) &pSMBr);
4496 if (rc)
4497 return rc;
4499 params = 14; /* includes 2 bytes of null string, converted to LE below*/
4500 byte_count = 0;
4501 pSMB->TotalDataCount = 0; /* no EAs */
4502 pSMB->MaxParameterCount = cpu_to_le16(8);
4503 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
4504 pSMB->MaxSetupCount = 0;
4505 pSMB->Reserved = 0;
4506 pSMB->Flags = 0;
4507 pSMB->Timeout = 0;
4508 pSMB->Reserved2 = 0;
4509 pSMB->ParameterOffset = cpu_to_le16(
4510 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4511 pSMB->DataCount = 0;
4512 pSMB->DataOffset = 0;
4513 pSMB->SetupCount = 1;
4514 pSMB->Reserved3 = 0;
4515 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4516 pSMB->SearchHandle = searchHandle; /* always kept as le */
4517 pSMB->SearchCount =
4518 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
4519 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4520 pSMB->ResumeKey = psrch_inf->resume_key;
4521 pSMB->SearchFlags =
4522 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
4524 name_len = psrch_inf->resume_name_len;
4525 params += name_len;
4526 if (name_len < PATH_MAX) {
4527 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4528 byte_count += name_len;
4529 /* 14 byte parm len above enough for 2 byte null terminator */
4530 pSMB->ResumeFileName[name_len] = 0;
4531 pSMB->ResumeFileName[name_len+1] = 0;
4532 } else {
4533 rc = -EINVAL;
4534 goto FNext2_err_exit;
4536 byte_count = params + 1 /* pad */ ;
4537 pSMB->TotalParameterCount = cpu_to_le16(params);
4538 pSMB->ParameterCount = pSMB->TotalParameterCount;
4539 inc_rfc1001_len(pSMB, byte_count);
4540 pSMB->ByteCount = cpu_to_le16(byte_count);
4542 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4543 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4544 cifs_stats_inc(&tcon->num_fnext);
4545 if (rc) {
4546 if (rc == -EBADF) {
4547 psrch_inf->endOfSearch = true;
4548 cifs_buf_release(pSMB);
4549 rc = 0; /* search probably was closed at end of search*/
4550 } else
4551 cFYI(1, "FindNext returned = %d", rc);
4552 } else { /* decode response */
4553 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4555 if (rc == 0) {
4556 unsigned int lnoff;
4558 /* BB fixme add lock for file (srch_info) struct here */
4559 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4560 psrch_inf->unicode = true;
4561 else
4562 psrch_inf->unicode = false;
4563 response_data = (char *) &pSMBr->hdr.Protocol +
4564 le16_to_cpu(pSMBr->t2.ParameterOffset);
4565 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4566 response_data = (char *)&pSMBr->hdr.Protocol +
4567 le16_to_cpu(pSMBr->t2.DataOffset);
4568 if (psrch_inf->smallBuf)
4569 cifs_small_buf_release(
4570 psrch_inf->ntwrk_buf_start);
4571 else
4572 cifs_buf_release(psrch_inf->ntwrk_buf_start);
4573 psrch_inf->srch_entries_start = response_data;
4574 psrch_inf->ntwrk_buf_start = (char *)pSMB;
4575 psrch_inf->smallBuf = 0;
4576 if (parms->EndofSearch)
4577 psrch_inf->endOfSearch = true;
4578 else
4579 psrch_inf->endOfSearch = false;
4580 psrch_inf->entries_in_buffer =
4581 le16_to_cpu(parms->SearchCount);
4582 psrch_inf->index_of_last_entry +=
4583 psrch_inf->entries_in_buffer;
4584 lnoff = le16_to_cpu(parms->LastNameOffset);
4585 if (CIFSMaxBufSize < lnoff) {
4586 cERROR(1, "ignoring corrupt resume name");
4587 psrch_inf->last_entry = NULL;
4588 return rc;
4589 } else
4590 psrch_inf->last_entry =
4591 psrch_inf->srch_entries_start + lnoff;
4593 /* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4594 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
4596 /* BB fixme add unlock here */
4601 /* BB On error, should we leave previous search buf (and count and
4602 last entry fields) intact or free the previous one? */
4604 /* Note: On -EAGAIN error only caller can retry on handle based calls
4605 since file handle passed in no longer valid */
4606 FNext2_err_exit:
4607 if (rc != 0)
4608 cifs_buf_release(pSMB);
4609 return rc;
4613 CIFSFindClose(const int xid, struct cifs_tcon *tcon,
4614 const __u16 searchHandle)
4616 int rc = 0;
4617 FINDCLOSE_REQ *pSMB = NULL;
4619 cFYI(1, "In CIFSSMBFindClose");
4620 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4622 /* no sense returning error if session restarted
4623 as file handle has been closed */
4624 if (rc == -EAGAIN)
4625 return 0;
4626 if (rc)
4627 return rc;
4629 pSMB->FileID = searchHandle;
4630 pSMB->ByteCount = 0;
4631 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4632 if (rc)
4633 cERROR(1, "Send error in FindClose = %d", rc);
4635 cifs_stats_inc(&tcon->num_fclose);
4637 /* Since session is dead, search handle closed on server already */
4638 if (rc == -EAGAIN)
4639 rc = 0;
4641 return rc;
4645 CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
4646 const unsigned char *searchName,
4647 __u64 *inode_number,
4648 const struct nls_table *nls_codepage, int remap)
4650 int rc = 0;
4651 TRANSACTION2_QPI_REQ *pSMB = NULL;
4652 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4653 int name_len, bytes_returned;
4654 __u16 params, byte_count;
4656 cFYI(1, "In GetSrvInodeNum for %s", searchName);
4657 if (tcon == NULL)
4658 return -ENODEV;
4660 GetInodeNumberRetry:
4661 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4662 (void **) &pSMBr);
4663 if (rc)
4664 return rc;
4666 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4667 name_len =
4668 cifsConvertToUTF16((__le16 *) pSMB->FileName,
4669 searchName, PATH_MAX, nls_codepage,
4670 remap);
4671 name_len++; /* trailing null */
4672 name_len *= 2;
4673 } else { /* BB improve the check for buffer overruns BB */
4674 name_len = strnlen(searchName, PATH_MAX);
4675 name_len++; /* trailing null */
4676 strncpy(pSMB->FileName, searchName, name_len);
4679 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4680 pSMB->TotalDataCount = 0;
4681 pSMB->MaxParameterCount = cpu_to_le16(2);
4682 /* BB find exact max data count below from sess structure BB */
4683 pSMB->MaxDataCount = cpu_to_le16(4000);
4684 pSMB->MaxSetupCount = 0;
4685 pSMB->Reserved = 0;
4686 pSMB->Flags = 0;
4687 pSMB->Timeout = 0;
4688 pSMB->Reserved2 = 0;
4689 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4690 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4691 pSMB->DataCount = 0;
4692 pSMB->DataOffset = 0;
4693 pSMB->SetupCount = 1;
4694 pSMB->Reserved3 = 0;
4695 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4696 byte_count = params + 1 /* pad */ ;
4697 pSMB->TotalParameterCount = cpu_to_le16(params);
4698 pSMB->ParameterCount = pSMB->TotalParameterCount;
4699 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4700 pSMB->Reserved4 = 0;
4701 inc_rfc1001_len(pSMB, byte_count);
4702 pSMB->ByteCount = cpu_to_le16(byte_count);
4704 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4705 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4706 if (rc) {
4707 cFYI(1, "error %d in QueryInternalInfo", rc);
4708 } else {
4709 /* decode response */
4710 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4711 /* BB also check enough total bytes returned */
4712 if (rc || get_bcc(&pSMBr->hdr) < 2)
4713 /* If rc should we check for EOPNOSUPP and
4714 disable the srvino flag? or in caller? */
4715 rc = -EIO; /* bad smb */
4716 else {
4717 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4718 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
4719 struct file_internal_info *pfinfo;
4720 /* BB Do we need a cast or hash here ? */
4721 if (count < 8) {
4722 cFYI(1, "Illegal size ret in QryIntrnlInf");
4723 rc = -EIO;
4724 goto GetInodeNumOut;
4726 pfinfo = (struct file_internal_info *)
4727 (data_offset + (char *) &pSMBr->hdr.Protocol);
4728 *inode_number = le64_to_cpu(pfinfo->UniqueId);
4731 GetInodeNumOut:
4732 cifs_buf_release(pSMB);
4733 if (rc == -EAGAIN)
4734 goto GetInodeNumberRetry;
4735 return rc;
4738 /* parses DFS refferal V3 structure
4739 * caller is responsible for freeing target_nodes
4740 * returns:
4741 * on success - 0
4742 * on failure - errno
4744 static int
4745 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
4746 unsigned int *num_of_nodes,
4747 struct dfs_info3_param **target_nodes,
4748 const struct nls_table *nls_codepage, int remap,
4749 const char *searchName)
4751 int i, rc = 0;
4752 char *data_end;
4753 bool is_unicode;
4754 struct dfs_referral_level_3 *ref;
4756 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4757 is_unicode = true;
4758 else
4759 is_unicode = false;
4760 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4762 if (*num_of_nodes < 1) {
4763 cERROR(1, "num_referrals: must be at least > 0,"
4764 "but we get num_referrals = %d\n", *num_of_nodes);
4765 rc = -EINVAL;
4766 goto parse_DFS_referrals_exit;
4769 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
4770 if (ref->VersionNumber != cpu_to_le16(3)) {
4771 cERROR(1, "Referrals of V%d version are not supported,"
4772 "should be V3", le16_to_cpu(ref->VersionNumber));
4773 rc = -EINVAL;
4774 goto parse_DFS_referrals_exit;
4777 /* get the upper boundary of the resp buffer */
4778 data_end = (char *)(&(pSMBr->PathConsumed)) +
4779 le16_to_cpu(pSMBr->t2.DataCount);
4781 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
4782 *num_of_nodes,
4783 le32_to_cpu(pSMBr->DFSFlags));
4785 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4786 *num_of_nodes, GFP_KERNEL);
4787 if (*target_nodes == NULL) {
4788 cERROR(1, "Failed to allocate buffer for target_nodes\n");
4789 rc = -ENOMEM;
4790 goto parse_DFS_referrals_exit;
4793 /* collect necessary data from referrals */
4794 for (i = 0; i < *num_of_nodes; i++) {
4795 char *temp;
4796 int max_len;
4797 struct dfs_info3_param *node = (*target_nodes)+i;
4799 node->flags = le32_to_cpu(pSMBr->DFSFlags);
4800 if (is_unicode) {
4801 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4802 GFP_KERNEL);
4803 if (tmp == NULL) {
4804 rc = -ENOMEM;
4805 goto parse_DFS_referrals_exit;
4807 cifsConvertToUTF16((__le16 *) tmp, searchName,
4808 PATH_MAX, nls_codepage, remap);
4809 node->path_consumed = cifs_utf16_bytes(tmp,
4810 le16_to_cpu(pSMBr->PathConsumed),
4811 nls_codepage);
4812 kfree(tmp);
4813 } else
4814 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4816 node->server_type = le16_to_cpu(ref->ServerType);
4817 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4819 /* copy DfsPath */
4820 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4821 max_len = data_end - temp;
4822 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4823 is_unicode, nls_codepage);
4824 if (!node->path_name) {
4825 rc = -ENOMEM;
4826 goto parse_DFS_referrals_exit;
4829 /* copy link target UNC */
4830 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4831 max_len = data_end - temp;
4832 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4833 is_unicode, nls_codepage);
4834 if (!node->node_name) {
4835 rc = -ENOMEM;
4836 goto parse_DFS_referrals_exit;
4839 ref++;
4842 parse_DFS_referrals_exit:
4843 if (rc) {
4844 free_dfs_info_array(*target_nodes, *num_of_nodes);
4845 *target_nodes = NULL;
4846 *num_of_nodes = 0;
4848 return rc;
4852 CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
4853 const unsigned char *searchName,
4854 struct dfs_info3_param **target_nodes,
4855 unsigned int *num_of_nodes,
4856 const struct nls_table *nls_codepage, int remap)
4858 /* TRANS2_GET_DFS_REFERRAL */
4859 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4860 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4861 int rc = 0;
4862 int bytes_returned;
4863 int name_len;
4864 __u16 params, byte_count;
4865 *num_of_nodes = 0;
4866 *target_nodes = NULL;
4868 cFYI(1, "In GetDFSRefer the path %s", searchName);
4869 if (ses == NULL)
4870 return -ENODEV;
4871 getDFSRetry:
4872 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4873 (void **) &pSMBr);
4874 if (rc)
4875 return rc;
4877 /* server pointer checked in called function,
4878 but should never be null here anyway */
4879 pSMB->hdr.Mid = GetNextMid(ses->server);
4880 pSMB->hdr.Tid = ses->ipc_tid;
4881 pSMB->hdr.Uid = ses->Suid;
4882 if (ses->capabilities & CAP_STATUS32)
4883 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4884 if (ses->capabilities & CAP_DFS)
4885 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4887 if (ses->capabilities & CAP_UNICODE) {
4888 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4889 name_len =
4890 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4891 searchName, PATH_MAX, nls_codepage,
4892 remap);
4893 name_len++; /* trailing null */
4894 name_len *= 2;
4895 } else { /* BB improve the check for buffer overruns BB */
4896 name_len = strnlen(searchName, PATH_MAX);
4897 name_len++; /* trailing null */
4898 strncpy(pSMB->RequestFileName, searchName, name_len);
4901 if (ses->server) {
4902 if (ses->server->sec_mode &
4903 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4904 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4907 pSMB->hdr.Uid = ses->Suid;
4909 params = 2 /* level */ + name_len /*includes null */ ;
4910 pSMB->TotalDataCount = 0;
4911 pSMB->DataCount = 0;
4912 pSMB->DataOffset = 0;
4913 pSMB->MaxParameterCount = 0;
4914 /* BB find exact max SMB PDU from sess structure BB */
4915 pSMB->MaxDataCount = cpu_to_le16(4000);
4916 pSMB->MaxSetupCount = 0;
4917 pSMB->Reserved = 0;
4918 pSMB->Flags = 0;
4919 pSMB->Timeout = 0;
4920 pSMB->Reserved2 = 0;
4921 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4922 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4923 pSMB->SetupCount = 1;
4924 pSMB->Reserved3 = 0;
4925 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4926 byte_count = params + 3 /* pad */ ;
4927 pSMB->ParameterCount = cpu_to_le16(params);
4928 pSMB->TotalParameterCount = pSMB->ParameterCount;
4929 pSMB->MaxReferralLevel = cpu_to_le16(3);
4930 inc_rfc1001_len(pSMB, byte_count);
4931 pSMB->ByteCount = cpu_to_le16(byte_count);
4933 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4934 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4935 if (rc) {
4936 cFYI(1, "Send error in GetDFSRefer = %d", rc);
4937 goto GetDFSRefExit;
4939 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4941 /* BB Also check if enough total bytes returned? */
4942 if (rc || get_bcc(&pSMBr->hdr) < 17) {
4943 rc = -EIO; /* bad smb */
4944 goto GetDFSRefExit;
4947 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
4948 get_bcc(&pSMBr->hdr),
4949 le16_to_cpu(pSMBr->t2.DataOffset));
4951 /* parse returned result into more usable form */
4952 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4953 target_nodes, nls_codepage, remap,
4954 searchName);
4956 GetDFSRefExit:
4957 cifs_buf_release(pSMB);
4959 if (rc == -EAGAIN)
4960 goto getDFSRetry;
4962 return rc;
4965 /* Query File System Info such as free space to old servers such as Win 9x */
4967 SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
4969 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4970 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4971 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4972 FILE_SYSTEM_ALLOC_INFO *response_data;
4973 int rc = 0;
4974 int bytes_returned = 0;
4975 __u16 params, byte_count;
4977 cFYI(1, "OldQFSInfo");
4978 oldQFSInfoRetry:
4979 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4980 (void **) &pSMBr);
4981 if (rc)
4982 return rc;
4984 params = 2; /* level */
4985 pSMB->TotalDataCount = 0;
4986 pSMB->MaxParameterCount = cpu_to_le16(2);
4987 pSMB->MaxDataCount = cpu_to_le16(1000);
4988 pSMB->MaxSetupCount = 0;
4989 pSMB->Reserved = 0;
4990 pSMB->Flags = 0;
4991 pSMB->Timeout = 0;
4992 pSMB->Reserved2 = 0;
4993 byte_count = params + 1 /* pad */ ;
4994 pSMB->TotalParameterCount = cpu_to_le16(params);
4995 pSMB->ParameterCount = pSMB->TotalParameterCount;
4996 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4997 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4998 pSMB->DataCount = 0;
4999 pSMB->DataOffset = 0;
5000 pSMB->SetupCount = 1;
5001 pSMB->Reserved3 = 0;
5002 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5003 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
5004 inc_rfc1001_len(pSMB, byte_count);
5005 pSMB->ByteCount = cpu_to_le16(byte_count);
5007 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5008 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5009 if (rc) {
5010 cFYI(1, "Send error in QFSInfo = %d", rc);
5011 } else { /* decode response */
5012 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5014 if (rc || get_bcc(&pSMBr->hdr) < 18)
5015 rc = -EIO; /* bad smb */
5016 else {
5017 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5018 cFYI(1, "qfsinf resp BCC: %d Offset %d",
5019 get_bcc(&pSMBr->hdr), data_offset);
5021 response_data = (FILE_SYSTEM_ALLOC_INFO *)
5022 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5023 FSData->f_bsize =
5024 le16_to_cpu(response_data->BytesPerSector) *
5025 le32_to_cpu(response_data->
5026 SectorsPerAllocationUnit);
5027 FSData->f_blocks =
5028 le32_to_cpu(response_data->TotalAllocationUnits);
5029 FSData->f_bfree = FSData->f_bavail =
5030 le32_to_cpu(response_data->FreeAllocationUnits);
5031 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5032 (unsigned long long)FSData->f_blocks,
5033 (unsigned long long)FSData->f_bfree,
5034 FSData->f_bsize);
5037 cifs_buf_release(pSMB);
5039 if (rc == -EAGAIN)
5040 goto oldQFSInfoRetry;
5042 return rc;
5046 CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
5048 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5049 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5050 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5051 FILE_SYSTEM_INFO *response_data;
5052 int rc = 0;
5053 int bytes_returned = 0;
5054 __u16 params, byte_count;
5056 cFYI(1, "In QFSInfo");
5057 QFSInfoRetry:
5058 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5059 (void **) &pSMBr);
5060 if (rc)
5061 return rc;
5063 params = 2; /* level */
5064 pSMB->TotalDataCount = 0;
5065 pSMB->MaxParameterCount = cpu_to_le16(2);
5066 pSMB->MaxDataCount = cpu_to_le16(1000);
5067 pSMB->MaxSetupCount = 0;
5068 pSMB->Reserved = 0;
5069 pSMB->Flags = 0;
5070 pSMB->Timeout = 0;
5071 pSMB->Reserved2 = 0;
5072 byte_count = params + 1 /* pad */ ;
5073 pSMB->TotalParameterCount = cpu_to_le16(params);
5074 pSMB->ParameterCount = pSMB->TotalParameterCount;
5075 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5076 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5077 pSMB->DataCount = 0;
5078 pSMB->DataOffset = 0;
5079 pSMB->SetupCount = 1;
5080 pSMB->Reserved3 = 0;
5081 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5082 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
5083 inc_rfc1001_len(pSMB, byte_count);
5084 pSMB->ByteCount = cpu_to_le16(byte_count);
5086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5088 if (rc) {
5089 cFYI(1, "Send error in QFSInfo = %d", rc);
5090 } else { /* decode response */
5091 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5093 if (rc || get_bcc(&pSMBr->hdr) < 24)
5094 rc = -EIO; /* bad smb */
5095 else {
5096 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5098 response_data =
5099 (FILE_SYSTEM_INFO
5100 *) (((char *) &pSMBr->hdr.Protocol) +
5101 data_offset);
5102 FSData->f_bsize =
5103 le32_to_cpu(response_data->BytesPerSector) *
5104 le32_to_cpu(response_data->
5105 SectorsPerAllocationUnit);
5106 FSData->f_blocks =
5107 le64_to_cpu(response_data->TotalAllocationUnits);
5108 FSData->f_bfree = FSData->f_bavail =
5109 le64_to_cpu(response_data->FreeAllocationUnits);
5110 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5111 (unsigned long long)FSData->f_blocks,
5112 (unsigned long long)FSData->f_bfree,
5113 FSData->f_bsize);
5116 cifs_buf_release(pSMB);
5118 if (rc == -EAGAIN)
5119 goto QFSInfoRetry;
5121 return rc;
5125 CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
5127 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5128 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5129 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5130 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5131 int rc = 0;
5132 int bytes_returned = 0;
5133 __u16 params, byte_count;
5135 cFYI(1, "In QFSAttributeInfo");
5136 QFSAttributeRetry:
5137 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5138 (void **) &pSMBr);
5139 if (rc)
5140 return rc;
5142 params = 2; /* level */
5143 pSMB->TotalDataCount = 0;
5144 pSMB->MaxParameterCount = cpu_to_le16(2);
5145 /* BB find exact max SMB PDU from sess structure BB */
5146 pSMB->MaxDataCount = cpu_to_le16(1000);
5147 pSMB->MaxSetupCount = 0;
5148 pSMB->Reserved = 0;
5149 pSMB->Flags = 0;
5150 pSMB->Timeout = 0;
5151 pSMB->Reserved2 = 0;
5152 byte_count = params + 1 /* pad */ ;
5153 pSMB->TotalParameterCount = cpu_to_le16(params);
5154 pSMB->ParameterCount = pSMB->TotalParameterCount;
5155 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5156 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5157 pSMB->DataCount = 0;
5158 pSMB->DataOffset = 0;
5159 pSMB->SetupCount = 1;
5160 pSMB->Reserved3 = 0;
5161 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5162 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
5163 inc_rfc1001_len(pSMB, byte_count);
5164 pSMB->ByteCount = cpu_to_le16(byte_count);
5166 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5167 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5168 if (rc) {
5169 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
5170 } else { /* decode response */
5171 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5173 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5174 /* BB also check if enough bytes returned */
5175 rc = -EIO; /* bad smb */
5176 } else {
5177 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5178 response_data =
5179 (FILE_SYSTEM_ATTRIBUTE_INFO
5180 *) (((char *) &pSMBr->hdr.Protocol) +
5181 data_offset);
5182 memcpy(&tcon->fsAttrInfo, response_data,
5183 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
5186 cifs_buf_release(pSMB);
5188 if (rc == -EAGAIN)
5189 goto QFSAttributeRetry;
5191 return rc;
5195 CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
5197 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5198 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5199 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5200 FILE_SYSTEM_DEVICE_INFO *response_data;
5201 int rc = 0;
5202 int bytes_returned = 0;
5203 __u16 params, byte_count;
5205 cFYI(1, "In QFSDeviceInfo");
5206 QFSDeviceRetry:
5207 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5208 (void **) &pSMBr);
5209 if (rc)
5210 return rc;
5212 params = 2; /* level */
5213 pSMB->TotalDataCount = 0;
5214 pSMB->MaxParameterCount = cpu_to_le16(2);
5215 /* BB find exact max SMB PDU from sess structure BB */
5216 pSMB->MaxDataCount = cpu_to_le16(1000);
5217 pSMB->MaxSetupCount = 0;
5218 pSMB->Reserved = 0;
5219 pSMB->Flags = 0;
5220 pSMB->Timeout = 0;
5221 pSMB->Reserved2 = 0;
5222 byte_count = params + 1 /* pad */ ;
5223 pSMB->TotalParameterCount = cpu_to_le16(params);
5224 pSMB->ParameterCount = pSMB->TotalParameterCount;
5225 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5226 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5228 pSMB->DataCount = 0;
5229 pSMB->DataOffset = 0;
5230 pSMB->SetupCount = 1;
5231 pSMB->Reserved3 = 0;
5232 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5233 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
5234 inc_rfc1001_len(pSMB, byte_count);
5235 pSMB->ByteCount = cpu_to_le16(byte_count);
5237 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5238 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5239 if (rc) {
5240 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
5241 } else { /* decode response */
5242 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5244 if (rc || get_bcc(&pSMBr->hdr) <
5245 sizeof(FILE_SYSTEM_DEVICE_INFO))
5246 rc = -EIO; /* bad smb */
5247 else {
5248 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5249 response_data =
5250 (FILE_SYSTEM_DEVICE_INFO *)
5251 (((char *) &pSMBr->hdr.Protocol) +
5252 data_offset);
5253 memcpy(&tcon->fsDevInfo, response_data,
5254 sizeof(FILE_SYSTEM_DEVICE_INFO));
5257 cifs_buf_release(pSMB);
5259 if (rc == -EAGAIN)
5260 goto QFSDeviceRetry;
5262 return rc;
5266 CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
5268 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5269 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5270 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5271 FILE_SYSTEM_UNIX_INFO *response_data;
5272 int rc = 0;
5273 int bytes_returned = 0;
5274 __u16 params, byte_count;
5276 cFYI(1, "In QFSUnixInfo");
5277 QFSUnixRetry:
5278 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5279 (void **) &pSMB, (void **) &pSMBr);
5280 if (rc)
5281 return rc;
5283 params = 2; /* level */
5284 pSMB->TotalDataCount = 0;
5285 pSMB->DataCount = 0;
5286 pSMB->DataOffset = 0;
5287 pSMB->MaxParameterCount = cpu_to_le16(2);
5288 /* BB find exact max SMB PDU from sess structure BB */
5289 pSMB->MaxDataCount = cpu_to_le16(100);
5290 pSMB->MaxSetupCount = 0;
5291 pSMB->Reserved = 0;
5292 pSMB->Flags = 0;
5293 pSMB->Timeout = 0;
5294 pSMB->Reserved2 = 0;
5295 byte_count = params + 1 /* pad */ ;
5296 pSMB->ParameterCount = cpu_to_le16(params);
5297 pSMB->TotalParameterCount = pSMB->ParameterCount;
5298 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5299 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5300 pSMB->SetupCount = 1;
5301 pSMB->Reserved3 = 0;
5302 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5303 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
5304 inc_rfc1001_len(pSMB, byte_count);
5305 pSMB->ByteCount = cpu_to_le16(byte_count);
5307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5309 if (rc) {
5310 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
5311 } else { /* decode response */
5312 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5314 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5315 rc = -EIO; /* bad smb */
5316 } else {
5317 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5318 response_data =
5319 (FILE_SYSTEM_UNIX_INFO
5320 *) (((char *) &pSMBr->hdr.Protocol) +
5321 data_offset);
5322 memcpy(&tcon->fsUnixInfo, response_data,
5323 sizeof(FILE_SYSTEM_UNIX_INFO));
5326 cifs_buf_release(pSMB);
5328 if (rc == -EAGAIN)
5329 goto QFSUnixRetry;
5332 return rc;
5336 CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
5338 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5339 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5340 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5341 int rc = 0;
5342 int bytes_returned = 0;
5343 __u16 params, param_offset, offset, byte_count;
5345 cFYI(1, "In SETFSUnixInfo");
5346 SETFSUnixRetry:
5347 /* BB switch to small buf init to save memory */
5348 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5349 (void **) &pSMB, (void **) &pSMBr);
5350 if (rc)
5351 return rc;
5353 params = 4; /* 2 bytes zero followed by info level. */
5354 pSMB->MaxSetupCount = 0;
5355 pSMB->Reserved = 0;
5356 pSMB->Flags = 0;
5357 pSMB->Timeout = 0;
5358 pSMB->Reserved2 = 0;
5359 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5360 - 4;
5361 offset = param_offset + params;
5363 pSMB->MaxParameterCount = cpu_to_le16(4);
5364 /* BB find exact max SMB PDU from sess structure BB */
5365 pSMB->MaxDataCount = cpu_to_le16(100);
5366 pSMB->SetupCount = 1;
5367 pSMB->Reserved3 = 0;
5368 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5369 byte_count = 1 /* pad */ + params + 12;
5371 pSMB->DataCount = cpu_to_le16(12);
5372 pSMB->ParameterCount = cpu_to_le16(params);
5373 pSMB->TotalDataCount = pSMB->DataCount;
5374 pSMB->TotalParameterCount = pSMB->ParameterCount;
5375 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5376 pSMB->DataOffset = cpu_to_le16(offset);
5378 /* Params. */
5379 pSMB->FileNum = 0;
5380 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5382 /* Data. */
5383 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5384 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5385 pSMB->ClientUnixCap = cpu_to_le64(cap);
5387 inc_rfc1001_len(pSMB, byte_count);
5388 pSMB->ByteCount = cpu_to_le16(byte_count);
5390 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5391 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5392 if (rc) {
5393 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
5394 } else { /* decode response */
5395 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5396 if (rc)
5397 rc = -EIO; /* bad smb */
5399 cifs_buf_release(pSMB);
5401 if (rc == -EAGAIN)
5402 goto SETFSUnixRetry;
5404 return rc;
5410 CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
5411 struct kstatfs *FSData)
5413 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5414 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5415 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5416 FILE_SYSTEM_POSIX_INFO *response_data;
5417 int rc = 0;
5418 int bytes_returned = 0;
5419 __u16 params, byte_count;
5421 cFYI(1, "In QFSPosixInfo");
5422 QFSPosixRetry:
5423 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5424 (void **) &pSMBr);
5425 if (rc)
5426 return rc;
5428 params = 2; /* level */
5429 pSMB->TotalDataCount = 0;
5430 pSMB->DataCount = 0;
5431 pSMB->DataOffset = 0;
5432 pSMB->MaxParameterCount = cpu_to_le16(2);
5433 /* BB find exact max SMB PDU from sess structure BB */
5434 pSMB->MaxDataCount = cpu_to_le16(100);
5435 pSMB->MaxSetupCount = 0;
5436 pSMB->Reserved = 0;
5437 pSMB->Flags = 0;
5438 pSMB->Timeout = 0;
5439 pSMB->Reserved2 = 0;
5440 byte_count = params + 1 /* pad */ ;
5441 pSMB->ParameterCount = cpu_to_le16(params);
5442 pSMB->TotalParameterCount = pSMB->ParameterCount;
5443 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5444 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5445 pSMB->SetupCount = 1;
5446 pSMB->Reserved3 = 0;
5447 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5448 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
5449 inc_rfc1001_len(pSMB, byte_count);
5450 pSMB->ByteCount = cpu_to_le16(byte_count);
5452 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5453 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5454 if (rc) {
5455 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
5456 } else { /* decode response */
5457 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5459 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5460 rc = -EIO; /* bad smb */
5461 } else {
5462 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5463 response_data =
5464 (FILE_SYSTEM_POSIX_INFO
5465 *) (((char *) &pSMBr->hdr.Protocol) +
5466 data_offset);
5467 FSData->f_bsize =
5468 le32_to_cpu(response_data->BlockSize);
5469 FSData->f_blocks =
5470 le64_to_cpu(response_data->TotalBlocks);
5471 FSData->f_bfree =
5472 le64_to_cpu(response_data->BlocksAvail);
5473 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
5474 FSData->f_bavail = FSData->f_bfree;
5475 } else {
5476 FSData->f_bavail =
5477 le64_to_cpu(response_data->UserBlocksAvail);
5479 if (response_data->TotalFileNodes != cpu_to_le64(-1))
5480 FSData->f_files =
5481 le64_to_cpu(response_data->TotalFileNodes);
5482 if (response_data->FreeFileNodes != cpu_to_le64(-1))
5483 FSData->f_ffree =
5484 le64_to_cpu(response_data->FreeFileNodes);
5487 cifs_buf_release(pSMB);
5489 if (rc == -EAGAIN)
5490 goto QFSPosixRetry;
5492 return rc;
5496 /* We can not use write of zero bytes trick to
5497 set file size due to need for large file support. Also note that
5498 this SetPathInfo is preferred to SetFileInfo based method in next
5499 routine which is only needed to work around a sharing violation bug
5500 in Samba which this routine can run into */
5503 CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
5504 __u64 size, bool SetAllocation,
5505 const struct nls_table *nls_codepage, int remap)
5507 struct smb_com_transaction2_spi_req *pSMB = NULL;
5508 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5509 struct file_end_of_file_info *parm_data;
5510 int name_len;
5511 int rc = 0;
5512 int bytes_returned = 0;
5513 __u16 params, byte_count, data_count, param_offset, offset;
5515 cFYI(1, "In SetEOF");
5516 SetEOFRetry:
5517 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5518 (void **) &pSMBr);
5519 if (rc)
5520 return rc;
5522 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5523 name_len =
5524 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5525 PATH_MAX, nls_codepage, remap);
5526 name_len++; /* trailing null */
5527 name_len *= 2;
5528 } else { /* BB improve the check for buffer overruns BB */
5529 name_len = strnlen(fileName, PATH_MAX);
5530 name_len++; /* trailing null */
5531 strncpy(pSMB->FileName, fileName, name_len);
5533 params = 6 + name_len;
5534 data_count = sizeof(struct file_end_of_file_info);
5535 pSMB->MaxParameterCount = cpu_to_le16(2);
5536 pSMB->MaxDataCount = cpu_to_le16(4100);
5537 pSMB->MaxSetupCount = 0;
5538 pSMB->Reserved = 0;
5539 pSMB->Flags = 0;
5540 pSMB->Timeout = 0;
5541 pSMB->Reserved2 = 0;
5542 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5543 InformationLevel) - 4;
5544 offset = param_offset + params;
5545 if (SetAllocation) {
5546 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5547 pSMB->InformationLevel =
5548 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5549 else
5550 pSMB->InformationLevel =
5551 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5552 } else /* Set File Size */ {
5553 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5554 pSMB->InformationLevel =
5555 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
5556 else
5557 pSMB->InformationLevel =
5558 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
5561 parm_data =
5562 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5563 offset);
5564 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5565 pSMB->DataOffset = cpu_to_le16(offset);
5566 pSMB->SetupCount = 1;
5567 pSMB->Reserved3 = 0;
5568 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5569 byte_count = 3 /* pad */ + params + data_count;
5570 pSMB->DataCount = cpu_to_le16(data_count);
5571 pSMB->TotalDataCount = pSMB->DataCount;
5572 pSMB->ParameterCount = cpu_to_le16(params);
5573 pSMB->TotalParameterCount = pSMB->ParameterCount;
5574 pSMB->Reserved4 = 0;
5575 inc_rfc1001_len(pSMB, byte_count);
5576 parm_data->FileSize = cpu_to_le64(size);
5577 pSMB->ByteCount = cpu_to_le16(byte_count);
5578 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5579 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5580 if (rc)
5581 cFYI(1, "SetPathInfo (file size) returned %d", rc);
5583 cifs_buf_release(pSMB);
5585 if (rc == -EAGAIN)
5586 goto SetEOFRetry;
5588 return rc;
5592 CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
5593 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
5595 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5596 struct file_end_of_file_info *parm_data;
5597 int rc = 0;
5598 __u16 params, param_offset, offset, byte_count, count;
5600 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5601 (long long)size);
5602 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5604 if (rc)
5605 return rc;
5607 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5608 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5610 params = 6;
5611 pSMB->MaxSetupCount = 0;
5612 pSMB->Reserved = 0;
5613 pSMB->Flags = 0;
5614 pSMB->Timeout = 0;
5615 pSMB->Reserved2 = 0;
5616 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5617 offset = param_offset + params;
5619 count = sizeof(struct file_end_of_file_info);
5620 pSMB->MaxParameterCount = cpu_to_le16(2);
5621 /* BB find exact max SMB PDU from sess structure BB */
5622 pSMB->MaxDataCount = cpu_to_le16(1000);
5623 pSMB->SetupCount = 1;
5624 pSMB->Reserved3 = 0;
5625 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5626 byte_count = 3 /* pad */ + params + count;
5627 pSMB->DataCount = cpu_to_le16(count);
5628 pSMB->ParameterCount = cpu_to_le16(params);
5629 pSMB->TotalDataCount = pSMB->DataCount;
5630 pSMB->TotalParameterCount = pSMB->ParameterCount;
5631 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5632 parm_data =
5633 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5634 + offset);
5635 pSMB->DataOffset = cpu_to_le16(offset);
5636 parm_data->FileSize = cpu_to_le64(size);
5637 pSMB->Fid = fid;
5638 if (SetAllocation) {
5639 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5640 pSMB->InformationLevel =
5641 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5642 else
5643 pSMB->InformationLevel =
5644 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5645 } else /* Set File Size */ {
5646 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5647 pSMB->InformationLevel =
5648 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
5649 else
5650 pSMB->InformationLevel =
5651 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
5653 pSMB->Reserved4 = 0;
5654 inc_rfc1001_len(pSMB, byte_count);
5655 pSMB->ByteCount = cpu_to_le16(byte_count);
5656 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5657 if (rc) {
5658 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
5661 /* Note: On -EAGAIN error only caller can retry on handle based calls
5662 since file handle passed in no longer valid */
5664 return rc;
5667 /* Some legacy servers such as NT4 require that the file times be set on
5668 an open handle, rather than by pathname - this is awkward due to
5669 potential access conflicts on the open, but it is unavoidable for these
5670 old servers since the only other choice is to go from 100 nanosecond DCE
5671 time and resort to the original setpathinfo level which takes the ancient
5672 DOS time format with 2 second granularity */
5674 CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
5675 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
5677 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5678 char *data_offset;
5679 int rc = 0;
5680 __u16 params, param_offset, offset, byte_count, count;
5682 cFYI(1, "Set Times (via SetFileInfo)");
5683 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5685 if (rc)
5686 return rc;
5688 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5689 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5691 params = 6;
5692 pSMB->MaxSetupCount = 0;
5693 pSMB->Reserved = 0;
5694 pSMB->Flags = 0;
5695 pSMB->Timeout = 0;
5696 pSMB->Reserved2 = 0;
5697 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5698 offset = param_offset + params;
5700 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5702 count = sizeof(FILE_BASIC_INFO);
5703 pSMB->MaxParameterCount = cpu_to_le16(2);
5704 /* BB find max SMB PDU from sess */
5705 pSMB->MaxDataCount = cpu_to_le16(1000);
5706 pSMB->SetupCount = 1;
5707 pSMB->Reserved3 = 0;
5708 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5709 byte_count = 3 /* pad */ + params + count;
5710 pSMB->DataCount = cpu_to_le16(count);
5711 pSMB->ParameterCount = cpu_to_le16(params);
5712 pSMB->TotalDataCount = pSMB->DataCount;
5713 pSMB->TotalParameterCount = pSMB->ParameterCount;
5714 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5715 pSMB->DataOffset = cpu_to_le16(offset);
5716 pSMB->Fid = fid;
5717 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5718 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5719 else
5720 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5721 pSMB->Reserved4 = 0;
5722 inc_rfc1001_len(pSMB, byte_count);
5723 pSMB->ByteCount = cpu_to_le16(byte_count);
5724 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5725 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5726 if (rc)
5727 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
5729 /* Note: On -EAGAIN error only caller can retry on handle based calls
5730 since file handle passed in no longer valid */
5732 return rc;
5736 CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
5737 bool delete_file, __u16 fid, __u32 pid_of_opener)
5739 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5740 char *data_offset;
5741 int rc = 0;
5742 __u16 params, param_offset, offset, byte_count, count;
5744 cFYI(1, "Set File Disposition (via SetFileInfo)");
5745 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5747 if (rc)
5748 return rc;
5750 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5751 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5753 params = 6;
5754 pSMB->MaxSetupCount = 0;
5755 pSMB->Reserved = 0;
5756 pSMB->Flags = 0;
5757 pSMB->Timeout = 0;
5758 pSMB->Reserved2 = 0;
5759 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5760 offset = param_offset + params;
5762 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5764 count = 1;
5765 pSMB->MaxParameterCount = cpu_to_le16(2);
5766 /* BB find max SMB PDU from sess */
5767 pSMB->MaxDataCount = cpu_to_le16(1000);
5768 pSMB->SetupCount = 1;
5769 pSMB->Reserved3 = 0;
5770 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5771 byte_count = 3 /* pad */ + params + count;
5772 pSMB->DataCount = cpu_to_le16(count);
5773 pSMB->ParameterCount = cpu_to_le16(params);
5774 pSMB->TotalDataCount = pSMB->DataCount;
5775 pSMB->TotalParameterCount = pSMB->ParameterCount;
5776 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5777 pSMB->DataOffset = cpu_to_le16(offset);
5778 pSMB->Fid = fid;
5779 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5780 pSMB->Reserved4 = 0;
5781 inc_rfc1001_len(pSMB, byte_count);
5782 pSMB->ByteCount = cpu_to_le16(byte_count);
5783 *data_offset = delete_file ? 1 : 0;
5784 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5785 if (rc)
5786 cFYI(1, "Send error in SetFileDisposition = %d", rc);
5788 return rc;
5792 CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
5793 const char *fileName, const FILE_BASIC_INFO *data,
5794 const struct nls_table *nls_codepage, int remap)
5796 TRANSACTION2_SPI_REQ *pSMB = NULL;
5797 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5798 int name_len;
5799 int rc = 0;
5800 int bytes_returned = 0;
5801 char *data_offset;
5802 __u16 params, param_offset, offset, byte_count, count;
5804 cFYI(1, "In SetTimes");
5806 SetTimesRetry:
5807 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5808 (void **) &pSMBr);
5809 if (rc)
5810 return rc;
5812 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5813 name_len =
5814 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5815 PATH_MAX, nls_codepage, remap);
5816 name_len++; /* trailing null */
5817 name_len *= 2;
5818 } else { /* BB improve the check for buffer overruns BB */
5819 name_len = strnlen(fileName, PATH_MAX);
5820 name_len++; /* trailing null */
5821 strncpy(pSMB->FileName, fileName, name_len);
5824 params = 6 + name_len;
5825 count = sizeof(FILE_BASIC_INFO);
5826 pSMB->MaxParameterCount = cpu_to_le16(2);
5827 /* BB find max SMB PDU from sess structure BB */
5828 pSMB->MaxDataCount = cpu_to_le16(1000);
5829 pSMB->MaxSetupCount = 0;
5830 pSMB->Reserved = 0;
5831 pSMB->Flags = 0;
5832 pSMB->Timeout = 0;
5833 pSMB->Reserved2 = 0;
5834 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5835 InformationLevel) - 4;
5836 offset = param_offset + params;
5837 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5838 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5839 pSMB->DataOffset = cpu_to_le16(offset);
5840 pSMB->SetupCount = 1;
5841 pSMB->Reserved3 = 0;
5842 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5843 byte_count = 3 /* pad */ + params + count;
5845 pSMB->DataCount = cpu_to_le16(count);
5846 pSMB->ParameterCount = cpu_to_le16(params);
5847 pSMB->TotalDataCount = pSMB->DataCount;
5848 pSMB->TotalParameterCount = pSMB->ParameterCount;
5849 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5850 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5851 else
5852 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5853 pSMB->Reserved4 = 0;
5854 inc_rfc1001_len(pSMB, byte_count);
5855 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5856 pSMB->ByteCount = cpu_to_le16(byte_count);
5857 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5858 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5859 if (rc)
5860 cFYI(1, "SetPathInfo (times) returned %d", rc);
5862 cifs_buf_release(pSMB);
5864 if (rc == -EAGAIN)
5865 goto SetTimesRetry;
5867 return rc;
5870 /* Can not be used to set time stamps yet (due to old DOS time format) */
5871 /* Can be used to set attributes */
5872 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5873 handling it anyway and NT4 was what we thought it would be needed for
5874 Do not delete it until we prove whether needed for Win9x though */
5876 CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
5877 __u16 dos_attrs, const struct nls_table *nls_codepage)
5879 SETATTR_REQ *pSMB = NULL;
5880 SETATTR_RSP *pSMBr = NULL;
5881 int rc = 0;
5882 int bytes_returned;
5883 int name_len;
5885 cFYI(1, "In SetAttrLegacy");
5887 SetAttrLgcyRetry:
5888 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5889 (void **) &pSMBr);
5890 if (rc)
5891 return rc;
5893 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5894 name_len =
5895 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5896 PATH_MAX, nls_codepage);
5897 name_len++; /* trailing null */
5898 name_len *= 2;
5899 } else { /* BB improve the check for buffer overruns BB */
5900 name_len = strnlen(fileName, PATH_MAX);
5901 name_len++; /* trailing null */
5902 strncpy(pSMB->fileName, fileName, name_len);
5904 pSMB->attr = cpu_to_le16(dos_attrs);
5905 pSMB->BufferFormat = 0x04;
5906 inc_rfc1001_len(pSMB, name_len + 1);
5907 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5910 if (rc)
5911 cFYI(1, "Error in LegacySetAttr = %d", rc);
5913 cifs_buf_release(pSMB);
5915 if (rc == -EAGAIN)
5916 goto SetAttrLgcyRetry;
5918 return rc;
5920 #endif /* temporarily unneeded SetAttr legacy function */
5922 static void
5923 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5924 const struct cifs_unix_set_info_args *args)
5926 u64 mode = args->mode;
5929 * Samba server ignores set of file size to zero due to bugs in some
5930 * older clients, but we should be precise - we use SetFileSize to
5931 * set file size and do not want to truncate file size to zero
5932 * accidentally as happened on one Samba server beta by putting
5933 * zero instead of -1 here
5935 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5936 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5937 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5938 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5939 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5940 data_offset->Uid = cpu_to_le64(args->uid);
5941 data_offset->Gid = cpu_to_le64(args->gid);
5942 /* better to leave device as zero when it is */
5943 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5944 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5945 data_offset->Permissions = cpu_to_le64(mode);
5947 if (S_ISREG(mode))
5948 data_offset->Type = cpu_to_le32(UNIX_FILE);
5949 else if (S_ISDIR(mode))
5950 data_offset->Type = cpu_to_le32(UNIX_DIR);
5951 else if (S_ISLNK(mode))
5952 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5953 else if (S_ISCHR(mode))
5954 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5955 else if (S_ISBLK(mode))
5956 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5957 else if (S_ISFIFO(mode))
5958 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5959 else if (S_ISSOCK(mode))
5960 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5964 CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
5965 const struct cifs_unix_set_info_args *args,
5966 u16 fid, u32 pid_of_opener)
5968 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5969 FILE_UNIX_BASIC_INFO *data_offset;
5970 int rc = 0;
5971 u16 params, param_offset, offset, byte_count, count;
5973 cFYI(1, "Set Unix Info (via SetFileInfo)");
5974 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5976 if (rc)
5977 return rc;
5979 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5980 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5982 params = 6;
5983 pSMB->MaxSetupCount = 0;
5984 pSMB->Reserved = 0;
5985 pSMB->Flags = 0;
5986 pSMB->Timeout = 0;
5987 pSMB->Reserved2 = 0;
5988 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5989 offset = param_offset + params;
5991 data_offset = (FILE_UNIX_BASIC_INFO *)
5992 ((char *)(&pSMB->hdr.Protocol) + offset);
5993 count = sizeof(FILE_UNIX_BASIC_INFO);
5995 pSMB->MaxParameterCount = cpu_to_le16(2);
5996 /* BB find max SMB PDU from sess */
5997 pSMB->MaxDataCount = cpu_to_le16(1000);
5998 pSMB->SetupCount = 1;
5999 pSMB->Reserved3 = 0;
6000 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6001 byte_count = 3 /* pad */ + params + count;
6002 pSMB->DataCount = cpu_to_le16(count);
6003 pSMB->ParameterCount = cpu_to_le16(params);
6004 pSMB->TotalDataCount = pSMB->DataCount;
6005 pSMB->TotalParameterCount = pSMB->ParameterCount;
6006 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6007 pSMB->DataOffset = cpu_to_le16(offset);
6008 pSMB->Fid = fid;
6009 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6010 pSMB->Reserved4 = 0;
6011 inc_rfc1001_len(pSMB, byte_count);
6012 pSMB->ByteCount = cpu_to_le16(byte_count);
6014 cifs_fill_unix_set_info(data_offset, args);
6016 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
6017 if (rc)
6018 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
6020 /* Note: On -EAGAIN error only caller can retry on handle based calls
6021 since file handle passed in no longer valid */
6023 return rc;
6027 CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
6028 const struct cifs_unix_set_info_args *args,
6029 const struct nls_table *nls_codepage, int remap)
6031 TRANSACTION2_SPI_REQ *pSMB = NULL;
6032 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6033 int name_len;
6034 int rc = 0;
6035 int bytes_returned = 0;
6036 FILE_UNIX_BASIC_INFO *data_offset;
6037 __u16 params, param_offset, offset, count, byte_count;
6039 cFYI(1, "In SetUID/GID/Mode");
6040 setPermsRetry:
6041 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6042 (void **) &pSMBr);
6043 if (rc)
6044 return rc;
6046 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6047 name_len =
6048 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6049 PATH_MAX, nls_codepage, remap);
6050 name_len++; /* trailing null */
6051 name_len *= 2;
6052 } else { /* BB improve the check for buffer overruns BB */
6053 name_len = strnlen(fileName, PATH_MAX);
6054 name_len++; /* trailing null */
6055 strncpy(pSMB->FileName, fileName, name_len);
6058 params = 6 + name_len;
6059 count = sizeof(FILE_UNIX_BASIC_INFO);
6060 pSMB->MaxParameterCount = cpu_to_le16(2);
6061 /* BB find max SMB PDU from sess structure BB */
6062 pSMB->MaxDataCount = cpu_to_le16(1000);
6063 pSMB->MaxSetupCount = 0;
6064 pSMB->Reserved = 0;
6065 pSMB->Flags = 0;
6066 pSMB->Timeout = 0;
6067 pSMB->Reserved2 = 0;
6068 param_offset = offsetof(struct smb_com_transaction2_spi_req,
6069 InformationLevel) - 4;
6070 offset = param_offset + params;
6071 data_offset =
6072 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6073 offset);
6074 memset(data_offset, 0, count);
6075 pSMB->DataOffset = cpu_to_le16(offset);
6076 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6077 pSMB->SetupCount = 1;
6078 pSMB->Reserved3 = 0;
6079 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6080 byte_count = 3 /* pad */ + params + count;
6081 pSMB->ParameterCount = cpu_to_le16(params);
6082 pSMB->DataCount = cpu_to_le16(count);
6083 pSMB->TotalParameterCount = pSMB->ParameterCount;
6084 pSMB->TotalDataCount = pSMB->DataCount;
6085 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6086 pSMB->Reserved4 = 0;
6087 inc_rfc1001_len(pSMB, byte_count);
6089 cifs_fill_unix_set_info(data_offset, args);
6091 pSMB->ByteCount = cpu_to_le16(byte_count);
6092 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6093 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6094 if (rc)
6095 cFYI(1, "SetPathInfo (perms) returned %d", rc);
6097 cifs_buf_release(pSMB);
6098 if (rc == -EAGAIN)
6099 goto setPermsRetry;
6100 return rc;
6103 #ifdef CONFIG_CIFS_XATTR
6105 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6106 * function used by listxattr and getxattr type calls. When ea_name is set,
6107 * it looks for that attribute name and stuffs that value into the EAData
6108 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6109 * buffer. In both cases, the return value is either the length of the
6110 * resulting data or a negative error code. If EAData is a NULL pointer then
6111 * the data isn't copied to it, but the length is returned.
6113 ssize_t
6114 CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
6115 const unsigned char *searchName, const unsigned char *ea_name,
6116 char *EAData, size_t buf_size,
6117 const struct nls_table *nls_codepage, int remap)
6119 /* BB assumes one setup word */
6120 TRANSACTION2_QPI_REQ *pSMB = NULL;
6121 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6122 int rc = 0;
6123 int bytes_returned;
6124 int list_len;
6125 struct fealist *ea_response_data;
6126 struct fea *temp_fea;
6127 char *temp_ptr;
6128 char *end_of_smb;
6129 __u16 params, byte_count, data_offset;
6130 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
6132 cFYI(1, "In Query All EAs path %s", searchName);
6133 QAllEAsRetry:
6134 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6135 (void **) &pSMBr);
6136 if (rc)
6137 return rc;
6139 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6140 list_len =
6141 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6142 PATH_MAX, nls_codepage, remap);
6143 list_len++; /* trailing null */
6144 list_len *= 2;
6145 } else { /* BB improve the check for buffer overruns BB */
6146 list_len = strnlen(searchName, PATH_MAX);
6147 list_len++; /* trailing null */
6148 strncpy(pSMB->FileName, searchName, list_len);
6151 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
6152 pSMB->TotalDataCount = 0;
6153 pSMB->MaxParameterCount = cpu_to_le16(2);
6154 /* BB find exact max SMB PDU from sess structure BB */
6155 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
6156 pSMB->MaxSetupCount = 0;
6157 pSMB->Reserved = 0;
6158 pSMB->Flags = 0;
6159 pSMB->Timeout = 0;
6160 pSMB->Reserved2 = 0;
6161 pSMB->ParameterOffset = cpu_to_le16(offsetof(
6162 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
6163 pSMB->DataCount = 0;
6164 pSMB->DataOffset = 0;
6165 pSMB->SetupCount = 1;
6166 pSMB->Reserved3 = 0;
6167 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6168 byte_count = params + 1 /* pad */ ;
6169 pSMB->TotalParameterCount = cpu_to_le16(params);
6170 pSMB->ParameterCount = pSMB->TotalParameterCount;
6171 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6172 pSMB->Reserved4 = 0;
6173 inc_rfc1001_len(pSMB, byte_count);
6174 pSMB->ByteCount = cpu_to_le16(byte_count);
6176 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6177 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6178 if (rc) {
6179 cFYI(1, "Send error in QueryAllEAs = %d", rc);
6180 goto QAllEAsOut;
6184 /* BB also check enough total bytes returned */
6185 /* BB we need to improve the validity checking
6186 of these trans2 responses */
6188 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
6189 if (rc || get_bcc(&pSMBr->hdr) < 4) {
6190 rc = -EIO; /* bad smb */
6191 goto QAllEAsOut;
6194 /* check that length of list is not more than bcc */
6195 /* check that each entry does not go beyond length
6196 of list */
6197 /* check that each element of each entry does not
6198 go beyond end of list */
6199 /* validate_trans2_offsets() */
6200 /* BB check if start of smb + data_offset > &bcc+ bcc */
6202 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6203 ea_response_data = (struct fealist *)
6204 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6206 list_len = le32_to_cpu(ea_response_data->list_len);
6207 cFYI(1, "ea length %d", list_len);
6208 if (list_len <= 8) {
6209 cFYI(1, "empty EA list returned from server");
6210 goto QAllEAsOut;
6213 /* make sure list_len doesn't go past end of SMB */
6214 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
6215 if ((char *)ea_response_data + list_len > end_of_smb) {
6216 cFYI(1, "EA list appears to go beyond SMB");
6217 rc = -EIO;
6218 goto QAllEAsOut;
6221 /* account for ea list len */
6222 list_len -= 4;
6223 temp_fea = ea_response_data->list;
6224 temp_ptr = (char *)temp_fea;
6225 while (list_len > 0) {
6226 unsigned int name_len;
6227 __u16 value_len;
6229 list_len -= 4;
6230 temp_ptr += 4;
6231 /* make sure we can read name_len and value_len */
6232 if (list_len < 0) {
6233 cFYI(1, "EA entry goes beyond length of list");
6234 rc = -EIO;
6235 goto QAllEAsOut;
6238 name_len = temp_fea->name_len;
6239 value_len = le16_to_cpu(temp_fea->value_len);
6240 list_len -= name_len + 1 + value_len;
6241 if (list_len < 0) {
6242 cFYI(1, "EA entry goes beyond length of list");
6243 rc = -EIO;
6244 goto QAllEAsOut;
6247 if (ea_name) {
6248 if (ea_name_len == name_len &&
6249 memcmp(ea_name, temp_ptr, name_len) == 0) {
6250 temp_ptr += name_len + 1;
6251 rc = value_len;
6252 if (buf_size == 0)
6253 goto QAllEAsOut;
6254 if ((size_t)value_len > buf_size) {
6255 rc = -ERANGE;
6256 goto QAllEAsOut;
6258 memcpy(EAData, temp_ptr, value_len);
6259 goto QAllEAsOut;
6261 } else {
6262 /* account for prefix user. and trailing null */
6263 rc += (5 + 1 + name_len);
6264 if (rc < (int) buf_size) {
6265 memcpy(EAData, "user.", 5);
6266 EAData += 5;
6267 memcpy(EAData, temp_ptr, name_len);
6268 EAData += name_len;
6269 /* null terminate name */
6270 *EAData = 0;
6271 ++EAData;
6272 } else if (buf_size == 0) {
6273 /* skip copy - calc size only */
6274 } else {
6275 /* stop before overrun buffer */
6276 rc = -ERANGE;
6277 break;
6280 temp_ptr += name_len + 1 + value_len;
6281 temp_fea = (struct fea *)temp_ptr;
6284 /* didn't find the named attribute */
6285 if (ea_name)
6286 rc = -ENODATA;
6288 QAllEAsOut:
6289 cifs_buf_release(pSMB);
6290 if (rc == -EAGAIN)
6291 goto QAllEAsRetry;
6293 return (ssize_t)rc;
6297 CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
6298 const char *ea_name, const void *ea_value,
6299 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6300 int remap)
6302 struct smb_com_transaction2_spi_req *pSMB = NULL;
6303 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6304 struct fealist *parm_data;
6305 int name_len;
6306 int rc = 0;
6307 int bytes_returned = 0;
6308 __u16 params, param_offset, byte_count, offset, count;
6310 cFYI(1, "In SetEA");
6311 SetEARetry:
6312 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6313 (void **) &pSMBr);
6314 if (rc)
6315 return rc;
6317 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6318 name_len =
6319 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6320 PATH_MAX, nls_codepage, remap);
6321 name_len++; /* trailing null */
6322 name_len *= 2;
6323 } else { /* BB improve the check for buffer overruns BB */
6324 name_len = strnlen(fileName, PATH_MAX);
6325 name_len++; /* trailing null */
6326 strncpy(pSMB->FileName, fileName, name_len);
6329 params = 6 + name_len;
6331 /* done calculating parms using name_len of file name,
6332 now use name_len to calculate length of ea name
6333 we are going to create in the inode xattrs */
6334 if (ea_name == NULL)
6335 name_len = 0;
6336 else
6337 name_len = strnlen(ea_name, 255);
6339 count = sizeof(*parm_data) + ea_value_len + name_len;
6340 pSMB->MaxParameterCount = cpu_to_le16(2);
6341 /* BB find max SMB PDU from sess */
6342 pSMB->MaxDataCount = cpu_to_le16(1000);
6343 pSMB->MaxSetupCount = 0;
6344 pSMB->Reserved = 0;
6345 pSMB->Flags = 0;
6346 pSMB->Timeout = 0;
6347 pSMB->Reserved2 = 0;
6348 param_offset = offsetof(struct smb_com_transaction2_spi_req,
6349 InformationLevel) - 4;
6350 offset = param_offset + params;
6351 pSMB->InformationLevel =
6352 cpu_to_le16(SMB_SET_FILE_EA);
6354 parm_data =
6355 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6356 offset);
6357 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6358 pSMB->DataOffset = cpu_to_le16(offset);
6359 pSMB->SetupCount = 1;
6360 pSMB->Reserved3 = 0;
6361 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6362 byte_count = 3 /* pad */ + params + count;
6363 pSMB->DataCount = cpu_to_le16(count);
6364 parm_data->list_len = cpu_to_le32(count);
6365 parm_data->list[0].EA_flags = 0;
6366 /* we checked above that name len is less than 255 */
6367 parm_data->list[0].name_len = (__u8)name_len;
6368 /* EA names are always ASCII */
6369 if (ea_name)
6370 strncpy(parm_data->list[0].name, ea_name, name_len);
6371 parm_data->list[0].name[name_len] = 0;
6372 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6373 /* caller ensures that ea_value_len is less than 64K but
6374 we need to ensure that it fits within the smb */
6376 /*BB add length check to see if it would fit in
6377 negotiated SMB buffer size BB */
6378 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6379 if (ea_value_len)
6380 memcpy(parm_data->list[0].name+name_len+1,
6381 ea_value, ea_value_len);
6383 pSMB->TotalDataCount = pSMB->DataCount;
6384 pSMB->ParameterCount = cpu_to_le16(params);
6385 pSMB->TotalParameterCount = pSMB->ParameterCount;
6386 pSMB->Reserved4 = 0;
6387 inc_rfc1001_len(pSMB, byte_count);
6388 pSMB->ByteCount = cpu_to_le16(byte_count);
6389 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6390 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6391 if (rc)
6392 cFYI(1, "SetPathInfo (EA) returned %d", rc);
6394 cifs_buf_release(pSMB);
6396 if (rc == -EAGAIN)
6397 goto SetEARetry;
6399 return rc;
6401 #endif
6403 #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6405 * Years ago the kernel added a "dnotify" function for Samba server,
6406 * to allow network clients (such as Windows) to display updated
6407 * lists of files in directory listings automatically when
6408 * files are added by one user when another user has the
6409 * same directory open on their desktop. The Linux cifs kernel
6410 * client hooked into the kernel side of this interface for
6411 * the same reason, but ironically when the VFS moved from
6412 * "dnotify" to "inotify" it became harder to plug in Linux
6413 * network file system clients (the most obvious use case
6414 * for notify interfaces is when multiple users can update
6415 * the contents of the same directory - exactly what network
6416 * file systems can do) although the server (Samba) could
6417 * still use it. For the short term we leave the worker
6418 * function ifdeffed out (below) until inotify is fixed
6419 * in the VFS to make it easier to plug in network file
6420 * system clients. If inotify turns out to be permanently
6421 * incompatible for network fs clients, we could instead simply
6422 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6424 int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
6425 const int notify_subdirs, const __u16 netfid,
6426 __u32 filter, struct file *pfile, int multishot,
6427 const struct nls_table *nls_codepage)
6429 int rc = 0;
6430 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6431 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6432 struct dir_notify_req *dnotify_req;
6433 int bytes_returned;
6435 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6436 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6437 (void **) &pSMBr);
6438 if (rc)
6439 return rc;
6441 pSMB->TotalParameterCount = 0 ;
6442 pSMB->TotalDataCount = 0;
6443 pSMB->MaxParameterCount = cpu_to_le32(2);
6444 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
6445 pSMB->MaxSetupCount = 4;
6446 pSMB->Reserved = 0;
6447 pSMB->ParameterOffset = 0;
6448 pSMB->DataCount = 0;
6449 pSMB->DataOffset = 0;
6450 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6451 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6452 pSMB->ParameterCount = pSMB->TotalParameterCount;
6453 if (notify_subdirs)
6454 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6455 pSMB->Reserved2 = 0;
6456 pSMB->CompletionFilter = cpu_to_le32(filter);
6457 pSMB->Fid = netfid; /* file handle always le */
6458 pSMB->ByteCount = 0;
6460 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6461 (struct smb_hdr *)pSMBr, &bytes_returned,
6462 CIFS_ASYNC_OP);
6463 if (rc) {
6464 cFYI(1, "Error in Notify = %d", rc);
6465 } else {
6466 /* Add file to outstanding requests */
6467 /* BB change to kmem cache alloc */
6468 dnotify_req = kmalloc(
6469 sizeof(struct dir_notify_req),
6470 GFP_KERNEL);
6471 if (dnotify_req) {
6472 dnotify_req->Pid = pSMB->hdr.Pid;
6473 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6474 dnotify_req->Mid = pSMB->hdr.Mid;
6475 dnotify_req->Tid = pSMB->hdr.Tid;
6476 dnotify_req->Uid = pSMB->hdr.Uid;
6477 dnotify_req->netfid = netfid;
6478 dnotify_req->pfile = pfile;
6479 dnotify_req->filter = filter;
6480 dnotify_req->multishot = multishot;
6481 spin_lock(&GlobalMid_Lock);
6482 list_add_tail(&dnotify_req->lhead,
6483 &GlobalDnotifyReqList);
6484 spin_unlock(&GlobalMid_Lock);
6485 } else
6486 rc = -ENOMEM;
6488 cifs_buf_release(pSMB);
6489 return rc;
6491 #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */