rcu: optimize rcutiny
[linux-2.6/x86.git] / fs / cifs / cifssmb.c
blobdf959bae67281597a2c1b4ce643eb3893b0e6ee2
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 <asm/uaccess.h>
36 #include "cifspdu.h"
37 #include "cifsglob.h"
38 #include "cifsacl.h"
39 #include "cifsproto.h"
40 #include "cifs_unicode.h"
41 #include "cifs_debug.h"
43 #ifdef CONFIG_CIFS_POSIX
44 static struct {
45 int index;
46 char *name;
47 } protocols[] = {
48 #ifdef CONFIG_CIFS_WEAK_PW_HASH
49 {LANMAN_PROT, "\2LM1.2X002"},
50 {LANMAN2_PROT, "\2LANMAN2.1"},
51 #endif /* weak password hashing for legacy clients */
52 {CIFS_PROT, "\2NT LM 0.12"},
53 {POSIX_PROT, "\2POSIX 2"},
54 {BAD_PROT, "\2"}
56 #else
57 static struct {
58 int index;
59 char *name;
60 } protocols[] = {
61 #ifdef CONFIG_CIFS_WEAK_PW_HASH
62 {LANMAN_PROT, "\2LM1.2X002"},
63 {LANMAN2_PROT, "\2LANMAN2.1"},
64 #endif /* weak password hashing for legacy clients */
65 {CIFS_PROT, "\2NT LM 0.12"},
66 {BAD_PROT, "\2"}
68 #endif
70 /* define the number of elements in the cifs dialect array */
71 #ifdef CONFIG_CIFS_POSIX
72 #ifdef CONFIG_CIFS_WEAK_PW_HASH
73 #define CIFS_NUM_PROT 4
74 #else
75 #define CIFS_NUM_PROT 2
76 #endif /* CIFS_WEAK_PW_HASH */
77 #else /* not posix */
78 #ifdef CONFIG_CIFS_WEAK_PW_HASH
79 #define CIFS_NUM_PROT 3
80 #else
81 #define CIFS_NUM_PROT 1
82 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
83 #endif /* CIFS_POSIX */
85 /* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
87 static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
89 struct cifsFileInfo *open_file = NULL;
90 struct list_head *tmp;
91 struct list_head *tmp1;
93 /* list all files open on tree connection and mark them invalid */
94 spin_lock(&cifs_file_list_lock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
96 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
97 open_file->invalidHandle = true;
98 open_file->oplock_break_cancelled = true;
100 spin_unlock(&cifs_file_list_lock);
101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
105 /* reconnect the socket, tcon, and smb session if needed */
106 static int
107 cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
109 int rc = 0;
110 struct cifsSesInfo *ses;
111 struct TCP_Server_Info *server;
112 struct nls_table *nls_codepage;
115 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
116 * tcp and smb session status done differently for those three - in the
117 * calling routine
119 if (!tcon)
120 return 0;
122 ses = tcon->ses;
123 server = ses->server;
126 * only tree disconnect, open, and write, (and ulogoff which does not
127 * have tcon) are allowed as we start force umount
129 if (tcon->tidStatus == CifsExiting) {
130 if (smb_command != SMB_COM_WRITE_ANDX &&
131 smb_command != SMB_COM_OPEN_ANDX &&
132 smb_command != SMB_COM_TREE_DISCONNECT) {
133 cFYI(1, "can not send cmd %d while umounting",
134 smb_command);
135 return -ENODEV;
140 * Give demultiplex thread up to 10 seconds to reconnect, should be
141 * greater than cifs socket timeout which is 7 seconds
143 while (server->tcpStatus == CifsNeedReconnect) {
144 wait_event_interruptible_timeout(server->response_q,
145 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
147 /* are we still trying to reconnect? */
148 if (server->tcpStatus != CifsNeedReconnect)
149 break;
152 * on "soft" mounts we wait once. Hard mounts keep
153 * retrying until process is killed or server comes
154 * back on-line
156 if (!tcon->retry) {
157 cFYI(1, "gave up waiting on reconnect in smb_init");
158 return -EHOSTDOWN;
162 if (!ses->need_reconnect && !tcon->need_reconnect)
163 return 0;
165 nls_codepage = load_nls_default();
168 * need to prevent multiple threads trying to simultaneously
169 * reconnect the same SMB session
171 mutex_lock(&ses->session_mutex);
172 rc = cifs_negotiate_protocol(0, ses);
173 if (rc == 0 && ses->need_reconnect)
174 rc = cifs_setup_session(0, ses, nls_codepage);
176 /* do we need to reconnect tcon? */
177 if (rc || !tcon->need_reconnect) {
178 mutex_unlock(&ses->session_mutex);
179 goto out;
182 mark_open_files_invalid(tcon);
183 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
184 mutex_unlock(&ses->session_mutex);
185 cFYI(1, "reconnect tcon rc = %d", rc);
187 if (rc)
188 goto out;
191 * FIXME: check if wsize needs updated due to negotiated smb buffer
192 * size shrinking
194 atomic_inc(&tconInfoReconnectCount);
196 /* tell server Unix caps we support */
197 if (ses->capabilities & CAP_UNIX)
198 reset_cifs_unix_caps(0, tcon, NULL, NULL);
201 * Removed call to reopen open files here. It is safer (and faster) to
202 * reopen files one at a time as needed in read and write.
204 * FIXME: what about file locks? don't we need to reclaim them ASAP?
207 out:
209 * Check if handle based operation so we know whether we can continue
210 * or not without returning to caller to reset file handle
212 switch (smb_command) {
213 case SMB_COM_READ_ANDX:
214 case SMB_COM_WRITE_ANDX:
215 case SMB_COM_CLOSE:
216 case SMB_COM_FIND_CLOSE2:
217 case SMB_COM_LOCKING_ANDX:
218 rc = -EAGAIN;
221 unload_nls(nls_codepage);
222 return rc;
225 /* Allocate and return pointer to an SMB request buffer, and set basic
226 SMB information in the SMB header. If the return code is zero, this
227 function must have filled in request_buf pointer */
228 static int
229 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
230 void **request_buf)
232 int rc;
234 rc = cifs_reconnect_tcon(tcon, smb_command);
235 if (rc)
236 return rc;
238 *request_buf = cifs_small_buf_get();
239 if (*request_buf == NULL) {
240 /* BB should we add a retry in here if not a writepage? */
241 return -ENOMEM;
244 header_assemble((struct smb_hdr *) *request_buf, smb_command,
245 tcon, wct);
247 if (tcon != NULL)
248 cifs_stats_inc(&tcon->num_smbs_sent);
250 return 0;
254 small_smb_init_no_tc(const int smb_command, const int wct,
255 struct cifsSesInfo *ses, void **request_buf)
257 int rc;
258 struct smb_hdr *buffer;
260 rc = small_smb_init(smb_command, wct, NULL, request_buf);
261 if (rc)
262 return rc;
264 buffer = (struct smb_hdr *)*request_buf;
265 buffer->Mid = GetNextMid(ses->server);
266 if (ses->capabilities & CAP_UNICODE)
267 buffer->Flags2 |= SMBFLG2_UNICODE;
268 if (ses->capabilities & CAP_STATUS32)
269 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
271 /* uid, tid can stay at zero as set in header assemble */
273 /* BB add support for turning on the signing when
274 this function is used after 1st of session setup requests */
276 return rc;
279 /* If the return code is zero, this function must fill in request_buf pointer */
280 static int
281 __smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
282 void **request_buf, void **response_buf)
284 *request_buf = cifs_buf_get();
285 if (*request_buf == NULL) {
286 /* BB should we add a retry in here if not a writepage? */
287 return -ENOMEM;
289 /* Although the original thought was we needed the response buf for */
290 /* potential retries of smb operations it turns out we can determine */
291 /* from the mid flags when the request buffer can be resent without */
292 /* having to use a second distinct buffer for the response */
293 if (response_buf)
294 *response_buf = *request_buf;
296 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
297 wct);
299 if (tcon != NULL)
300 cifs_stats_inc(&tcon->num_smbs_sent);
302 return 0;
305 /* If the return code is zero, this function must fill in request_buf pointer */
306 static int
307 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
308 void **request_buf, void **response_buf)
310 int rc;
312 rc = cifs_reconnect_tcon(tcon, smb_command);
313 if (rc)
314 return rc;
316 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
319 static int
320 smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
321 void **request_buf, void **response_buf)
323 if (tcon->ses->need_reconnect || tcon->need_reconnect)
324 return -EHOSTDOWN;
326 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
329 static int validate_t2(struct smb_t2_rsp *pSMB)
331 unsigned int total_size;
333 /* check for plausible wct */
334 if (pSMB->hdr.WordCount < 10)
335 goto vt2_err;
337 /* check for parm and data offset going beyond end of smb */
338 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
339 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
340 goto vt2_err;
342 /* check that bcc is at least as big as parms + data */
343 /* check that bcc is less than negotiated smb buffer */
344 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
345 if (total_size >= 512)
346 goto vt2_err;
348 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
349 if (total_size > get_bcc(&pSMB->hdr) ||
350 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
351 goto vt2_err;
353 return 0;
354 vt2_err:
355 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
356 sizeof(struct smb_t2_rsp) + 16);
357 return -EINVAL;
361 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
363 NEGOTIATE_REQ *pSMB;
364 NEGOTIATE_RSP *pSMBr;
365 int rc = 0;
366 int bytes_returned;
367 int i;
368 struct TCP_Server_Info *server;
369 u16 count;
370 unsigned int secFlags;
372 if (ses->server)
373 server = ses->server;
374 else {
375 rc = -EIO;
376 return rc;
378 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
379 (void **) &pSMB, (void **) &pSMBr);
380 if (rc)
381 return rc;
383 /* if any of auth flags (ie not sign or seal) are overriden use them */
384 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
385 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
386 else /* if override flags set only sign/seal OR them with global auth */
387 secFlags = global_secflags | ses->overrideSecFlg;
389 cFYI(1, "secFlags 0x%x", secFlags);
391 pSMB->hdr.Mid = GetNextMid(server);
392 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
394 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
395 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
396 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
397 cFYI(1, "Kerberos only mechanism, enable extended security");
398 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
399 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
400 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
401 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
402 cFYI(1, "NTLMSSP only mechanism, enable extended security");
403 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
406 count = 0;
407 for (i = 0; i < CIFS_NUM_PROT; i++) {
408 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
409 count += strlen(protocols[i].name) + 1;
410 /* null at end of source and target buffers anyway */
412 pSMB->hdr.smb_buf_length += count;
413 pSMB->ByteCount = cpu_to_le16(count);
415 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
416 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
417 if (rc != 0)
418 goto neg_err_exit;
420 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
421 cFYI(1, "Dialect: %d", server->dialect);
422 /* Check wct = 1 error case */
423 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
424 /* core returns wct = 1, but we do not ask for core - otherwise
425 small wct just comes when dialect index is -1 indicating we
426 could not negotiate a common dialect */
427 rc = -EOPNOTSUPP;
428 goto neg_err_exit;
429 #ifdef CONFIG_CIFS_WEAK_PW_HASH
430 } else if ((pSMBr->hdr.WordCount == 13)
431 && ((server->dialect == LANMAN_PROT)
432 || (server->dialect == LANMAN2_PROT))) {
433 __s16 tmp;
434 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
436 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
437 (secFlags & CIFSSEC_MAY_PLNTXT))
438 server->secType = LANMAN;
439 else {
440 cERROR(1, "mount failed weak security disabled"
441 " in /proc/fs/cifs/SecurityFlags");
442 rc = -EOPNOTSUPP;
443 goto neg_err_exit;
445 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
446 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
447 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
448 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
449 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
450 /* even though we do not use raw we might as well set this
451 accurately, in case we ever find a need for it */
452 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
453 server->max_rw = 0xFF00;
454 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
455 } else {
456 server->max_rw = 0;/* do not need to use raw anyway */
457 server->capabilities = CAP_MPX_MODE;
459 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
460 if (tmp == -1) {
461 /* OS/2 often does not set timezone therefore
462 * we must use server time to calc time zone.
463 * Could deviate slightly from the right zone.
464 * Smallest defined timezone difference is 15 minutes
465 * (i.e. Nepal). Rounding up/down is done to match
466 * this requirement.
468 int val, seconds, remain, result;
469 struct timespec ts, utc;
470 utc = CURRENT_TIME;
471 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
472 rsp->SrvTime.Time, 0);
473 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
474 (int)ts.tv_sec, (int)utc.tv_sec,
475 (int)(utc.tv_sec - ts.tv_sec));
476 val = (int)(utc.tv_sec - ts.tv_sec);
477 seconds = abs(val);
478 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
479 remain = seconds % MIN_TZ_ADJ;
480 if (remain >= (MIN_TZ_ADJ / 2))
481 result += MIN_TZ_ADJ;
482 if (val < 0)
483 result = -result;
484 server->timeAdj = result;
485 } else {
486 server->timeAdj = (int)tmp;
487 server->timeAdj *= 60; /* also in seconds */
489 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
492 /* BB get server time for time conversions and add
493 code to use it and timezone since this is not UTC */
495 if (rsp->EncryptionKeyLength ==
496 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
497 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
498 CIFS_CRYPTO_KEY_SIZE);
499 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
500 rc = -EIO; /* need cryptkey unless plain text */
501 goto neg_err_exit;
504 cFYI(1, "LANMAN negotiated");
505 /* we will not end up setting signing flags - as no signing
506 was in LANMAN and server did not return the flags on */
507 goto signing_check;
508 #else /* weak security disabled */
509 } else if (pSMBr->hdr.WordCount == 13) {
510 cERROR(1, "mount failed, cifs module not built "
511 "with CIFS_WEAK_PW_HASH support");
512 rc = -EOPNOTSUPP;
513 #endif /* WEAK_PW_HASH */
514 goto neg_err_exit;
515 } else if (pSMBr->hdr.WordCount != 17) {
516 /* unknown wct */
517 rc = -EOPNOTSUPP;
518 goto neg_err_exit;
520 /* else wct == 17 NTLM */
521 server->secMode = pSMBr->SecurityMode;
522 if ((server->secMode & SECMODE_USER) == 0)
523 cFYI(1, "share mode security");
525 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
526 #ifdef CONFIG_CIFS_WEAK_PW_HASH
527 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
528 #endif /* CIFS_WEAK_PW_HASH */
529 cERROR(1, "Server requests plain text password"
530 " but client support disabled");
532 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
533 server->secType = NTLMv2;
534 else if (secFlags & CIFSSEC_MAY_NTLM)
535 server->secType = NTLM;
536 else if (secFlags & CIFSSEC_MAY_NTLMV2)
537 server->secType = NTLMv2;
538 else if (secFlags & CIFSSEC_MAY_KRB5)
539 server->secType = Kerberos;
540 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
541 server->secType = RawNTLMSSP;
542 else if (secFlags & CIFSSEC_MAY_LANMAN)
543 server->secType = LANMAN;
544 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
545 else if (secFlags & CIFSSEC_MAY_PLNTXT)
546 server->secType = ??
547 #endif */
548 else {
549 rc = -EOPNOTSUPP;
550 cERROR(1, "Invalid security type");
551 goto neg_err_exit;
553 /* else ... any others ...? */
555 /* one byte, so no need to convert this or EncryptionKeyLen from
556 little endian */
557 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
558 /* probably no need to store and check maxvcs */
559 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
560 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
561 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
562 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
563 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
564 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
565 server->timeAdj *= 60;
566 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
567 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
568 CIFS_CRYPTO_KEY_SIZE);
569 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
570 && (pSMBr->EncryptionKeyLength == 0)) {
571 /* decode security blob */
572 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
573 rc = -EIO; /* no crypt key only if plain text pwd */
574 goto neg_err_exit;
577 /* BB might be helpful to save off the domain of server here */
579 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
580 (server->capabilities & CAP_EXTENDED_SECURITY)) {
581 count = pSMBr->ByteCount;
582 if (count < 16) {
583 rc = -EIO;
584 goto neg_err_exit;
586 spin_lock(&cifs_tcp_ses_lock);
587 if (server->srv_count > 1) {
588 spin_unlock(&cifs_tcp_ses_lock);
589 if (memcmp(server->server_GUID,
590 pSMBr->u.extended_response.
591 GUID, 16) != 0) {
592 cFYI(1, "server UID changed");
593 memcpy(server->server_GUID,
594 pSMBr->u.extended_response.GUID,
595 16);
597 } else {
598 spin_unlock(&cifs_tcp_ses_lock);
599 memcpy(server->server_GUID,
600 pSMBr->u.extended_response.GUID, 16);
603 if (count == 16) {
604 server->secType = RawNTLMSSP;
605 } else {
606 rc = decode_negTokenInit(pSMBr->u.extended_response.
607 SecurityBlob, count - 16,
608 server);
609 if (rc == 1)
610 rc = 0;
611 else
612 rc = -EINVAL;
613 if (server->secType == Kerberos) {
614 if (!server->sec_kerberos &&
615 !server->sec_mskerberos)
616 rc = -EOPNOTSUPP;
617 } else if (server->secType == RawNTLMSSP) {
618 if (!server->sec_ntlmssp)
619 rc = -EOPNOTSUPP;
620 } else
621 rc = -EOPNOTSUPP;
623 } else
624 server->capabilities &= ~CAP_EXTENDED_SECURITY;
626 #ifdef CONFIG_CIFS_WEAK_PW_HASH
627 signing_check:
628 #endif
629 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
630 /* MUST_SIGN already includes the MAY_SIGN FLAG
631 so if this is zero it means that signing is disabled */
632 cFYI(1, "Signing disabled");
633 if (server->secMode & SECMODE_SIGN_REQUIRED) {
634 cERROR(1, "Server requires "
635 "packet signing to be enabled in "
636 "/proc/fs/cifs/SecurityFlags.");
637 rc = -EOPNOTSUPP;
639 server->secMode &=
640 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
641 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
642 /* signing required */
643 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
644 if ((server->secMode &
645 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
646 cERROR(1, "signing required but server lacks support");
647 rc = -EOPNOTSUPP;
648 } else
649 server->secMode |= SECMODE_SIGN_REQUIRED;
650 } else {
651 /* signing optional ie CIFSSEC_MAY_SIGN */
652 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
653 server->secMode &=
654 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
657 neg_err_exit:
658 cifs_buf_release(pSMB);
660 cFYI(1, "negprot rc %d", rc);
661 return rc;
665 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
667 struct smb_hdr *smb_buffer;
668 int rc = 0;
670 cFYI(1, "In tree disconnect");
672 /* BB: do we need to check this? These should never be NULL. */
673 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
674 return -EIO;
677 * No need to return error on this operation if tid invalidated and
678 * closed on server already e.g. due to tcp session crashing. Also,
679 * the tcon is no longer on the list, so no need to take lock before
680 * checking this.
682 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
683 return 0;
685 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
686 (void **)&smb_buffer);
687 if (rc)
688 return rc;
690 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
691 if (rc)
692 cFYI(1, "Tree disconnect failed %d", rc);
694 /* No need to return error on this operation if tid invalidated and
695 closed on server already e.g. due to tcp session crashing */
696 if (rc == -EAGAIN)
697 rc = 0;
699 return rc;
703 * This is a no-op for now. We're not really interested in the reply, but
704 * rather in the fact that the server sent one and that server->lstrp
705 * gets updated.
707 * FIXME: maybe we should consider checking that the reply matches request?
709 static void
710 cifs_echo_callback(struct mid_q_entry *mid)
712 struct TCP_Server_Info *server = mid->callback_data;
714 DeleteMidQEntry(mid);
715 atomic_dec(&server->inFlight);
716 wake_up(&server->request_q);
720 CIFSSMBEcho(struct TCP_Server_Info *server)
722 ECHO_REQ *smb;
723 int rc = 0;
725 cFYI(1, "In echo request");
727 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
728 if (rc)
729 return rc;
731 /* set up echo request */
732 smb->hdr.Tid = 0xffff;
733 smb->hdr.WordCount = 1;
734 put_unaligned_le16(1, &smb->EchoCount);
735 put_bcc_le(1, &smb->hdr);
736 smb->Data[0] = 'a';
737 smb->hdr.smb_buf_length += 3;
739 rc = cifs_call_async(server, (struct smb_hdr *)smb,
740 cifs_echo_callback, server);
741 if (rc)
742 cFYI(1, "Echo request failed: %d", rc);
744 cifs_small_buf_release(smb);
746 return rc;
750 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
752 LOGOFF_ANDX_REQ *pSMB;
753 int rc = 0;
755 cFYI(1, "In SMBLogoff for session disconnect");
758 * BB: do we need to check validity of ses and server? They should
759 * always be valid since we have an active reference. If not, that
760 * should probably be a BUG()
762 if (!ses || !ses->server)
763 return -EIO;
765 mutex_lock(&ses->session_mutex);
766 if (ses->need_reconnect)
767 goto session_already_dead; /* no need to send SMBlogoff if uid
768 already closed due to reconnect */
769 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
770 if (rc) {
771 mutex_unlock(&ses->session_mutex);
772 return rc;
775 pSMB->hdr.Mid = GetNextMid(ses->server);
777 if (ses->server->secMode &
778 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
779 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
781 pSMB->hdr.Uid = ses->Suid;
783 pSMB->AndXCommand = 0xFF;
784 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
785 session_already_dead:
786 mutex_unlock(&ses->session_mutex);
788 /* if session dead then we do not need to do ulogoff,
789 since server closed smb session, no sense reporting
790 error */
791 if (rc == -EAGAIN)
792 rc = 0;
793 return rc;
797 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
798 __u16 type, const struct nls_table *nls_codepage, int remap)
800 TRANSACTION2_SPI_REQ *pSMB = NULL;
801 TRANSACTION2_SPI_RSP *pSMBr = NULL;
802 struct unlink_psx_rq *pRqD;
803 int name_len;
804 int rc = 0;
805 int bytes_returned = 0;
806 __u16 params, param_offset, offset, byte_count;
808 cFYI(1, "In POSIX delete");
809 PsxDelete:
810 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
811 (void **) &pSMBr);
812 if (rc)
813 return rc;
815 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
816 name_len =
817 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
818 PATH_MAX, nls_codepage, remap);
819 name_len++; /* trailing null */
820 name_len *= 2;
821 } else { /* BB add path length overrun check */
822 name_len = strnlen(fileName, PATH_MAX);
823 name_len++; /* trailing null */
824 strncpy(pSMB->FileName, fileName, name_len);
827 params = 6 + name_len;
828 pSMB->MaxParameterCount = cpu_to_le16(2);
829 pSMB->MaxDataCount = 0; /* BB double check this with jra */
830 pSMB->MaxSetupCount = 0;
831 pSMB->Reserved = 0;
832 pSMB->Flags = 0;
833 pSMB->Timeout = 0;
834 pSMB->Reserved2 = 0;
835 param_offset = offsetof(struct smb_com_transaction2_spi_req,
836 InformationLevel) - 4;
837 offset = param_offset + params;
839 /* Setup pointer to Request Data (inode type) */
840 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
841 pRqD->type = cpu_to_le16(type);
842 pSMB->ParameterOffset = cpu_to_le16(param_offset);
843 pSMB->DataOffset = cpu_to_le16(offset);
844 pSMB->SetupCount = 1;
845 pSMB->Reserved3 = 0;
846 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
847 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
849 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
850 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
851 pSMB->ParameterCount = cpu_to_le16(params);
852 pSMB->TotalParameterCount = pSMB->ParameterCount;
853 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
854 pSMB->Reserved4 = 0;
855 pSMB->hdr.smb_buf_length += byte_count;
856 pSMB->ByteCount = cpu_to_le16(byte_count);
857 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
858 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
859 if (rc)
860 cFYI(1, "Posix delete returned %d", rc);
861 cifs_buf_release(pSMB);
863 cifs_stats_inc(&tcon->num_deletes);
865 if (rc == -EAGAIN)
866 goto PsxDelete;
868 return rc;
872 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
873 const struct nls_table *nls_codepage, int remap)
875 DELETE_FILE_REQ *pSMB = NULL;
876 DELETE_FILE_RSP *pSMBr = NULL;
877 int rc = 0;
878 int bytes_returned;
879 int name_len;
881 DelFileRetry:
882 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
883 (void **) &pSMBr);
884 if (rc)
885 return rc;
887 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
888 name_len =
889 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
890 PATH_MAX, nls_codepage, remap);
891 name_len++; /* trailing null */
892 name_len *= 2;
893 } else { /* BB improve check for buffer overruns BB */
894 name_len = strnlen(fileName, PATH_MAX);
895 name_len++; /* trailing null */
896 strncpy(pSMB->fileName, fileName, name_len);
898 pSMB->SearchAttributes =
899 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
900 pSMB->BufferFormat = 0x04;
901 pSMB->hdr.smb_buf_length += name_len + 1;
902 pSMB->ByteCount = cpu_to_le16(name_len + 1);
903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
905 cifs_stats_inc(&tcon->num_deletes);
906 if (rc)
907 cFYI(1, "Error in RMFile = %d", rc);
909 cifs_buf_release(pSMB);
910 if (rc == -EAGAIN)
911 goto DelFileRetry;
913 return rc;
917 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
918 const struct nls_table *nls_codepage, int remap)
920 DELETE_DIRECTORY_REQ *pSMB = NULL;
921 DELETE_DIRECTORY_RSP *pSMBr = NULL;
922 int rc = 0;
923 int bytes_returned;
924 int name_len;
926 cFYI(1, "In CIFSSMBRmDir");
927 RmDirRetry:
928 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
929 (void **) &pSMBr);
930 if (rc)
931 return rc;
933 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
934 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
935 PATH_MAX, nls_codepage, remap);
936 name_len++; /* trailing null */
937 name_len *= 2;
938 } else { /* BB improve check for buffer overruns BB */
939 name_len = strnlen(dirName, PATH_MAX);
940 name_len++; /* trailing null */
941 strncpy(pSMB->DirName, dirName, name_len);
944 pSMB->BufferFormat = 0x04;
945 pSMB->hdr.smb_buf_length += name_len + 1;
946 pSMB->ByteCount = cpu_to_le16(name_len + 1);
947 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
948 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
949 cifs_stats_inc(&tcon->num_rmdirs);
950 if (rc)
951 cFYI(1, "Error in RMDir = %d", rc);
953 cifs_buf_release(pSMB);
954 if (rc == -EAGAIN)
955 goto RmDirRetry;
956 return rc;
960 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
961 const char *name, const struct nls_table *nls_codepage, int remap)
963 int rc = 0;
964 CREATE_DIRECTORY_REQ *pSMB = NULL;
965 CREATE_DIRECTORY_RSP *pSMBr = NULL;
966 int bytes_returned;
967 int name_len;
969 cFYI(1, "In CIFSSMBMkDir");
970 MkDirRetry:
971 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
972 (void **) &pSMBr);
973 if (rc)
974 return rc;
976 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
977 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
978 PATH_MAX, nls_codepage, remap);
979 name_len++; /* trailing null */
980 name_len *= 2;
981 } else { /* BB improve check for buffer overruns BB */
982 name_len = strnlen(name, PATH_MAX);
983 name_len++; /* trailing null */
984 strncpy(pSMB->DirName, name, name_len);
987 pSMB->BufferFormat = 0x04;
988 pSMB->hdr.smb_buf_length += name_len + 1;
989 pSMB->ByteCount = cpu_to_le16(name_len + 1);
990 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
991 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
992 cifs_stats_inc(&tcon->num_mkdirs);
993 if (rc)
994 cFYI(1, "Error in Mkdir = %d", rc);
996 cifs_buf_release(pSMB);
997 if (rc == -EAGAIN)
998 goto MkDirRetry;
999 return rc;
1003 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1004 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
1005 __u32 *pOplock, const char *name,
1006 const struct nls_table *nls_codepage, int remap)
1008 TRANSACTION2_SPI_REQ *pSMB = NULL;
1009 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1010 int name_len;
1011 int rc = 0;
1012 int bytes_returned = 0;
1013 __u16 params, param_offset, offset, byte_count, count;
1014 OPEN_PSX_REQ *pdata;
1015 OPEN_PSX_RSP *psx_rsp;
1017 cFYI(1, "In POSIX Create");
1018 PsxCreat:
1019 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1020 (void **) &pSMBr);
1021 if (rc)
1022 return rc;
1024 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1025 name_len =
1026 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1027 PATH_MAX, nls_codepage, remap);
1028 name_len++; /* trailing null */
1029 name_len *= 2;
1030 } else { /* BB improve the check for buffer overruns BB */
1031 name_len = strnlen(name, PATH_MAX);
1032 name_len++; /* trailing null */
1033 strncpy(pSMB->FileName, name, name_len);
1036 params = 6 + name_len;
1037 count = sizeof(OPEN_PSX_REQ);
1038 pSMB->MaxParameterCount = cpu_to_le16(2);
1039 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1040 pSMB->MaxSetupCount = 0;
1041 pSMB->Reserved = 0;
1042 pSMB->Flags = 0;
1043 pSMB->Timeout = 0;
1044 pSMB->Reserved2 = 0;
1045 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1046 InformationLevel) - 4;
1047 offset = param_offset + params;
1048 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1049 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1050 pdata->Permissions = cpu_to_le64(mode);
1051 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1052 pdata->OpenFlags = cpu_to_le32(*pOplock);
1053 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1054 pSMB->DataOffset = cpu_to_le16(offset);
1055 pSMB->SetupCount = 1;
1056 pSMB->Reserved3 = 0;
1057 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1058 byte_count = 3 /* pad */ + params + count;
1060 pSMB->DataCount = cpu_to_le16(count);
1061 pSMB->ParameterCount = cpu_to_le16(params);
1062 pSMB->TotalDataCount = pSMB->DataCount;
1063 pSMB->TotalParameterCount = pSMB->ParameterCount;
1064 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1065 pSMB->Reserved4 = 0;
1066 pSMB->hdr.smb_buf_length += byte_count;
1067 pSMB->ByteCount = cpu_to_le16(byte_count);
1068 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1070 if (rc) {
1071 cFYI(1, "Posix create returned %d", rc);
1072 goto psx_create_err;
1075 cFYI(1, "copying inode info");
1076 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1078 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1079 rc = -EIO; /* bad smb */
1080 goto psx_create_err;
1083 /* copy return information to pRetData */
1084 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1085 + le16_to_cpu(pSMBr->t2.DataOffset));
1087 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1088 if (netfid)
1089 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1090 /* Let caller know file was created so we can set the mode. */
1091 /* Do we care about the CreateAction in any other cases? */
1092 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1093 *pOplock |= CIFS_CREATE_ACTION;
1094 /* check to make sure response data is there */
1095 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1096 pRetData->Type = cpu_to_le32(-1); /* unknown */
1097 cFYI(DBG2, "unknown type");
1098 } else {
1099 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1100 + sizeof(FILE_UNIX_BASIC_INFO)) {
1101 cERROR(1, "Open response data too small");
1102 pRetData->Type = cpu_to_le32(-1);
1103 goto psx_create_err;
1105 memcpy((char *) pRetData,
1106 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1107 sizeof(FILE_UNIX_BASIC_INFO));
1110 psx_create_err:
1111 cifs_buf_release(pSMB);
1113 if (posix_flags & SMB_O_DIRECTORY)
1114 cifs_stats_inc(&tcon->num_posixmkdirs);
1115 else
1116 cifs_stats_inc(&tcon->num_posixopens);
1118 if (rc == -EAGAIN)
1119 goto PsxCreat;
1121 return rc;
1124 static __u16 convert_disposition(int disposition)
1126 __u16 ofun = 0;
1128 switch (disposition) {
1129 case FILE_SUPERSEDE:
1130 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1131 break;
1132 case FILE_OPEN:
1133 ofun = SMBOPEN_OAPPEND;
1134 break;
1135 case FILE_CREATE:
1136 ofun = SMBOPEN_OCREATE;
1137 break;
1138 case FILE_OPEN_IF:
1139 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1140 break;
1141 case FILE_OVERWRITE:
1142 ofun = SMBOPEN_OTRUNC;
1143 break;
1144 case FILE_OVERWRITE_IF:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 default:
1148 cFYI(1, "unknown disposition %d", disposition);
1149 ofun = SMBOPEN_OAPPEND; /* regular open */
1151 return ofun;
1154 static int
1155 access_flags_to_smbopen_mode(const int access_flags)
1157 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1159 if (masked_flags == GENERIC_READ)
1160 return SMBOPEN_READ;
1161 else if (masked_flags == GENERIC_WRITE)
1162 return SMBOPEN_WRITE;
1164 /* just go for read/write */
1165 return SMBOPEN_READWRITE;
1169 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1170 const char *fileName, const int openDisposition,
1171 const int access_flags, const int create_options, __u16 *netfid,
1172 int *pOplock, FILE_ALL_INFO *pfile_info,
1173 const struct nls_table *nls_codepage, int remap)
1175 int rc = -EACCES;
1176 OPENX_REQ *pSMB = NULL;
1177 OPENX_RSP *pSMBr = NULL;
1178 int bytes_returned;
1179 int name_len;
1180 __u16 count;
1182 OldOpenRetry:
1183 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1184 (void **) &pSMBr);
1185 if (rc)
1186 return rc;
1188 pSMB->AndXCommand = 0xFF; /* none */
1190 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1191 count = 1; /* account for one byte pad to word boundary */
1192 name_len =
1193 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1194 fileName, PATH_MAX, nls_codepage, remap);
1195 name_len++; /* trailing null */
1196 name_len *= 2;
1197 } else { /* BB improve check for buffer overruns BB */
1198 count = 0; /* no pad */
1199 name_len = strnlen(fileName, PATH_MAX);
1200 name_len++; /* trailing null */
1201 strncpy(pSMB->fileName, fileName, name_len);
1203 if (*pOplock & REQ_OPLOCK)
1204 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1205 else if (*pOplock & REQ_BATCHOPLOCK)
1206 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1208 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1209 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1210 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1211 /* set file as system file if special file such
1212 as fifo and server expecting SFU style and
1213 no Unix extensions */
1215 if (create_options & CREATE_OPTION_SPECIAL)
1216 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1217 else /* BB FIXME BB */
1218 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1220 if (create_options & CREATE_OPTION_READONLY)
1221 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1223 /* BB FIXME BB */
1224 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1225 CREATE_OPTIONS_MASK); */
1226 /* BB FIXME END BB */
1228 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1229 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1230 count += name_len;
1231 pSMB->hdr.smb_buf_length += count;
1233 pSMB->ByteCount = cpu_to_le16(count);
1234 /* long_op set to 1 to allow for oplock break timeouts */
1235 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1236 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1237 cifs_stats_inc(&tcon->num_opens);
1238 if (rc) {
1239 cFYI(1, "Error in Open = %d", rc);
1240 } else {
1241 /* BB verify if wct == 15 */
1243 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1245 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1246 /* Let caller know file was created so we can set the mode. */
1247 /* Do we care about the CreateAction in any other cases? */
1248 /* BB FIXME BB */
1249 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1250 *pOplock |= CIFS_CREATE_ACTION; */
1251 /* BB FIXME END */
1253 if (pfile_info) {
1254 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1255 pfile_info->LastAccessTime = 0; /* BB fixme */
1256 pfile_info->LastWriteTime = 0; /* BB fixme */
1257 pfile_info->ChangeTime = 0; /* BB fixme */
1258 pfile_info->Attributes =
1259 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1260 /* the file_info buf is endian converted by caller */
1261 pfile_info->AllocationSize =
1262 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1263 pfile_info->EndOfFile = pfile_info->AllocationSize;
1264 pfile_info->NumberOfLinks = cpu_to_le32(1);
1265 pfile_info->DeletePending = 0;
1269 cifs_buf_release(pSMB);
1270 if (rc == -EAGAIN)
1271 goto OldOpenRetry;
1272 return rc;
1276 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1277 const char *fileName, const int openDisposition,
1278 const int access_flags, const int create_options, __u16 *netfid,
1279 int *pOplock, FILE_ALL_INFO *pfile_info,
1280 const struct nls_table *nls_codepage, int remap)
1282 int rc = -EACCES;
1283 OPEN_REQ *pSMB = NULL;
1284 OPEN_RSP *pSMBr = NULL;
1285 int bytes_returned;
1286 int name_len;
1287 __u16 count;
1289 openRetry:
1290 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1291 (void **) &pSMBr);
1292 if (rc)
1293 return rc;
1295 pSMB->AndXCommand = 0xFF; /* none */
1297 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1298 count = 1; /* account for one byte pad to word boundary */
1299 name_len =
1300 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1301 fileName, PATH_MAX, nls_codepage, remap);
1302 name_len++; /* trailing null */
1303 name_len *= 2;
1304 pSMB->NameLength = cpu_to_le16(name_len);
1305 } else { /* BB improve check for buffer overruns BB */
1306 count = 0; /* no pad */
1307 name_len = strnlen(fileName, PATH_MAX);
1308 name_len++; /* trailing null */
1309 pSMB->NameLength = cpu_to_le16(name_len);
1310 strncpy(pSMB->fileName, fileName, name_len);
1312 if (*pOplock & REQ_OPLOCK)
1313 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1314 else if (*pOplock & REQ_BATCHOPLOCK)
1315 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1316 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1317 pSMB->AllocationSize = 0;
1318 /* set file as system file if special file such
1319 as fifo and server expecting SFU style and
1320 no Unix extensions */
1321 if (create_options & CREATE_OPTION_SPECIAL)
1322 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1323 else
1324 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1326 /* XP does not handle ATTR_POSIX_SEMANTICS */
1327 /* but it helps speed up case sensitive checks for other
1328 servers such as Samba */
1329 if (tcon->ses->capabilities & CAP_UNIX)
1330 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1332 if (create_options & CREATE_OPTION_READONLY)
1333 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1335 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1336 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1337 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1338 /* BB Expirement with various impersonation levels and verify */
1339 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1340 pSMB->SecurityFlags =
1341 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1343 count += name_len;
1344 pSMB->hdr.smb_buf_length += count;
1346 pSMB->ByteCount = cpu_to_le16(count);
1347 /* long_op set to 1 to allow for oplock break timeouts */
1348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1349 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1350 cifs_stats_inc(&tcon->num_opens);
1351 if (rc) {
1352 cFYI(1, "Error in Open = %d", rc);
1353 } else {
1354 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1355 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1356 /* Let caller know file was created so we can set the mode. */
1357 /* Do we care about the CreateAction in any other cases? */
1358 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1359 *pOplock |= CIFS_CREATE_ACTION;
1360 if (pfile_info) {
1361 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1362 36 /* CreationTime to Attributes */);
1363 /* the file_info buf is endian converted by caller */
1364 pfile_info->AllocationSize = pSMBr->AllocationSize;
1365 pfile_info->EndOfFile = pSMBr->EndOfFile;
1366 pfile_info->NumberOfLinks = cpu_to_le32(1);
1367 pfile_info->DeletePending = 0;
1371 cifs_buf_release(pSMB);
1372 if (rc == -EAGAIN)
1373 goto openRetry;
1374 return rc;
1378 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1379 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1380 char **buf, int *pbuf_type)
1382 int rc = -EACCES;
1383 READ_REQ *pSMB = NULL;
1384 READ_RSP *pSMBr = NULL;
1385 char *pReadData = NULL;
1386 int wct;
1387 int resp_buf_type = 0;
1388 struct kvec iov[1];
1390 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
1391 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1392 wct = 12;
1393 else {
1394 wct = 10; /* old style read */
1395 if ((lseek >> 32) > 0) {
1396 /* can not handle this big offset for old */
1397 return -EIO;
1401 *nbytes = 0;
1402 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1403 if (rc)
1404 return rc;
1406 /* tcon and ses pointer are checked in smb_init */
1407 if (tcon->ses->server == NULL)
1408 return -ECONNABORTED;
1410 pSMB->AndXCommand = 0xFF; /* none */
1411 pSMB->Fid = netfid;
1412 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1413 if (wct == 12)
1414 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1416 pSMB->Remaining = 0;
1417 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1418 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1419 if (wct == 12)
1420 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1421 else {
1422 /* old style read */
1423 struct smb_com_readx_req *pSMBW =
1424 (struct smb_com_readx_req *)pSMB;
1425 pSMBW->ByteCount = 0;
1428 iov[0].iov_base = (char *)pSMB;
1429 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1430 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1431 &resp_buf_type, CIFS_LOG_ERROR);
1432 cifs_stats_inc(&tcon->num_reads);
1433 pSMBr = (READ_RSP *)iov[0].iov_base;
1434 if (rc) {
1435 cERROR(1, "Send error in read = %d", rc);
1436 } else {
1437 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1438 data_length = data_length << 16;
1439 data_length += le16_to_cpu(pSMBr->DataLength);
1440 *nbytes = data_length;
1442 /*check that DataLength would not go beyond end of SMB */
1443 if ((data_length > CIFSMaxBufSize)
1444 || (data_length > count)) {
1445 cFYI(1, "bad length %d for count %d",
1446 data_length, count);
1447 rc = -EIO;
1448 *nbytes = 0;
1449 } else {
1450 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1451 le16_to_cpu(pSMBr->DataOffset);
1452 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1453 cERROR(1, "Faulting on read rc = %d",rc);
1454 rc = -EFAULT;
1455 }*/ /* can not use copy_to_user when using page cache*/
1456 if (*buf)
1457 memcpy(*buf, pReadData, data_length);
1461 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1462 if (*buf) {
1463 if (resp_buf_type == CIFS_SMALL_BUFFER)
1464 cifs_small_buf_release(iov[0].iov_base);
1465 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1466 cifs_buf_release(iov[0].iov_base);
1467 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1468 /* return buffer to caller to free */
1469 *buf = iov[0].iov_base;
1470 if (resp_buf_type == CIFS_SMALL_BUFFER)
1471 *pbuf_type = CIFS_SMALL_BUFFER;
1472 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1473 *pbuf_type = CIFS_LARGE_BUFFER;
1474 } /* else no valid buffer on return - leave as null */
1476 /* Note: On -EAGAIN error only caller can retry on handle based calls
1477 since file handle passed in no longer valid */
1478 return rc;
1483 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1484 const int netfid, const unsigned int count,
1485 const __u64 offset, unsigned int *nbytes, const char *buf,
1486 const char __user *ubuf, const int long_op)
1488 int rc = -EACCES;
1489 WRITE_REQ *pSMB = NULL;
1490 WRITE_RSP *pSMBr = NULL;
1491 int bytes_returned, wct;
1492 __u32 bytes_sent;
1493 __u16 byte_count;
1495 *nbytes = 0;
1497 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
1498 if (tcon->ses == NULL)
1499 return -ECONNABORTED;
1501 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1502 wct = 14;
1503 else {
1504 wct = 12;
1505 if ((offset >> 32) > 0) {
1506 /* can not handle big offset for old srv */
1507 return -EIO;
1511 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1512 (void **) &pSMBr);
1513 if (rc)
1514 return rc;
1515 /* tcon and ses pointer are checked in smb_init */
1516 if (tcon->ses->server == NULL)
1517 return -ECONNABORTED;
1519 pSMB->AndXCommand = 0xFF; /* none */
1520 pSMB->Fid = netfid;
1521 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1522 if (wct == 14)
1523 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1525 pSMB->Reserved = 0xFFFFFFFF;
1526 pSMB->WriteMode = 0;
1527 pSMB->Remaining = 0;
1529 /* Can increase buffer size if buffer is big enough in some cases ie we
1530 can send more if LARGE_WRITE_X capability returned by the server and if
1531 our buffer is big enough or if we convert to iovecs on socket writes
1532 and eliminate the copy to the CIFS buffer */
1533 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1534 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1535 } else {
1536 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1537 & ~0xFF;
1540 if (bytes_sent > count)
1541 bytes_sent = count;
1542 pSMB->DataOffset =
1543 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1544 if (buf)
1545 memcpy(pSMB->Data, buf, bytes_sent);
1546 else if (ubuf) {
1547 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1548 cifs_buf_release(pSMB);
1549 return -EFAULT;
1551 } else if (count != 0) {
1552 /* No buffer */
1553 cifs_buf_release(pSMB);
1554 return -EINVAL;
1555 } /* else setting file size with write of zero bytes */
1556 if (wct == 14)
1557 byte_count = bytes_sent + 1; /* pad */
1558 else /* wct == 12 */
1559 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1561 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1562 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1563 pSMB->hdr.smb_buf_length += byte_count;
1565 if (wct == 14)
1566 pSMB->ByteCount = cpu_to_le16(byte_count);
1567 else { /* old style write has byte count 4 bytes earlier
1568 so 4 bytes pad */
1569 struct smb_com_writex_req *pSMBW =
1570 (struct smb_com_writex_req *)pSMB;
1571 pSMBW->ByteCount = cpu_to_le16(byte_count);
1574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1575 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1576 cifs_stats_inc(&tcon->num_writes);
1577 if (rc) {
1578 cFYI(1, "Send error in write = %d", rc);
1579 } else {
1580 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1581 *nbytes = (*nbytes) << 16;
1582 *nbytes += le16_to_cpu(pSMBr->Count);
1585 * Mask off high 16 bits when bytes written as returned by the
1586 * server is greater than bytes requested by the client. Some
1587 * OS/2 servers are known to set incorrect CountHigh values.
1589 if (*nbytes > count)
1590 *nbytes &= 0xFFFF;
1593 cifs_buf_release(pSMB);
1595 /* Note: On -EAGAIN error only caller can retry on handle based calls
1596 since file handle passed in no longer valid */
1598 return rc;
1602 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1603 const int netfid, const unsigned int count,
1604 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1605 int n_vec, const int long_op)
1607 int rc = -EACCES;
1608 WRITE_REQ *pSMB = NULL;
1609 int wct;
1610 int smb_hdr_len;
1611 int resp_buf_type = 0;
1613 *nbytes = 0;
1615 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
1617 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1618 wct = 14;
1619 } else {
1620 wct = 12;
1621 if ((offset >> 32) > 0) {
1622 /* can not handle big offset for old srv */
1623 return -EIO;
1626 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1627 if (rc)
1628 return rc;
1629 /* tcon and ses pointer are checked in smb_init */
1630 if (tcon->ses->server == NULL)
1631 return -ECONNABORTED;
1633 pSMB->AndXCommand = 0xFF; /* none */
1634 pSMB->Fid = netfid;
1635 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1636 if (wct == 14)
1637 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1638 pSMB->Reserved = 0xFFFFFFFF;
1639 pSMB->WriteMode = 0;
1640 pSMB->Remaining = 0;
1642 pSMB->DataOffset =
1643 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1645 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1646 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1647 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1648 if (wct == 14)
1649 pSMB->hdr.smb_buf_length += count+1;
1650 else /* wct == 12 */
1651 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1652 if (wct == 14)
1653 pSMB->ByteCount = cpu_to_le16(count + 1);
1654 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1655 struct smb_com_writex_req *pSMBW =
1656 (struct smb_com_writex_req *)pSMB;
1657 pSMBW->ByteCount = cpu_to_le16(count + 5);
1659 iov[0].iov_base = pSMB;
1660 if (wct == 14)
1661 iov[0].iov_len = smb_hdr_len + 4;
1662 else /* wct == 12 pad bigger by four bytes */
1663 iov[0].iov_len = smb_hdr_len + 8;
1666 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1667 long_op);
1668 cifs_stats_inc(&tcon->num_writes);
1669 if (rc) {
1670 cFYI(1, "Send error Write2 = %d", rc);
1671 } else if (resp_buf_type == 0) {
1672 /* presumably this can not happen, but best to be safe */
1673 rc = -EIO;
1674 } else {
1675 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1676 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1677 *nbytes = (*nbytes) << 16;
1678 *nbytes += le16_to_cpu(pSMBr->Count);
1681 * Mask off high 16 bits when bytes written as returned by the
1682 * server is greater than bytes requested by the client. OS/2
1683 * servers are known to set incorrect CountHigh values.
1685 if (*nbytes > count)
1686 *nbytes &= 0xFFFF;
1689 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1690 if (resp_buf_type == CIFS_SMALL_BUFFER)
1691 cifs_small_buf_release(iov[0].iov_base);
1692 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1693 cifs_buf_release(iov[0].iov_base);
1695 /* Note: On -EAGAIN error only caller can retry on handle based calls
1696 since file handle passed in no longer valid */
1698 return rc;
1703 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1704 const __u16 smb_file_id, const __u64 len,
1705 const __u64 offset, const __u32 numUnlock,
1706 const __u32 numLock, const __u8 lockType,
1707 const bool waitFlag, const __u8 oplock_level)
1709 int rc = 0;
1710 LOCK_REQ *pSMB = NULL;
1711 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1712 int bytes_returned;
1713 int timeout = 0;
1714 __u16 count;
1716 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
1717 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1719 if (rc)
1720 return rc;
1722 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1723 timeout = CIFS_ASYNC_OP; /* no response expected */
1724 pSMB->Timeout = 0;
1725 } else if (waitFlag) {
1726 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1727 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1728 } else {
1729 pSMB->Timeout = 0;
1732 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1733 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1734 pSMB->LockType = lockType;
1735 pSMB->OplockLevel = oplock_level;
1736 pSMB->AndXCommand = 0xFF; /* none */
1737 pSMB->Fid = smb_file_id; /* netfid stays le */
1739 if ((numLock != 0) || (numUnlock != 0)) {
1740 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1741 /* BB where to store pid high? */
1742 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1743 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1744 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1745 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1746 count = sizeof(LOCKING_ANDX_RANGE);
1747 } else {
1748 /* oplock break */
1749 count = 0;
1751 pSMB->hdr.smb_buf_length += count;
1752 pSMB->ByteCount = cpu_to_le16(count);
1754 if (waitFlag) {
1755 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1756 (struct smb_hdr *) pSMB, &bytes_returned);
1757 cifs_small_buf_release(pSMB);
1758 } else {
1759 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1760 timeout);
1761 /* SMB buffer freed by function above */
1763 cifs_stats_inc(&tcon->num_locks);
1764 if (rc)
1765 cFYI(1, "Send error in Lock = %d", rc);
1767 /* Note: On -EAGAIN error only caller can retry on handle based calls
1768 since file handle passed in no longer valid */
1769 return rc;
1773 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1774 const __u16 smb_file_id, const int get_flag, const __u64 len,
1775 struct file_lock *pLockData, const __u16 lock_type,
1776 const bool waitFlag)
1778 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1779 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1780 struct cifs_posix_lock *parm_data;
1781 int rc = 0;
1782 int timeout = 0;
1783 int bytes_returned = 0;
1784 int resp_buf_type = 0;
1785 __u16 params, param_offset, offset, byte_count, count;
1786 struct kvec iov[1];
1788 cFYI(1, "Posix Lock");
1790 if (pLockData == NULL)
1791 return -EINVAL;
1793 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1795 if (rc)
1796 return rc;
1798 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1800 params = 6;
1801 pSMB->MaxSetupCount = 0;
1802 pSMB->Reserved = 0;
1803 pSMB->Flags = 0;
1804 pSMB->Reserved2 = 0;
1805 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1806 offset = param_offset + params;
1808 count = sizeof(struct cifs_posix_lock);
1809 pSMB->MaxParameterCount = cpu_to_le16(2);
1810 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1811 pSMB->SetupCount = 1;
1812 pSMB->Reserved3 = 0;
1813 if (get_flag)
1814 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1815 else
1816 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1817 byte_count = 3 /* pad */ + params + count;
1818 pSMB->DataCount = cpu_to_le16(count);
1819 pSMB->ParameterCount = cpu_to_le16(params);
1820 pSMB->TotalDataCount = pSMB->DataCount;
1821 pSMB->TotalParameterCount = pSMB->ParameterCount;
1822 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1823 parm_data = (struct cifs_posix_lock *)
1824 (((char *) &pSMB->hdr.Protocol) + offset);
1826 parm_data->lock_type = cpu_to_le16(lock_type);
1827 if (waitFlag) {
1828 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1829 parm_data->lock_flags = cpu_to_le16(1);
1830 pSMB->Timeout = cpu_to_le32(-1);
1831 } else
1832 pSMB->Timeout = 0;
1834 parm_data->pid = cpu_to_le32(current->tgid);
1835 parm_data->start = cpu_to_le64(pLockData->fl_start);
1836 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1838 pSMB->DataOffset = cpu_to_le16(offset);
1839 pSMB->Fid = smb_file_id;
1840 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1841 pSMB->Reserved4 = 0;
1842 pSMB->hdr.smb_buf_length += byte_count;
1843 pSMB->ByteCount = cpu_to_le16(byte_count);
1844 if (waitFlag) {
1845 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1846 (struct smb_hdr *) pSMBr, &bytes_returned);
1847 } else {
1848 iov[0].iov_base = (char *)pSMB;
1849 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1850 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1851 &resp_buf_type, timeout);
1852 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1853 not try to free it twice below on exit */
1854 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1857 if (rc) {
1858 cFYI(1, "Send error in Posix Lock = %d", rc);
1859 } else if (get_flag) {
1860 /* lock structure can be returned on get */
1861 __u16 data_offset;
1862 __u16 data_count;
1863 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1865 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1866 rc = -EIO; /* bad smb */
1867 goto plk_err_exit;
1869 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1870 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1871 if (data_count < sizeof(struct cifs_posix_lock)) {
1872 rc = -EIO;
1873 goto plk_err_exit;
1875 parm_data = (struct cifs_posix_lock *)
1876 ((char *)&pSMBr->hdr.Protocol + data_offset);
1877 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
1878 pLockData->fl_type = F_UNLCK;
1879 else {
1880 if (parm_data->lock_type ==
1881 __constant_cpu_to_le16(CIFS_RDLCK))
1882 pLockData->fl_type = F_RDLCK;
1883 else if (parm_data->lock_type ==
1884 __constant_cpu_to_le16(CIFS_WRLCK))
1885 pLockData->fl_type = F_WRLCK;
1887 pLockData->fl_start = le64_to_cpu(parm_data->start);
1888 pLockData->fl_end = pLockData->fl_start +
1889 le64_to_cpu(parm_data->length) - 1;
1890 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
1894 plk_err_exit:
1895 if (pSMB)
1896 cifs_small_buf_release(pSMB);
1898 if (resp_buf_type == CIFS_SMALL_BUFFER)
1899 cifs_small_buf_release(iov[0].iov_base);
1900 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1901 cifs_buf_release(iov[0].iov_base);
1903 /* Note: On -EAGAIN error only caller can retry on handle based calls
1904 since file handle passed in no longer valid */
1906 return rc;
1911 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1913 int rc = 0;
1914 CLOSE_REQ *pSMB = NULL;
1915 cFYI(1, "In CIFSSMBClose");
1917 /* do not retry on dead session on close */
1918 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1919 if (rc == -EAGAIN)
1920 return 0;
1921 if (rc)
1922 return rc;
1924 pSMB->FileID = (__u16) smb_file_id;
1925 pSMB->LastWriteTime = 0xFFFFFFFF;
1926 pSMB->ByteCount = 0;
1927 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1928 cifs_stats_inc(&tcon->num_closes);
1929 if (rc) {
1930 if (rc != -EINTR) {
1931 /* EINTR is expected when user ctl-c to kill app */
1932 cERROR(1, "Send error in Close = %d", rc);
1936 /* Since session is dead, file will be closed on server already */
1937 if (rc == -EAGAIN)
1938 rc = 0;
1940 return rc;
1944 CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1946 int rc = 0;
1947 FLUSH_REQ *pSMB = NULL;
1948 cFYI(1, "In CIFSSMBFlush");
1950 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1951 if (rc)
1952 return rc;
1954 pSMB->FileID = (__u16) smb_file_id;
1955 pSMB->ByteCount = 0;
1956 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1957 cifs_stats_inc(&tcon->num_flushes);
1958 if (rc)
1959 cERROR(1, "Send error in Flush = %d", rc);
1961 return rc;
1965 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1966 const char *fromName, const char *toName,
1967 const struct nls_table *nls_codepage, int remap)
1969 int rc = 0;
1970 RENAME_REQ *pSMB = NULL;
1971 RENAME_RSP *pSMBr = NULL;
1972 int bytes_returned;
1973 int name_len, name_len2;
1974 __u16 count;
1976 cFYI(1, "In CIFSSMBRename");
1977 renameRetry:
1978 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1979 (void **) &pSMBr);
1980 if (rc)
1981 return rc;
1983 pSMB->BufferFormat = 0x04;
1984 pSMB->SearchAttributes =
1985 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1986 ATTR_DIRECTORY);
1988 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1989 name_len =
1990 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1991 PATH_MAX, nls_codepage, remap);
1992 name_len++; /* trailing null */
1993 name_len *= 2;
1994 pSMB->OldFileName[name_len] = 0x04; /* pad */
1995 /* protocol requires ASCII signature byte on Unicode string */
1996 pSMB->OldFileName[name_len + 1] = 0x00;
1997 name_len2 =
1998 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1999 toName, PATH_MAX, nls_codepage, remap);
2000 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2001 name_len2 *= 2; /* convert to bytes */
2002 } else { /* BB improve the check for buffer overruns BB */
2003 name_len = strnlen(fromName, PATH_MAX);
2004 name_len++; /* trailing null */
2005 strncpy(pSMB->OldFileName, fromName, name_len);
2006 name_len2 = strnlen(toName, PATH_MAX);
2007 name_len2++; /* trailing null */
2008 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2009 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2010 name_len2++; /* trailing null */
2011 name_len2++; /* signature byte */
2014 count = 1 /* 1st signature byte */ + name_len + name_len2;
2015 pSMB->hdr.smb_buf_length += count;
2016 pSMB->ByteCount = cpu_to_le16(count);
2018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2019 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2020 cifs_stats_inc(&tcon->num_renames);
2021 if (rc)
2022 cFYI(1, "Send error in rename = %d", rc);
2024 cifs_buf_release(pSMB);
2026 if (rc == -EAGAIN)
2027 goto renameRetry;
2029 return rc;
2032 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2033 int netfid, const char *target_name,
2034 const struct nls_table *nls_codepage, int remap)
2036 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2037 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2038 struct set_file_rename *rename_info;
2039 char *data_offset;
2040 char dummy_string[30];
2041 int rc = 0;
2042 int bytes_returned = 0;
2043 int len_of_str;
2044 __u16 params, param_offset, offset, count, byte_count;
2046 cFYI(1, "Rename to File by handle");
2047 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2048 (void **) &pSMBr);
2049 if (rc)
2050 return rc;
2052 params = 6;
2053 pSMB->MaxSetupCount = 0;
2054 pSMB->Reserved = 0;
2055 pSMB->Flags = 0;
2056 pSMB->Timeout = 0;
2057 pSMB->Reserved2 = 0;
2058 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2059 offset = param_offset + params;
2061 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2062 rename_info = (struct set_file_rename *) data_offset;
2063 pSMB->MaxParameterCount = cpu_to_le16(2);
2064 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2065 pSMB->SetupCount = 1;
2066 pSMB->Reserved3 = 0;
2067 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2068 byte_count = 3 /* pad */ + params;
2069 pSMB->ParameterCount = cpu_to_le16(params);
2070 pSMB->TotalParameterCount = pSMB->ParameterCount;
2071 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2072 pSMB->DataOffset = cpu_to_le16(offset);
2073 /* construct random name ".cifs_tmp<inodenum><mid>" */
2074 rename_info->overwrite = cpu_to_le32(1);
2075 rename_info->root_fid = 0;
2076 /* unicode only call */
2077 if (target_name == NULL) {
2078 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2079 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2080 dummy_string, 24, nls_codepage, remap);
2081 } else {
2082 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2083 target_name, PATH_MAX, nls_codepage,
2084 remap);
2086 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2087 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2088 byte_count += count;
2089 pSMB->DataCount = cpu_to_le16(count);
2090 pSMB->TotalDataCount = pSMB->DataCount;
2091 pSMB->Fid = netfid;
2092 pSMB->InformationLevel =
2093 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2094 pSMB->Reserved4 = 0;
2095 pSMB->hdr.smb_buf_length += byte_count;
2096 pSMB->ByteCount = cpu_to_le16(byte_count);
2097 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2099 cifs_stats_inc(&pTcon->num_t2renames);
2100 if (rc)
2101 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
2103 cifs_buf_release(pSMB);
2105 /* Note: On -EAGAIN error only caller can retry on handle based calls
2106 since file handle passed in no longer valid */
2108 return rc;
2112 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2113 const __u16 target_tid, const char *toName, const int flags,
2114 const struct nls_table *nls_codepage, int remap)
2116 int rc = 0;
2117 COPY_REQ *pSMB = NULL;
2118 COPY_RSP *pSMBr = NULL;
2119 int bytes_returned;
2120 int name_len, name_len2;
2121 __u16 count;
2123 cFYI(1, "In CIFSSMBCopy");
2124 copyRetry:
2125 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2126 (void **) &pSMBr);
2127 if (rc)
2128 return rc;
2130 pSMB->BufferFormat = 0x04;
2131 pSMB->Tid2 = target_tid;
2133 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2135 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2136 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2137 fromName, PATH_MAX, nls_codepage,
2138 remap);
2139 name_len++; /* trailing null */
2140 name_len *= 2;
2141 pSMB->OldFileName[name_len] = 0x04; /* pad */
2142 /* protocol requires ASCII signature byte on Unicode string */
2143 pSMB->OldFileName[name_len + 1] = 0x00;
2144 name_len2 =
2145 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2146 toName, PATH_MAX, nls_codepage, remap);
2147 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2148 name_len2 *= 2; /* convert to bytes */
2149 } else { /* BB improve the check for buffer overruns BB */
2150 name_len = strnlen(fromName, PATH_MAX);
2151 name_len++; /* trailing null */
2152 strncpy(pSMB->OldFileName, fromName, name_len);
2153 name_len2 = strnlen(toName, PATH_MAX);
2154 name_len2++; /* trailing null */
2155 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2156 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2157 name_len2++; /* trailing null */
2158 name_len2++; /* signature byte */
2161 count = 1 /* 1st signature byte */ + name_len + name_len2;
2162 pSMB->hdr.smb_buf_length += count;
2163 pSMB->ByteCount = cpu_to_le16(count);
2165 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2166 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2167 if (rc) {
2168 cFYI(1, "Send error in copy = %d with %d files copied",
2169 rc, le16_to_cpu(pSMBr->CopyCount));
2171 cifs_buf_release(pSMB);
2173 if (rc == -EAGAIN)
2174 goto copyRetry;
2176 return rc;
2180 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2181 const char *fromName, const char *toName,
2182 const struct nls_table *nls_codepage)
2184 TRANSACTION2_SPI_REQ *pSMB = NULL;
2185 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2186 char *data_offset;
2187 int name_len;
2188 int name_len_target;
2189 int rc = 0;
2190 int bytes_returned = 0;
2191 __u16 params, param_offset, offset, byte_count;
2193 cFYI(1, "In Symlink Unix style");
2194 createSymLinkRetry:
2195 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2196 (void **) &pSMBr);
2197 if (rc)
2198 return rc;
2200 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2201 name_len =
2202 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2203 /* find define for this maxpathcomponent */
2204 , nls_codepage);
2205 name_len++; /* trailing null */
2206 name_len *= 2;
2208 } else { /* BB improve the check for buffer overruns BB */
2209 name_len = strnlen(fromName, PATH_MAX);
2210 name_len++; /* trailing null */
2211 strncpy(pSMB->FileName, fromName, name_len);
2213 params = 6 + name_len;
2214 pSMB->MaxSetupCount = 0;
2215 pSMB->Reserved = 0;
2216 pSMB->Flags = 0;
2217 pSMB->Timeout = 0;
2218 pSMB->Reserved2 = 0;
2219 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2220 InformationLevel) - 4;
2221 offset = param_offset + params;
2223 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2224 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2225 name_len_target =
2226 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2227 /* find define for this maxpathcomponent */
2228 , nls_codepage);
2229 name_len_target++; /* trailing null */
2230 name_len_target *= 2;
2231 } else { /* BB improve the check for buffer overruns BB */
2232 name_len_target = strnlen(toName, PATH_MAX);
2233 name_len_target++; /* trailing null */
2234 strncpy(data_offset, toName, name_len_target);
2237 pSMB->MaxParameterCount = cpu_to_le16(2);
2238 /* BB find exact max on data count below from sess */
2239 pSMB->MaxDataCount = cpu_to_le16(1000);
2240 pSMB->SetupCount = 1;
2241 pSMB->Reserved3 = 0;
2242 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2243 byte_count = 3 /* pad */ + params + name_len_target;
2244 pSMB->DataCount = cpu_to_le16(name_len_target);
2245 pSMB->ParameterCount = cpu_to_le16(params);
2246 pSMB->TotalDataCount = pSMB->DataCount;
2247 pSMB->TotalParameterCount = pSMB->ParameterCount;
2248 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2249 pSMB->DataOffset = cpu_to_le16(offset);
2250 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2251 pSMB->Reserved4 = 0;
2252 pSMB->hdr.smb_buf_length += byte_count;
2253 pSMB->ByteCount = cpu_to_le16(byte_count);
2254 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2255 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2256 cifs_stats_inc(&tcon->num_symlinks);
2257 if (rc)
2258 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
2260 cifs_buf_release(pSMB);
2262 if (rc == -EAGAIN)
2263 goto createSymLinkRetry;
2265 return rc;
2269 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2270 const char *fromName, const char *toName,
2271 const struct nls_table *nls_codepage, int remap)
2273 TRANSACTION2_SPI_REQ *pSMB = NULL;
2274 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2275 char *data_offset;
2276 int name_len;
2277 int name_len_target;
2278 int rc = 0;
2279 int bytes_returned = 0;
2280 __u16 params, param_offset, offset, byte_count;
2282 cFYI(1, "In Create Hard link Unix style");
2283 createHardLinkRetry:
2284 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2285 (void **) &pSMBr);
2286 if (rc)
2287 return rc;
2289 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2290 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2291 PATH_MAX, nls_codepage, remap);
2292 name_len++; /* trailing null */
2293 name_len *= 2;
2295 } else { /* BB improve the check for buffer overruns BB */
2296 name_len = strnlen(toName, PATH_MAX);
2297 name_len++; /* trailing null */
2298 strncpy(pSMB->FileName, toName, name_len);
2300 params = 6 + name_len;
2301 pSMB->MaxSetupCount = 0;
2302 pSMB->Reserved = 0;
2303 pSMB->Flags = 0;
2304 pSMB->Timeout = 0;
2305 pSMB->Reserved2 = 0;
2306 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2307 InformationLevel) - 4;
2308 offset = param_offset + params;
2310 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2311 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2312 name_len_target =
2313 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2314 nls_codepage, remap);
2315 name_len_target++; /* trailing null */
2316 name_len_target *= 2;
2317 } else { /* BB improve the check for buffer overruns BB */
2318 name_len_target = strnlen(fromName, PATH_MAX);
2319 name_len_target++; /* trailing null */
2320 strncpy(data_offset, fromName, name_len_target);
2323 pSMB->MaxParameterCount = cpu_to_le16(2);
2324 /* BB find exact max on data count below from sess*/
2325 pSMB->MaxDataCount = cpu_to_le16(1000);
2326 pSMB->SetupCount = 1;
2327 pSMB->Reserved3 = 0;
2328 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2329 byte_count = 3 /* pad */ + params + name_len_target;
2330 pSMB->ParameterCount = cpu_to_le16(params);
2331 pSMB->TotalParameterCount = pSMB->ParameterCount;
2332 pSMB->DataCount = cpu_to_le16(name_len_target);
2333 pSMB->TotalDataCount = pSMB->DataCount;
2334 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2335 pSMB->DataOffset = cpu_to_le16(offset);
2336 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2337 pSMB->Reserved4 = 0;
2338 pSMB->hdr.smb_buf_length += byte_count;
2339 pSMB->ByteCount = cpu_to_le16(byte_count);
2340 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2341 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2342 cifs_stats_inc(&tcon->num_hardlinks);
2343 if (rc)
2344 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
2346 cifs_buf_release(pSMB);
2347 if (rc == -EAGAIN)
2348 goto createHardLinkRetry;
2350 return rc;
2354 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2355 const char *fromName, const char *toName,
2356 const struct nls_table *nls_codepage, int remap)
2358 int rc = 0;
2359 NT_RENAME_REQ *pSMB = NULL;
2360 RENAME_RSP *pSMBr = NULL;
2361 int bytes_returned;
2362 int name_len, name_len2;
2363 __u16 count;
2365 cFYI(1, "In CIFSCreateHardLink");
2366 winCreateHardLinkRetry:
2368 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2369 (void **) &pSMBr);
2370 if (rc)
2371 return rc;
2373 pSMB->SearchAttributes =
2374 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2375 ATTR_DIRECTORY);
2376 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2377 pSMB->ClusterCount = 0;
2379 pSMB->BufferFormat = 0x04;
2381 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2382 name_len =
2383 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2384 PATH_MAX, nls_codepage, remap);
2385 name_len++; /* trailing null */
2386 name_len *= 2;
2388 /* protocol specifies ASCII buffer format (0x04) for unicode */
2389 pSMB->OldFileName[name_len] = 0x04;
2390 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2391 name_len2 =
2392 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2393 toName, PATH_MAX, nls_codepage, remap);
2394 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2395 name_len2 *= 2; /* convert to bytes */
2396 } else { /* BB improve the check for buffer overruns BB */
2397 name_len = strnlen(fromName, PATH_MAX);
2398 name_len++; /* trailing null */
2399 strncpy(pSMB->OldFileName, fromName, name_len);
2400 name_len2 = strnlen(toName, PATH_MAX);
2401 name_len2++; /* trailing null */
2402 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2403 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2404 name_len2++; /* trailing null */
2405 name_len2++; /* signature byte */
2408 count = 1 /* string type byte */ + name_len + name_len2;
2409 pSMB->hdr.smb_buf_length += count;
2410 pSMB->ByteCount = cpu_to_le16(count);
2412 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2413 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2414 cifs_stats_inc(&tcon->num_hardlinks);
2415 if (rc)
2416 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
2418 cifs_buf_release(pSMB);
2419 if (rc == -EAGAIN)
2420 goto winCreateHardLinkRetry;
2422 return rc;
2426 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2427 const unsigned char *searchName, char **symlinkinfo,
2428 const struct nls_table *nls_codepage)
2430 /* SMB_QUERY_FILE_UNIX_LINK */
2431 TRANSACTION2_QPI_REQ *pSMB = NULL;
2432 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2433 int rc = 0;
2434 int bytes_returned;
2435 int name_len;
2436 __u16 params, byte_count;
2437 char *data_start;
2439 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
2441 querySymLinkRetry:
2442 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2443 (void **) &pSMBr);
2444 if (rc)
2445 return rc;
2447 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2448 name_len =
2449 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2450 PATH_MAX, nls_codepage);
2451 name_len++; /* trailing null */
2452 name_len *= 2;
2453 } else { /* BB improve the check for buffer overruns BB */
2454 name_len = strnlen(searchName, PATH_MAX);
2455 name_len++; /* trailing null */
2456 strncpy(pSMB->FileName, searchName, name_len);
2459 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2460 pSMB->TotalDataCount = 0;
2461 pSMB->MaxParameterCount = cpu_to_le16(2);
2462 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
2463 pSMB->MaxSetupCount = 0;
2464 pSMB->Reserved = 0;
2465 pSMB->Flags = 0;
2466 pSMB->Timeout = 0;
2467 pSMB->Reserved2 = 0;
2468 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2469 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2470 pSMB->DataCount = 0;
2471 pSMB->DataOffset = 0;
2472 pSMB->SetupCount = 1;
2473 pSMB->Reserved3 = 0;
2474 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2475 byte_count = params + 1 /* pad */ ;
2476 pSMB->TotalParameterCount = cpu_to_le16(params);
2477 pSMB->ParameterCount = pSMB->TotalParameterCount;
2478 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2479 pSMB->Reserved4 = 0;
2480 pSMB->hdr.smb_buf_length += byte_count;
2481 pSMB->ByteCount = cpu_to_le16(byte_count);
2483 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2484 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2485 if (rc) {
2486 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
2487 } else {
2488 /* decode response */
2490 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2491 /* BB also check enough total bytes returned */
2492 if (rc || (pSMBr->ByteCount < 2))
2493 rc = -EIO;
2494 else {
2495 bool is_unicode;
2496 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2498 data_start = ((char *) &pSMBr->hdr.Protocol) +
2499 le16_to_cpu(pSMBr->t2.DataOffset);
2501 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2502 is_unicode = true;
2503 else
2504 is_unicode = false;
2506 /* BB FIXME investigate remapping reserved chars here */
2507 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
2508 is_unicode, nls_codepage);
2509 if (!*symlinkinfo)
2510 rc = -ENOMEM;
2513 cifs_buf_release(pSMB);
2514 if (rc == -EAGAIN)
2515 goto querySymLinkRetry;
2516 return rc;
2519 #ifdef CONFIG_CIFS_EXPERIMENTAL
2521 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2522 const unsigned char *searchName,
2523 char *symlinkinfo, const int buflen, __u16 fid,
2524 const struct nls_table *nls_codepage)
2526 int rc = 0;
2527 int bytes_returned;
2528 struct smb_com_transaction_ioctl_req *pSMB;
2529 struct smb_com_transaction_ioctl_rsp *pSMBr;
2531 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
2532 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2533 (void **) &pSMBr);
2534 if (rc)
2535 return rc;
2537 pSMB->TotalParameterCount = 0 ;
2538 pSMB->TotalDataCount = 0;
2539 pSMB->MaxParameterCount = cpu_to_le32(2);
2540 /* BB find exact data count max from sess structure BB */
2541 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2542 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2543 pSMB->MaxSetupCount = 4;
2544 pSMB->Reserved = 0;
2545 pSMB->ParameterOffset = 0;
2546 pSMB->DataCount = 0;
2547 pSMB->DataOffset = 0;
2548 pSMB->SetupCount = 4;
2549 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2550 pSMB->ParameterCount = pSMB->TotalParameterCount;
2551 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2552 pSMB->IsFsctl = 1; /* FSCTL */
2553 pSMB->IsRootFlag = 0;
2554 pSMB->Fid = fid; /* file handle always le */
2555 pSMB->ByteCount = 0;
2557 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2558 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2559 if (rc) {
2560 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
2561 } else { /* decode response */
2562 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2563 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2564 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
2565 /* BB also check enough total bytes returned */
2566 rc = -EIO; /* bad smb */
2567 goto qreparse_out;
2569 if (data_count && (data_count < 2048)) {
2570 char *end_of_smb = 2 /* sizeof byte count */ +
2571 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
2573 struct reparse_data *reparse_buf =
2574 (struct reparse_data *)
2575 ((char *)&pSMBr->hdr.Protocol
2576 + data_offset);
2577 if ((char *)reparse_buf >= end_of_smb) {
2578 rc = -EIO;
2579 goto qreparse_out;
2581 if ((reparse_buf->LinkNamesBuf +
2582 reparse_buf->TargetNameOffset +
2583 reparse_buf->TargetNameLen) > end_of_smb) {
2584 cFYI(1, "reparse buf beyond SMB");
2585 rc = -EIO;
2586 goto qreparse_out;
2589 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2590 cifs_from_ucs2(symlinkinfo, (__le16 *)
2591 (reparse_buf->LinkNamesBuf +
2592 reparse_buf->TargetNameOffset),
2593 buflen,
2594 reparse_buf->TargetNameLen,
2595 nls_codepage, 0);
2596 } else { /* ASCII names */
2597 strncpy(symlinkinfo,
2598 reparse_buf->LinkNamesBuf +
2599 reparse_buf->TargetNameOffset,
2600 min_t(const int, buflen,
2601 reparse_buf->TargetNameLen));
2603 } else {
2604 rc = -EIO;
2605 cFYI(1, "Invalid return data count on "
2606 "get reparse info ioctl");
2608 symlinkinfo[buflen] = 0; /* just in case so the caller
2609 does not go off the end of the buffer */
2610 cFYI(1, "readlink result - %s", symlinkinfo);
2613 qreparse_out:
2614 cifs_buf_release(pSMB);
2616 /* Note: On -EAGAIN error only caller can retry on handle based calls
2617 since file handle passed in no longer valid */
2619 return rc;
2621 #endif /* CIFS_EXPERIMENTAL */
2623 #ifdef CONFIG_CIFS_POSIX
2625 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2626 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2627 struct cifs_posix_ace *cifs_ace)
2629 /* u8 cifs fields do not need le conversion */
2630 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2631 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2632 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2633 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
2635 return;
2638 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2639 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2640 const int acl_type, const int size_of_data_area)
2642 int size = 0;
2643 int i;
2644 __u16 count;
2645 struct cifs_posix_ace *pACE;
2646 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2647 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2649 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2650 return -EOPNOTSUPP;
2652 if (acl_type & ACL_TYPE_ACCESS) {
2653 count = le16_to_cpu(cifs_acl->access_entry_count);
2654 pACE = &cifs_acl->ace_array[0];
2655 size = sizeof(struct cifs_posix_acl);
2656 size += sizeof(struct cifs_posix_ace) * count;
2657 /* check if we would go beyond end of SMB */
2658 if (size_of_data_area < size) {
2659 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2660 size_of_data_area, size);
2661 return -EINVAL;
2663 } else if (acl_type & ACL_TYPE_DEFAULT) {
2664 count = le16_to_cpu(cifs_acl->access_entry_count);
2665 size = sizeof(struct cifs_posix_acl);
2666 size += sizeof(struct cifs_posix_ace) * count;
2667 /* skip past access ACEs to get to default ACEs */
2668 pACE = &cifs_acl->ace_array[count];
2669 count = le16_to_cpu(cifs_acl->default_entry_count);
2670 size += sizeof(struct cifs_posix_ace) * count;
2671 /* check if we would go beyond end of SMB */
2672 if (size_of_data_area < size)
2673 return -EINVAL;
2674 } else {
2675 /* illegal type */
2676 return -EINVAL;
2679 size = posix_acl_xattr_size(count);
2680 if ((buflen == 0) || (local_acl == NULL)) {
2681 /* used to query ACL EA size */
2682 } else if (size > buflen) {
2683 return -ERANGE;
2684 } else /* buffer big enough */ {
2685 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2686 for (i = 0; i < count ; i++) {
2687 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2688 pACE++;
2691 return size;
2694 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2695 const posix_acl_xattr_entry *local_ace)
2697 __u16 rc = 0; /* 0 = ACL converted ok */
2699 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2700 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2701 /* BB is there a better way to handle the large uid? */
2702 if (local_ace->e_id == cpu_to_le32(-1)) {
2703 /* Probably no need to le convert -1 on any arch but can not hurt */
2704 cifs_ace->cifs_uid = cpu_to_le64(-1);
2705 } else
2706 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2707 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
2708 return rc;
2711 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2712 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2713 const int buflen, const int acl_type)
2715 __u16 rc = 0;
2716 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2717 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2718 int count;
2719 int i;
2721 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2722 return 0;
2724 count = posix_acl_xattr_count((size_t)buflen);
2725 cFYI(1, "setting acl with %d entries from buf of length %d and "
2726 "version of %d",
2727 count, buflen, le32_to_cpu(local_acl->a_version));
2728 if (le32_to_cpu(local_acl->a_version) != 2) {
2729 cFYI(1, "unknown POSIX ACL version %d",
2730 le32_to_cpu(local_acl->a_version));
2731 return 0;
2733 cifs_acl->version = cpu_to_le16(1);
2734 if (acl_type == ACL_TYPE_ACCESS)
2735 cifs_acl->access_entry_count = cpu_to_le16(count);
2736 else if (acl_type == ACL_TYPE_DEFAULT)
2737 cifs_acl->default_entry_count = cpu_to_le16(count);
2738 else {
2739 cFYI(1, "unknown ACL type %d", acl_type);
2740 return 0;
2742 for (i = 0; i < count; i++) {
2743 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2744 &local_acl->a_entries[i]);
2745 if (rc != 0) {
2746 /* ACE not converted */
2747 break;
2750 if (rc == 0) {
2751 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2752 rc += sizeof(struct cifs_posix_acl);
2753 /* BB add check to make sure ACL does not overflow SMB */
2755 return rc;
2759 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2760 const unsigned char *searchName,
2761 char *acl_inf, const int buflen, const int acl_type,
2762 const struct nls_table *nls_codepage, int remap)
2764 /* SMB_QUERY_POSIX_ACL */
2765 TRANSACTION2_QPI_REQ *pSMB = NULL;
2766 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2767 int rc = 0;
2768 int bytes_returned;
2769 int name_len;
2770 __u16 params, byte_count;
2772 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
2774 queryAclRetry:
2775 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2776 (void **) &pSMBr);
2777 if (rc)
2778 return rc;
2780 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2781 name_len =
2782 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2783 PATH_MAX, nls_codepage, remap);
2784 name_len++; /* trailing null */
2785 name_len *= 2;
2786 pSMB->FileName[name_len] = 0;
2787 pSMB->FileName[name_len+1] = 0;
2788 } else { /* BB improve the check for buffer overruns BB */
2789 name_len = strnlen(searchName, PATH_MAX);
2790 name_len++; /* trailing null */
2791 strncpy(pSMB->FileName, searchName, name_len);
2794 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2795 pSMB->TotalDataCount = 0;
2796 pSMB->MaxParameterCount = cpu_to_le16(2);
2797 /* BB find exact max data count below from sess structure BB */
2798 pSMB->MaxDataCount = cpu_to_le16(4000);
2799 pSMB->MaxSetupCount = 0;
2800 pSMB->Reserved = 0;
2801 pSMB->Flags = 0;
2802 pSMB->Timeout = 0;
2803 pSMB->Reserved2 = 0;
2804 pSMB->ParameterOffset = cpu_to_le16(
2805 offsetof(struct smb_com_transaction2_qpi_req,
2806 InformationLevel) - 4);
2807 pSMB->DataCount = 0;
2808 pSMB->DataOffset = 0;
2809 pSMB->SetupCount = 1;
2810 pSMB->Reserved3 = 0;
2811 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2812 byte_count = params + 1 /* pad */ ;
2813 pSMB->TotalParameterCount = cpu_to_le16(params);
2814 pSMB->ParameterCount = pSMB->TotalParameterCount;
2815 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2816 pSMB->Reserved4 = 0;
2817 pSMB->hdr.smb_buf_length += byte_count;
2818 pSMB->ByteCount = cpu_to_le16(byte_count);
2820 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2821 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2822 cifs_stats_inc(&tcon->num_acl_get);
2823 if (rc) {
2824 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
2825 } else {
2826 /* decode response */
2828 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2829 if (rc || (pSMBr->ByteCount < 2))
2830 /* BB also check enough total bytes returned */
2831 rc = -EIO; /* bad smb */
2832 else {
2833 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2834 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2835 rc = cifs_copy_posix_acl(acl_inf,
2836 (char *)&pSMBr->hdr.Protocol+data_offset,
2837 buflen, acl_type, count);
2840 cifs_buf_release(pSMB);
2841 if (rc == -EAGAIN)
2842 goto queryAclRetry;
2843 return rc;
2847 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2848 const unsigned char *fileName,
2849 const char *local_acl, const int buflen,
2850 const int acl_type,
2851 const struct nls_table *nls_codepage, int remap)
2853 struct smb_com_transaction2_spi_req *pSMB = NULL;
2854 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2855 char *parm_data;
2856 int name_len;
2857 int rc = 0;
2858 int bytes_returned = 0;
2859 __u16 params, byte_count, data_count, param_offset, offset;
2861 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
2862 setAclRetry:
2863 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2864 (void **) &pSMBr);
2865 if (rc)
2866 return rc;
2867 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2868 name_len =
2869 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2870 PATH_MAX, nls_codepage, remap);
2871 name_len++; /* trailing null */
2872 name_len *= 2;
2873 } else { /* BB improve the check for buffer overruns BB */
2874 name_len = strnlen(fileName, PATH_MAX);
2875 name_len++; /* trailing null */
2876 strncpy(pSMB->FileName, fileName, name_len);
2878 params = 6 + name_len;
2879 pSMB->MaxParameterCount = cpu_to_le16(2);
2880 /* BB find max SMB size from sess */
2881 pSMB->MaxDataCount = cpu_to_le16(1000);
2882 pSMB->MaxSetupCount = 0;
2883 pSMB->Reserved = 0;
2884 pSMB->Flags = 0;
2885 pSMB->Timeout = 0;
2886 pSMB->Reserved2 = 0;
2887 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2888 InformationLevel) - 4;
2889 offset = param_offset + params;
2890 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2891 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2893 /* convert to on the wire format for POSIX ACL */
2894 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2896 if (data_count == 0) {
2897 rc = -EOPNOTSUPP;
2898 goto setACLerrorExit;
2900 pSMB->DataOffset = cpu_to_le16(offset);
2901 pSMB->SetupCount = 1;
2902 pSMB->Reserved3 = 0;
2903 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2904 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2905 byte_count = 3 /* pad */ + params + data_count;
2906 pSMB->DataCount = cpu_to_le16(data_count);
2907 pSMB->TotalDataCount = pSMB->DataCount;
2908 pSMB->ParameterCount = cpu_to_le16(params);
2909 pSMB->TotalParameterCount = pSMB->ParameterCount;
2910 pSMB->Reserved4 = 0;
2911 pSMB->hdr.smb_buf_length += byte_count;
2912 pSMB->ByteCount = cpu_to_le16(byte_count);
2913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2915 if (rc)
2916 cFYI(1, "Set POSIX ACL returned %d", rc);
2918 setACLerrorExit:
2919 cifs_buf_release(pSMB);
2920 if (rc == -EAGAIN)
2921 goto setAclRetry;
2922 return rc;
2925 /* BB fix tabs in this function FIXME BB */
2927 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2928 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2930 int rc = 0;
2931 struct smb_t2_qfi_req *pSMB = NULL;
2932 struct smb_t2_qfi_rsp *pSMBr = NULL;
2933 int bytes_returned;
2934 __u16 params, byte_count;
2936 cFYI(1, "In GetExtAttr");
2937 if (tcon == NULL)
2938 return -ENODEV;
2940 GetExtAttrRetry:
2941 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2942 (void **) &pSMBr);
2943 if (rc)
2944 return rc;
2946 params = 2 /* level */ + 2 /* fid */;
2947 pSMB->t2.TotalDataCount = 0;
2948 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2949 /* BB find exact max data count below from sess structure BB */
2950 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2951 pSMB->t2.MaxSetupCount = 0;
2952 pSMB->t2.Reserved = 0;
2953 pSMB->t2.Flags = 0;
2954 pSMB->t2.Timeout = 0;
2955 pSMB->t2.Reserved2 = 0;
2956 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2957 Fid) - 4);
2958 pSMB->t2.DataCount = 0;
2959 pSMB->t2.DataOffset = 0;
2960 pSMB->t2.SetupCount = 1;
2961 pSMB->t2.Reserved3 = 0;
2962 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2963 byte_count = params + 1 /* pad */ ;
2964 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2965 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2966 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2967 pSMB->Pad = 0;
2968 pSMB->Fid = netfid;
2969 pSMB->hdr.smb_buf_length += byte_count;
2970 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2972 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2973 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2974 if (rc) {
2975 cFYI(1, "error %d in GetExtAttr", rc);
2976 } else {
2977 /* decode response */
2978 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2979 if (rc || (pSMBr->ByteCount < 2))
2980 /* BB also check enough total bytes returned */
2981 /* If rc should we check for EOPNOSUPP and
2982 disable the srvino flag? or in caller? */
2983 rc = -EIO; /* bad smb */
2984 else {
2985 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2986 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2987 struct file_chattr_info *pfinfo;
2988 /* BB Do we need a cast or hash here ? */
2989 if (count != 16) {
2990 cFYI(1, "Illegal size ret in GetExtAttr");
2991 rc = -EIO;
2992 goto GetExtAttrOut;
2994 pfinfo = (struct file_chattr_info *)
2995 (data_offset + (char *) &pSMBr->hdr.Protocol);
2996 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2997 *pMask = le64_to_cpu(pfinfo->mask);
3000 GetExtAttrOut:
3001 cifs_buf_release(pSMB);
3002 if (rc == -EAGAIN)
3003 goto GetExtAttrRetry;
3004 return rc;
3007 #endif /* CONFIG_POSIX */
3009 #ifdef CONFIG_CIFS_ACL
3011 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3012 * all NT TRANSACTS that we init here have total parm and data under about 400
3013 * bytes (to fit in small cifs buffer size), which is the case so far, it
3014 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3015 * returned setup area) and MaxParameterCount (returned parms size) must be set
3016 * by caller
3018 static int
3019 smb_init_nttransact(const __u16 sub_command, const int setup_count,
3020 const int parm_len, struct cifsTconInfo *tcon,
3021 void **ret_buf)
3023 int rc;
3024 __u32 temp_offset;
3025 struct smb_com_ntransact_req *pSMB;
3027 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3028 (void **)&pSMB);
3029 if (rc)
3030 return rc;
3031 *ret_buf = (void *)pSMB;
3032 pSMB->Reserved = 0;
3033 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3034 pSMB->TotalDataCount = 0;
3035 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3036 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3037 pSMB->ParameterCount = pSMB->TotalParameterCount;
3038 pSMB->DataCount = pSMB->TotalDataCount;
3039 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3040 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3041 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3042 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3043 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3044 pSMB->SubCommand = cpu_to_le16(sub_command);
3045 return 0;
3048 static int
3049 validate_ntransact(char *buf, char **ppparm, char **ppdata,
3050 __u32 *pparmlen, __u32 *pdatalen)
3052 char *end_of_smb;
3053 __u32 data_count, data_offset, parm_count, parm_offset;
3054 struct smb_com_ntransact_rsp *pSMBr;
3056 *pdatalen = 0;
3057 *pparmlen = 0;
3059 if (buf == NULL)
3060 return -EINVAL;
3062 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3064 /* ByteCount was converted from little endian in SendReceive */
3065 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
3066 (char *)&pSMBr->ByteCount;
3068 data_offset = le32_to_cpu(pSMBr->DataOffset);
3069 data_count = le32_to_cpu(pSMBr->DataCount);
3070 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3071 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3073 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3074 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3076 /* should we also check that parm and data areas do not overlap? */
3077 if (*ppparm > end_of_smb) {
3078 cFYI(1, "parms start after end of smb");
3079 return -EINVAL;
3080 } else if (parm_count + *ppparm > end_of_smb) {
3081 cFYI(1, "parm end after end of smb");
3082 return -EINVAL;
3083 } else if (*ppdata > end_of_smb) {
3084 cFYI(1, "data starts after end of smb");
3085 return -EINVAL;
3086 } else if (data_count + *ppdata > end_of_smb) {
3087 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3088 *ppdata, data_count, (data_count + *ppdata),
3089 end_of_smb, pSMBr);
3090 return -EINVAL;
3091 } else if (parm_count + data_count > pSMBr->ByteCount) {
3092 cFYI(1, "parm count and data count larger than SMB");
3093 return -EINVAL;
3095 *pdatalen = data_count;
3096 *pparmlen = parm_count;
3097 return 0;
3100 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3102 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3103 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3105 int rc = 0;
3106 int buf_type = 0;
3107 QUERY_SEC_DESC_REQ *pSMB;
3108 struct kvec iov[1];
3110 cFYI(1, "GetCifsACL");
3112 *pbuflen = 0;
3113 *acl_inf = NULL;
3115 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3116 8 /* parm len */, tcon, (void **) &pSMB);
3117 if (rc)
3118 return rc;
3120 pSMB->MaxParameterCount = cpu_to_le32(4);
3121 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3122 pSMB->MaxSetupCount = 0;
3123 pSMB->Fid = fid; /* file handle always le */
3124 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3125 CIFS_ACL_DACL);
3126 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3127 pSMB->hdr.smb_buf_length += 11;
3128 iov[0].iov_base = (char *)pSMB;
3129 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3131 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3133 cifs_stats_inc(&tcon->num_acl_get);
3134 if (rc) {
3135 cFYI(1, "Send error in QuerySecDesc = %d", rc);
3136 } else { /* decode response */
3137 __le32 *parm;
3138 __u32 parm_len;
3139 __u32 acl_len;
3140 struct smb_com_ntransact_rsp *pSMBr;
3141 char *pdata;
3143 /* validate_nttransact */
3144 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3145 &pdata, &parm_len, pbuflen);
3146 if (rc)
3147 goto qsec_out;
3148 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3150 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
3152 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3153 rc = -EIO; /* bad smb */
3154 *pbuflen = 0;
3155 goto qsec_out;
3158 /* BB check that data area is minimum length and as big as acl_len */
3160 acl_len = le32_to_cpu(*parm);
3161 if (acl_len != *pbuflen) {
3162 cERROR(1, "acl length %d does not match %d",
3163 acl_len, *pbuflen);
3164 if (*pbuflen > acl_len)
3165 *pbuflen = acl_len;
3168 /* check if buffer is big enough for the acl
3169 header followed by the smallest SID */
3170 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3171 (*pbuflen >= 64 * 1024)) {
3172 cERROR(1, "bad acl length %d", *pbuflen);
3173 rc = -EINVAL;
3174 *pbuflen = 0;
3175 } else {
3176 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3177 if (*acl_inf == NULL) {
3178 *pbuflen = 0;
3179 rc = -ENOMEM;
3181 memcpy(*acl_inf, pdata, *pbuflen);
3184 qsec_out:
3185 if (buf_type == CIFS_SMALL_BUFFER)
3186 cifs_small_buf_release(iov[0].iov_base);
3187 else if (buf_type == CIFS_LARGE_BUFFER)
3188 cifs_buf_release(iov[0].iov_base);
3189 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3190 return rc;
3194 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3195 struct cifs_ntsd *pntsd, __u32 acllen)
3197 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3198 int rc = 0;
3199 int bytes_returned = 0;
3200 SET_SEC_DESC_REQ *pSMB = NULL;
3201 NTRANSACT_RSP *pSMBr = NULL;
3203 setCifsAclRetry:
3204 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3205 (void **) &pSMBr);
3206 if (rc)
3207 return (rc);
3209 pSMB->MaxSetupCount = 0;
3210 pSMB->Reserved = 0;
3212 param_count = 8;
3213 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3214 data_count = acllen;
3215 data_offset = param_offset + param_count;
3216 byte_count = 3 /* pad */ + param_count;
3218 pSMB->DataCount = cpu_to_le32(data_count);
3219 pSMB->TotalDataCount = pSMB->DataCount;
3220 pSMB->MaxParameterCount = cpu_to_le32(4);
3221 pSMB->MaxDataCount = cpu_to_le32(16384);
3222 pSMB->ParameterCount = cpu_to_le32(param_count);
3223 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3224 pSMB->TotalParameterCount = pSMB->ParameterCount;
3225 pSMB->DataOffset = cpu_to_le32(data_offset);
3226 pSMB->SetupCount = 0;
3227 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3228 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3230 pSMB->Fid = fid; /* file handle always le */
3231 pSMB->Reserved2 = 0;
3232 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3234 if (pntsd && acllen) {
3235 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3236 (char *) pntsd,
3237 acllen);
3238 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3240 } else
3241 pSMB->hdr.smb_buf_length += byte_count;
3243 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3244 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3246 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
3247 if (rc)
3248 cFYI(1, "Set CIFS ACL returned %d", rc);
3249 cifs_buf_release(pSMB);
3251 if (rc == -EAGAIN)
3252 goto setCifsAclRetry;
3254 return (rc);
3257 #endif /* CONFIG_CIFS_ACL */
3259 /* Legacy Query Path Information call for lookup to old servers such
3260 as Win9x/WinME */
3261 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3262 const unsigned char *searchName,
3263 FILE_ALL_INFO *pFinfo,
3264 const struct nls_table *nls_codepage, int remap)
3266 QUERY_INFORMATION_REQ *pSMB;
3267 QUERY_INFORMATION_RSP *pSMBr;
3268 int rc = 0;
3269 int bytes_returned;
3270 int name_len;
3272 cFYI(1, "In SMBQPath path %s", searchName);
3273 QInfRetry:
3274 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3275 (void **) &pSMBr);
3276 if (rc)
3277 return rc;
3279 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3280 name_len =
3281 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3282 PATH_MAX, nls_codepage, remap);
3283 name_len++; /* trailing null */
3284 name_len *= 2;
3285 } else {
3286 name_len = strnlen(searchName, PATH_MAX);
3287 name_len++; /* trailing null */
3288 strncpy(pSMB->FileName, searchName, name_len);
3290 pSMB->BufferFormat = 0x04;
3291 name_len++; /* account for buffer type byte */
3292 pSMB->hdr.smb_buf_length += (__u16) name_len;
3293 pSMB->ByteCount = cpu_to_le16(name_len);
3295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3296 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3297 if (rc) {
3298 cFYI(1, "Send error in QueryInfo = %d", rc);
3299 } else if (pFinfo) {
3300 struct timespec ts;
3301 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3303 /* decode response */
3304 /* BB FIXME - add time zone adjustment BB */
3305 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3306 ts.tv_nsec = 0;
3307 ts.tv_sec = time;
3308 /* decode time fields */
3309 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3310 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3311 pFinfo->LastAccessTime = 0;
3312 pFinfo->AllocationSize =
3313 cpu_to_le64(le32_to_cpu(pSMBr->size));
3314 pFinfo->EndOfFile = pFinfo->AllocationSize;
3315 pFinfo->Attributes =
3316 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3317 } else
3318 rc = -EIO; /* bad buffer passed in */
3320 cifs_buf_release(pSMB);
3322 if (rc == -EAGAIN)
3323 goto QInfRetry;
3325 return rc;
3329 CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3330 u16 netfid, FILE_ALL_INFO *pFindData)
3332 struct smb_t2_qfi_req *pSMB = NULL;
3333 struct smb_t2_qfi_rsp *pSMBr = NULL;
3334 int rc = 0;
3335 int bytes_returned;
3336 __u16 params, byte_count;
3338 QFileInfoRetry:
3339 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3340 (void **) &pSMBr);
3341 if (rc)
3342 return rc;
3344 params = 2 /* level */ + 2 /* fid */;
3345 pSMB->t2.TotalDataCount = 0;
3346 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3347 /* BB find exact max data count below from sess structure BB */
3348 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3349 pSMB->t2.MaxSetupCount = 0;
3350 pSMB->t2.Reserved = 0;
3351 pSMB->t2.Flags = 0;
3352 pSMB->t2.Timeout = 0;
3353 pSMB->t2.Reserved2 = 0;
3354 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3355 Fid) - 4);
3356 pSMB->t2.DataCount = 0;
3357 pSMB->t2.DataOffset = 0;
3358 pSMB->t2.SetupCount = 1;
3359 pSMB->t2.Reserved3 = 0;
3360 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3361 byte_count = params + 1 /* pad */ ;
3362 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3363 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3364 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3365 pSMB->Pad = 0;
3366 pSMB->Fid = netfid;
3367 pSMB->hdr.smb_buf_length += byte_count;
3369 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3370 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3371 if (rc) {
3372 cFYI(1, "Send error in QPathInfo = %d", rc);
3373 } else { /* decode response */
3374 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3376 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3377 rc = -EIO;
3378 else if (pSMBr->ByteCount < 40)
3379 rc = -EIO; /* bad smb */
3380 else if (pFindData) {
3381 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3382 memcpy((char *) pFindData,
3383 (char *) &pSMBr->hdr.Protocol +
3384 data_offset, sizeof(FILE_ALL_INFO));
3385 } else
3386 rc = -ENOMEM;
3388 cifs_buf_release(pSMB);
3389 if (rc == -EAGAIN)
3390 goto QFileInfoRetry;
3392 return rc;
3396 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3397 const unsigned char *searchName,
3398 FILE_ALL_INFO *pFindData,
3399 int legacy /* old style infolevel */,
3400 const struct nls_table *nls_codepage, int remap)
3402 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3403 TRANSACTION2_QPI_REQ *pSMB = NULL;
3404 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3405 int rc = 0;
3406 int bytes_returned;
3407 int name_len;
3408 __u16 params, byte_count;
3410 /* cFYI(1, "In QPathInfo path %s", searchName); */
3411 QPathInfoRetry:
3412 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3413 (void **) &pSMBr);
3414 if (rc)
3415 return rc;
3417 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3418 name_len =
3419 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3420 PATH_MAX, nls_codepage, remap);
3421 name_len++; /* trailing null */
3422 name_len *= 2;
3423 } else { /* BB improve the check for buffer overruns BB */
3424 name_len = strnlen(searchName, PATH_MAX);
3425 name_len++; /* trailing null */
3426 strncpy(pSMB->FileName, searchName, name_len);
3429 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3430 pSMB->TotalDataCount = 0;
3431 pSMB->MaxParameterCount = cpu_to_le16(2);
3432 /* BB find exact max SMB PDU from sess structure BB */
3433 pSMB->MaxDataCount = cpu_to_le16(4000);
3434 pSMB->MaxSetupCount = 0;
3435 pSMB->Reserved = 0;
3436 pSMB->Flags = 0;
3437 pSMB->Timeout = 0;
3438 pSMB->Reserved2 = 0;
3439 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3440 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3441 pSMB->DataCount = 0;
3442 pSMB->DataOffset = 0;
3443 pSMB->SetupCount = 1;
3444 pSMB->Reserved3 = 0;
3445 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3446 byte_count = params + 1 /* pad */ ;
3447 pSMB->TotalParameterCount = cpu_to_le16(params);
3448 pSMB->ParameterCount = pSMB->TotalParameterCount;
3449 if (legacy)
3450 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3451 else
3452 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3453 pSMB->Reserved4 = 0;
3454 pSMB->hdr.smb_buf_length += byte_count;
3455 pSMB->ByteCount = cpu_to_le16(byte_count);
3457 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3458 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3459 if (rc) {
3460 cFYI(1, "Send error in QPathInfo = %d", rc);
3461 } else { /* decode response */
3462 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3464 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3465 rc = -EIO;
3466 else if (!legacy && (pSMBr->ByteCount < 40))
3467 rc = -EIO; /* bad smb */
3468 else if (legacy && (pSMBr->ByteCount < 24))
3469 rc = -EIO; /* 24 or 26 expected but we do not read
3470 last field */
3471 else if (pFindData) {
3472 int size;
3473 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3475 /* On legacy responses we do not read the last field,
3476 EAsize, fortunately since it varies by subdialect and
3477 also note it differs on Set vs. Get, ie two bytes or 4
3478 bytes depending but we don't care here */
3479 if (legacy)
3480 size = sizeof(FILE_INFO_STANDARD);
3481 else
3482 size = sizeof(FILE_ALL_INFO);
3483 memcpy((char *) pFindData,
3484 (char *) &pSMBr->hdr.Protocol +
3485 data_offset, size);
3486 } else
3487 rc = -ENOMEM;
3489 cifs_buf_release(pSMB);
3490 if (rc == -EAGAIN)
3491 goto QPathInfoRetry;
3493 return rc;
3497 CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3498 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3500 struct smb_t2_qfi_req *pSMB = NULL;
3501 struct smb_t2_qfi_rsp *pSMBr = NULL;
3502 int rc = 0;
3503 int bytes_returned;
3504 __u16 params, byte_count;
3506 UnixQFileInfoRetry:
3507 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3508 (void **) &pSMBr);
3509 if (rc)
3510 return rc;
3512 params = 2 /* level */ + 2 /* fid */;
3513 pSMB->t2.TotalDataCount = 0;
3514 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3515 /* BB find exact max data count below from sess structure BB */
3516 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3517 pSMB->t2.MaxSetupCount = 0;
3518 pSMB->t2.Reserved = 0;
3519 pSMB->t2.Flags = 0;
3520 pSMB->t2.Timeout = 0;
3521 pSMB->t2.Reserved2 = 0;
3522 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3523 Fid) - 4);
3524 pSMB->t2.DataCount = 0;
3525 pSMB->t2.DataOffset = 0;
3526 pSMB->t2.SetupCount = 1;
3527 pSMB->t2.Reserved3 = 0;
3528 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3529 byte_count = params + 1 /* pad */ ;
3530 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3531 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3532 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3533 pSMB->Pad = 0;
3534 pSMB->Fid = netfid;
3535 pSMB->hdr.smb_buf_length += byte_count;
3537 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3538 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3539 if (rc) {
3540 cFYI(1, "Send error in QPathInfo = %d", rc);
3541 } else { /* decode response */
3542 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3544 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3545 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
3546 "Unix Extensions can be disabled on mount "
3547 "by specifying the nosfu mount option.");
3548 rc = -EIO; /* bad smb */
3549 } else {
3550 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3551 memcpy((char *) pFindData,
3552 (char *) &pSMBr->hdr.Protocol +
3553 data_offset,
3554 sizeof(FILE_UNIX_BASIC_INFO));
3558 cifs_buf_release(pSMB);
3559 if (rc == -EAGAIN)
3560 goto UnixQFileInfoRetry;
3562 return rc;
3566 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3567 const unsigned char *searchName,
3568 FILE_UNIX_BASIC_INFO *pFindData,
3569 const struct nls_table *nls_codepage, int remap)
3571 /* SMB_QUERY_FILE_UNIX_BASIC */
3572 TRANSACTION2_QPI_REQ *pSMB = NULL;
3573 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3574 int rc = 0;
3575 int bytes_returned = 0;
3576 int name_len;
3577 __u16 params, byte_count;
3579 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
3580 UnixQPathInfoRetry:
3581 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3582 (void **) &pSMBr);
3583 if (rc)
3584 return rc;
3586 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3587 name_len =
3588 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3589 PATH_MAX, nls_codepage, remap);
3590 name_len++; /* trailing null */
3591 name_len *= 2;
3592 } else { /* BB improve the check for buffer overruns BB */
3593 name_len = strnlen(searchName, PATH_MAX);
3594 name_len++; /* trailing null */
3595 strncpy(pSMB->FileName, searchName, name_len);
3598 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3599 pSMB->TotalDataCount = 0;
3600 pSMB->MaxParameterCount = cpu_to_le16(2);
3601 /* BB find exact max SMB PDU from sess structure BB */
3602 pSMB->MaxDataCount = cpu_to_le16(4000);
3603 pSMB->MaxSetupCount = 0;
3604 pSMB->Reserved = 0;
3605 pSMB->Flags = 0;
3606 pSMB->Timeout = 0;
3607 pSMB->Reserved2 = 0;
3608 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3609 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3610 pSMB->DataCount = 0;
3611 pSMB->DataOffset = 0;
3612 pSMB->SetupCount = 1;
3613 pSMB->Reserved3 = 0;
3614 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3615 byte_count = params + 1 /* pad */ ;
3616 pSMB->TotalParameterCount = cpu_to_le16(params);
3617 pSMB->ParameterCount = pSMB->TotalParameterCount;
3618 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3619 pSMB->Reserved4 = 0;
3620 pSMB->hdr.smb_buf_length += byte_count;
3621 pSMB->ByteCount = cpu_to_le16(byte_count);
3623 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3624 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3625 if (rc) {
3626 cFYI(1, "Send error in QPathInfo = %d", rc);
3627 } else { /* decode response */
3628 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3630 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3631 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
3632 "Unix Extensions can be disabled on mount "
3633 "by specifying the nosfu mount option.");
3634 rc = -EIO; /* bad smb */
3635 } else {
3636 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3637 memcpy((char *) pFindData,
3638 (char *) &pSMBr->hdr.Protocol +
3639 data_offset,
3640 sizeof(FILE_UNIX_BASIC_INFO));
3643 cifs_buf_release(pSMB);
3644 if (rc == -EAGAIN)
3645 goto UnixQPathInfoRetry;
3647 return rc;
3650 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3652 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3653 const char *searchName,
3654 const struct nls_table *nls_codepage,
3655 __u16 *pnetfid,
3656 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3658 /* level 257 SMB_ */
3659 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3660 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3661 T2_FFIRST_RSP_PARMS *parms;
3662 int rc = 0;
3663 int bytes_returned = 0;
3664 int name_len;
3665 __u16 params, byte_count;
3667 cFYI(1, "In FindFirst for %s", searchName);
3669 findFirstRetry:
3670 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3671 (void **) &pSMBr);
3672 if (rc)
3673 return rc;
3675 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3676 name_len =
3677 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3678 PATH_MAX, nls_codepage, remap);
3679 /* We can not add the asterik earlier in case
3680 it got remapped to 0xF03A as if it were part of the
3681 directory name instead of a wildcard */
3682 name_len *= 2;
3683 pSMB->FileName[name_len] = dirsep;
3684 pSMB->FileName[name_len+1] = 0;
3685 pSMB->FileName[name_len+2] = '*';
3686 pSMB->FileName[name_len+3] = 0;
3687 name_len += 4; /* now the trailing null */
3688 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3689 pSMB->FileName[name_len+1] = 0;
3690 name_len += 2;
3691 } else { /* BB add check for overrun of SMB buf BB */
3692 name_len = strnlen(searchName, PATH_MAX);
3693 /* BB fix here and in unicode clause above ie
3694 if (name_len > buffersize-header)
3695 free buffer exit; BB */
3696 strncpy(pSMB->FileName, searchName, name_len);
3697 pSMB->FileName[name_len] = dirsep;
3698 pSMB->FileName[name_len+1] = '*';
3699 pSMB->FileName[name_len+2] = 0;
3700 name_len += 3;
3703 params = 12 + name_len /* includes null */ ;
3704 pSMB->TotalDataCount = 0; /* no EAs */
3705 pSMB->MaxParameterCount = cpu_to_le16(10);
3706 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3707 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3708 pSMB->MaxSetupCount = 0;
3709 pSMB->Reserved = 0;
3710 pSMB->Flags = 0;
3711 pSMB->Timeout = 0;
3712 pSMB->Reserved2 = 0;
3713 byte_count = params + 1 /* pad */ ;
3714 pSMB->TotalParameterCount = cpu_to_le16(params);
3715 pSMB->ParameterCount = pSMB->TotalParameterCount;
3716 pSMB->ParameterOffset = cpu_to_le16(
3717 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3718 - 4);
3719 pSMB->DataCount = 0;
3720 pSMB->DataOffset = 0;
3721 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3722 pSMB->Reserved3 = 0;
3723 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3724 pSMB->SearchAttributes =
3725 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3726 ATTR_DIRECTORY);
3727 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3728 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3729 CIFS_SEARCH_RETURN_RESUME);
3730 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3732 /* BB what should we set StorageType to? Does it matter? BB */
3733 pSMB->SearchStorageType = 0;
3734 pSMB->hdr.smb_buf_length += byte_count;
3735 pSMB->ByteCount = cpu_to_le16(byte_count);
3737 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3738 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3739 cifs_stats_inc(&tcon->num_ffirst);
3741 if (rc) {/* BB add logic to retry regular search if Unix search
3742 rejected unexpectedly by server */
3743 /* BB Add code to handle unsupported level rc */
3744 cFYI(1, "Error in FindFirst = %d", rc);
3746 cifs_buf_release(pSMB);
3748 /* BB eventually could optimize out free and realloc of buf */
3749 /* for this case */
3750 if (rc == -EAGAIN)
3751 goto findFirstRetry;
3752 } else { /* decode response */
3753 /* BB remember to free buffer if error BB */
3754 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3755 if (rc == 0) {
3756 unsigned int lnoff;
3758 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3759 psrch_inf->unicode = true;
3760 else
3761 psrch_inf->unicode = false;
3763 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3764 psrch_inf->smallBuf = 0;
3765 psrch_inf->srch_entries_start =
3766 (char *) &pSMBr->hdr.Protocol +
3767 le16_to_cpu(pSMBr->t2.DataOffset);
3768 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3769 le16_to_cpu(pSMBr->t2.ParameterOffset));
3771 if (parms->EndofSearch)
3772 psrch_inf->endOfSearch = true;
3773 else
3774 psrch_inf->endOfSearch = false;
3776 psrch_inf->entries_in_buffer =
3777 le16_to_cpu(parms->SearchCount);
3778 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3779 psrch_inf->entries_in_buffer;
3780 lnoff = le16_to_cpu(parms->LastNameOffset);
3781 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3782 lnoff) {
3783 cERROR(1, "ignoring corrupt resume name");
3784 psrch_inf->last_entry = NULL;
3785 return rc;
3788 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3789 lnoff;
3791 *pnetfid = parms->SearchHandle;
3792 } else {
3793 cifs_buf_release(pSMB);
3797 return rc;
3800 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3801 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3803 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3804 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3805 T2_FNEXT_RSP_PARMS *parms;
3806 char *response_data;
3807 int rc = 0;
3808 int bytes_returned, name_len;
3809 __u16 params, byte_count;
3811 cFYI(1, "In FindNext");
3813 if (psrch_inf->endOfSearch)
3814 return -ENOENT;
3816 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3817 (void **) &pSMBr);
3818 if (rc)
3819 return rc;
3821 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3822 byte_count = 0;
3823 pSMB->TotalDataCount = 0; /* no EAs */
3824 pSMB->MaxParameterCount = cpu_to_le16(8);
3825 pSMB->MaxDataCount =
3826 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3827 0xFFFFFF00);
3828 pSMB->MaxSetupCount = 0;
3829 pSMB->Reserved = 0;
3830 pSMB->Flags = 0;
3831 pSMB->Timeout = 0;
3832 pSMB->Reserved2 = 0;
3833 pSMB->ParameterOffset = cpu_to_le16(
3834 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3835 pSMB->DataCount = 0;
3836 pSMB->DataOffset = 0;
3837 pSMB->SetupCount = 1;
3838 pSMB->Reserved3 = 0;
3839 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3840 pSMB->SearchHandle = searchHandle; /* always kept as le */
3841 pSMB->SearchCount =
3842 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3843 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3844 pSMB->ResumeKey = psrch_inf->resume_key;
3845 pSMB->SearchFlags =
3846 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3848 name_len = psrch_inf->resume_name_len;
3849 params += name_len;
3850 if (name_len < PATH_MAX) {
3851 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3852 byte_count += name_len;
3853 /* 14 byte parm len above enough for 2 byte null terminator */
3854 pSMB->ResumeFileName[name_len] = 0;
3855 pSMB->ResumeFileName[name_len+1] = 0;
3856 } else {
3857 rc = -EINVAL;
3858 goto FNext2_err_exit;
3860 byte_count = params + 1 /* pad */ ;
3861 pSMB->TotalParameterCount = cpu_to_le16(params);
3862 pSMB->ParameterCount = pSMB->TotalParameterCount;
3863 pSMB->hdr.smb_buf_length += byte_count;
3864 pSMB->ByteCount = cpu_to_le16(byte_count);
3866 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3867 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3868 cifs_stats_inc(&tcon->num_fnext);
3869 if (rc) {
3870 if (rc == -EBADF) {
3871 psrch_inf->endOfSearch = true;
3872 cifs_buf_release(pSMB);
3873 rc = 0; /* search probably was closed at end of search*/
3874 } else
3875 cFYI(1, "FindNext returned = %d", rc);
3876 } else { /* decode response */
3877 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3879 if (rc == 0) {
3880 unsigned int lnoff;
3882 /* BB fixme add lock for file (srch_info) struct here */
3883 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3884 psrch_inf->unicode = true;
3885 else
3886 psrch_inf->unicode = false;
3887 response_data = (char *) &pSMBr->hdr.Protocol +
3888 le16_to_cpu(pSMBr->t2.ParameterOffset);
3889 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3890 response_data = (char *)&pSMBr->hdr.Protocol +
3891 le16_to_cpu(pSMBr->t2.DataOffset);
3892 if (psrch_inf->smallBuf)
3893 cifs_small_buf_release(
3894 psrch_inf->ntwrk_buf_start);
3895 else
3896 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3897 psrch_inf->srch_entries_start = response_data;
3898 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3899 psrch_inf->smallBuf = 0;
3900 if (parms->EndofSearch)
3901 psrch_inf->endOfSearch = true;
3902 else
3903 psrch_inf->endOfSearch = false;
3904 psrch_inf->entries_in_buffer =
3905 le16_to_cpu(parms->SearchCount);
3906 psrch_inf->index_of_last_entry +=
3907 psrch_inf->entries_in_buffer;
3908 lnoff = le16_to_cpu(parms->LastNameOffset);
3909 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3910 lnoff) {
3911 cERROR(1, "ignoring corrupt resume name");
3912 psrch_inf->last_entry = NULL;
3913 return rc;
3914 } else
3915 psrch_inf->last_entry =
3916 psrch_inf->srch_entries_start + lnoff;
3918 /* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3919 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
3921 /* BB fixme add unlock here */
3926 /* BB On error, should we leave previous search buf (and count and
3927 last entry fields) intact or free the previous one? */
3929 /* Note: On -EAGAIN error only caller can retry on handle based calls
3930 since file handle passed in no longer valid */
3931 FNext2_err_exit:
3932 if (rc != 0)
3933 cifs_buf_release(pSMB);
3934 return rc;
3938 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3939 const __u16 searchHandle)
3941 int rc = 0;
3942 FINDCLOSE_REQ *pSMB = NULL;
3944 cFYI(1, "In CIFSSMBFindClose");
3945 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3947 /* no sense returning error if session restarted
3948 as file handle has been closed */
3949 if (rc == -EAGAIN)
3950 return 0;
3951 if (rc)
3952 return rc;
3954 pSMB->FileID = searchHandle;
3955 pSMB->ByteCount = 0;
3956 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3957 if (rc)
3958 cERROR(1, "Send error in FindClose = %d", rc);
3960 cifs_stats_inc(&tcon->num_fclose);
3962 /* Since session is dead, search handle closed on server already */
3963 if (rc == -EAGAIN)
3964 rc = 0;
3966 return rc;
3970 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3971 const unsigned char *searchName,
3972 __u64 *inode_number,
3973 const struct nls_table *nls_codepage, int remap)
3975 int rc = 0;
3976 TRANSACTION2_QPI_REQ *pSMB = NULL;
3977 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3978 int name_len, bytes_returned;
3979 __u16 params, byte_count;
3981 cFYI(1, "In GetSrvInodeNum for %s", searchName);
3982 if (tcon == NULL)
3983 return -ENODEV;
3985 GetInodeNumberRetry:
3986 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3987 (void **) &pSMBr);
3988 if (rc)
3989 return rc;
3991 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3992 name_len =
3993 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3994 PATH_MAX, nls_codepage, remap);
3995 name_len++; /* trailing null */
3996 name_len *= 2;
3997 } else { /* BB improve the check for buffer overruns BB */
3998 name_len = strnlen(searchName, PATH_MAX);
3999 name_len++; /* trailing null */
4000 strncpy(pSMB->FileName, searchName, name_len);
4003 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4004 pSMB->TotalDataCount = 0;
4005 pSMB->MaxParameterCount = cpu_to_le16(2);
4006 /* BB find exact max data count below from sess structure BB */
4007 pSMB->MaxDataCount = cpu_to_le16(4000);
4008 pSMB->MaxSetupCount = 0;
4009 pSMB->Reserved = 0;
4010 pSMB->Flags = 0;
4011 pSMB->Timeout = 0;
4012 pSMB->Reserved2 = 0;
4013 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4014 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4015 pSMB->DataCount = 0;
4016 pSMB->DataOffset = 0;
4017 pSMB->SetupCount = 1;
4018 pSMB->Reserved3 = 0;
4019 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4020 byte_count = params + 1 /* pad */ ;
4021 pSMB->TotalParameterCount = cpu_to_le16(params);
4022 pSMB->ParameterCount = pSMB->TotalParameterCount;
4023 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4024 pSMB->Reserved4 = 0;
4025 pSMB->hdr.smb_buf_length += byte_count;
4026 pSMB->ByteCount = cpu_to_le16(byte_count);
4028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4030 if (rc) {
4031 cFYI(1, "error %d in QueryInternalInfo", rc);
4032 } else {
4033 /* decode response */
4034 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4035 if (rc || (pSMBr->ByteCount < 2))
4036 /* BB also check enough total bytes returned */
4037 /* If rc should we check for EOPNOSUPP and
4038 disable the srvino flag? or in caller? */
4039 rc = -EIO; /* bad smb */
4040 else {
4041 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4042 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
4043 struct file_internal_info *pfinfo;
4044 /* BB Do we need a cast or hash here ? */
4045 if (count < 8) {
4046 cFYI(1, "Illegal size ret in QryIntrnlInf");
4047 rc = -EIO;
4048 goto GetInodeNumOut;
4050 pfinfo = (struct file_internal_info *)
4051 (data_offset + (char *) &pSMBr->hdr.Protocol);
4052 *inode_number = le64_to_cpu(pfinfo->UniqueId);
4055 GetInodeNumOut:
4056 cifs_buf_release(pSMB);
4057 if (rc == -EAGAIN)
4058 goto GetInodeNumberRetry;
4059 return rc;
4062 /* parses DFS refferal V3 structure
4063 * caller is responsible for freeing target_nodes
4064 * returns:
4065 * on success - 0
4066 * on failure - errno
4068 static int
4069 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
4070 unsigned int *num_of_nodes,
4071 struct dfs_info3_param **target_nodes,
4072 const struct nls_table *nls_codepage, int remap,
4073 const char *searchName)
4075 int i, rc = 0;
4076 char *data_end;
4077 bool is_unicode;
4078 struct dfs_referral_level_3 *ref;
4080 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4081 is_unicode = true;
4082 else
4083 is_unicode = false;
4084 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4086 if (*num_of_nodes < 1) {
4087 cERROR(1, "num_referrals: must be at least > 0,"
4088 "but we get num_referrals = %d\n", *num_of_nodes);
4089 rc = -EINVAL;
4090 goto parse_DFS_referrals_exit;
4093 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
4094 if (ref->VersionNumber != cpu_to_le16(3)) {
4095 cERROR(1, "Referrals of V%d version are not supported,"
4096 "should be V3", le16_to_cpu(ref->VersionNumber));
4097 rc = -EINVAL;
4098 goto parse_DFS_referrals_exit;
4101 /* get the upper boundary of the resp buffer */
4102 data_end = (char *)(&(pSMBr->PathConsumed)) +
4103 le16_to_cpu(pSMBr->t2.DataCount);
4105 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
4106 *num_of_nodes,
4107 le32_to_cpu(pSMBr->DFSFlags));
4109 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4110 *num_of_nodes, GFP_KERNEL);
4111 if (*target_nodes == NULL) {
4112 cERROR(1, "Failed to allocate buffer for target_nodes\n");
4113 rc = -ENOMEM;
4114 goto parse_DFS_referrals_exit;
4117 /* collect necessary data from referrals */
4118 for (i = 0; i < *num_of_nodes; i++) {
4119 char *temp;
4120 int max_len;
4121 struct dfs_info3_param *node = (*target_nodes)+i;
4123 node->flags = le32_to_cpu(pSMBr->DFSFlags);
4124 if (is_unicode) {
4125 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4126 GFP_KERNEL);
4127 if (tmp == NULL) {
4128 rc = -ENOMEM;
4129 goto parse_DFS_referrals_exit;
4131 cifsConvertToUCS((__le16 *) tmp, searchName,
4132 PATH_MAX, nls_codepage, remap);
4133 node->path_consumed = cifs_ucs2_bytes(tmp,
4134 le16_to_cpu(pSMBr->PathConsumed),
4135 nls_codepage);
4136 kfree(tmp);
4137 } else
4138 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4140 node->server_type = le16_to_cpu(ref->ServerType);
4141 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4143 /* copy DfsPath */
4144 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4145 max_len = data_end - temp;
4146 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4147 is_unicode, nls_codepage);
4148 if (!node->path_name) {
4149 rc = -ENOMEM;
4150 goto parse_DFS_referrals_exit;
4153 /* copy link target UNC */
4154 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4155 max_len = data_end - temp;
4156 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4157 is_unicode, nls_codepage);
4158 if (!node->node_name)
4159 rc = -ENOMEM;
4162 parse_DFS_referrals_exit:
4163 if (rc) {
4164 free_dfs_info_array(*target_nodes, *num_of_nodes);
4165 *target_nodes = NULL;
4166 *num_of_nodes = 0;
4168 return rc;
4172 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4173 const unsigned char *searchName,
4174 struct dfs_info3_param **target_nodes,
4175 unsigned int *num_of_nodes,
4176 const struct nls_table *nls_codepage, int remap)
4178 /* TRANS2_GET_DFS_REFERRAL */
4179 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4180 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4181 int rc = 0;
4182 int bytes_returned;
4183 int name_len;
4184 __u16 params, byte_count;
4185 *num_of_nodes = 0;
4186 *target_nodes = NULL;
4188 cFYI(1, "In GetDFSRefer the path %s", searchName);
4189 if (ses == NULL)
4190 return -ENODEV;
4191 getDFSRetry:
4192 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4193 (void **) &pSMBr);
4194 if (rc)
4195 return rc;
4197 /* server pointer checked in called function,
4198 but should never be null here anyway */
4199 pSMB->hdr.Mid = GetNextMid(ses->server);
4200 pSMB->hdr.Tid = ses->ipc_tid;
4201 pSMB->hdr.Uid = ses->Suid;
4202 if (ses->capabilities & CAP_STATUS32)
4203 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4204 if (ses->capabilities & CAP_DFS)
4205 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4207 if (ses->capabilities & CAP_UNICODE) {
4208 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4209 name_len =
4210 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4211 searchName, PATH_MAX, nls_codepage, remap);
4212 name_len++; /* trailing null */
4213 name_len *= 2;
4214 } else { /* BB improve the check for buffer overruns BB */
4215 name_len = strnlen(searchName, PATH_MAX);
4216 name_len++; /* trailing null */
4217 strncpy(pSMB->RequestFileName, searchName, name_len);
4220 if (ses->server) {
4221 if (ses->server->secMode &
4222 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4223 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4226 pSMB->hdr.Uid = ses->Suid;
4228 params = 2 /* level */ + name_len /*includes null */ ;
4229 pSMB->TotalDataCount = 0;
4230 pSMB->DataCount = 0;
4231 pSMB->DataOffset = 0;
4232 pSMB->MaxParameterCount = 0;
4233 /* BB find exact max SMB PDU from sess structure BB */
4234 pSMB->MaxDataCount = cpu_to_le16(4000);
4235 pSMB->MaxSetupCount = 0;
4236 pSMB->Reserved = 0;
4237 pSMB->Flags = 0;
4238 pSMB->Timeout = 0;
4239 pSMB->Reserved2 = 0;
4240 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4241 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4242 pSMB->SetupCount = 1;
4243 pSMB->Reserved3 = 0;
4244 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4245 byte_count = params + 3 /* pad */ ;
4246 pSMB->ParameterCount = cpu_to_le16(params);
4247 pSMB->TotalParameterCount = pSMB->ParameterCount;
4248 pSMB->MaxReferralLevel = cpu_to_le16(3);
4249 pSMB->hdr.smb_buf_length += byte_count;
4250 pSMB->ByteCount = cpu_to_le16(byte_count);
4252 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4253 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4254 if (rc) {
4255 cFYI(1, "Send error in GetDFSRefer = %d", rc);
4256 goto GetDFSRefExit;
4258 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4260 /* BB Also check if enough total bytes returned? */
4261 if (rc || (pSMBr->ByteCount < 17)) {
4262 rc = -EIO; /* bad smb */
4263 goto GetDFSRefExit;
4266 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
4267 pSMBr->ByteCount,
4268 le16_to_cpu(pSMBr->t2.DataOffset));
4270 /* parse returned result into more usable form */
4271 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4272 target_nodes, nls_codepage, remap,
4273 searchName);
4275 GetDFSRefExit:
4276 cifs_buf_release(pSMB);
4278 if (rc == -EAGAIN)
4279 goto getDFSRetry;
4281 return rc;
4284 /* Query File System Info such as free space to old servers such as Win 9x */
4286 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4288 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4289 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4290 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4291 FILE_SYSTEM_ALLOC_INFO *response_data;
4292 int rc = 0;
4293 int bytes_returned = 0;
4294 __u16 params, byte_count;
4296 cFYI(1, "OldQFSInfo");
4297 oldQFSInfoRetry:
4298 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4299 (void **) &pSMBr);
4300 if (rc)
4301 return rc;
4303 params = 2; /* level */
4304 pSMB->TotalDataCount = 0;
4305 pSMB->MaxParameterCount = cpu_to_le16(2);
4306 pSMB->MaxDataCount = cpu_to_le16(1000);
4307 pSMB->MaxSetupCount = 0;
4308 pSMB->Reserved = 0;
4309 pSMB->Flags = 0;
4310 pSMB->Timeout = 0;
4311 pSMB->Reserved2 = 0;
4312 byte_count = params + 1 /* pad */ ;
4313 pSMB->TotalParameterCount = cpu_to_le16(params);
4314 pSMB->ParameterCount = pSMB->TotalParameterCount;
4315 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4316 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4317 pSMB->DataCount = 0;
4318 pSMB->DataOffset = 0;
4319 pSMB->SetupCount = 1;
4320 pSMB->Reserved3 = 0;
4321 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4322 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4323 pSMB->hdr.smb_buf_length += byte_count;
4324 pSMB->ByteCount = cpu_to_le16(byte_count);
4326 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4327 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4328 if (rc) {
4329 cFYI(1, "Send error in QFSInfo = %d", rc);
4330 } else { /* decode response */
4331 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4333 if (rc || (pSMBr->ByteCount < 18))
4334 rc = -EIO; /* bad smb */
4335 else {
4336 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4337 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4338 pSMBr->ByteCount, data_offset);
4340 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4341 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4342 FSData->f_bsize =
4343 le16_to_cpu(response_data->BytesPerSector) *
4344 le32_to_cpu(response_data->
4345 SectorsPerAllocationUnit);
4346 FSData->f_blocks =
4347 le32_to_cpu(response_data->TotalAllocationUnits);
4348 FSData->f_bfree = FSData->f_bavail =
4349 le32_to_cpu(response_data->FreeAllocationUnits);
4350 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4351 (unsigned long long)FSData->f_blocks,
4352 (unsigned long long)FSData->f_bfree,
4353 FSData->f_bsize);
4356 cifs_buf_release(pSMB);
4358 if (rc == -EAGAIN)
4359 goto oldQFSInfoRetry;
4361 return rc;
4365 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4367 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4368 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4369 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4370 FILE_SYSTEM_INFO *response_data;
4371 int rc = 0;
4372 int bytes_returned = 0;
4373 __u16 params, byte_count;
4375 cFYI(1, "In QFSInfo");
4376 QFSInfoRetry:
4377 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4378 (void **) &pSMBr);
4379 if (rc)
4380 return rc;
4382 params = 2; /* level */
4383 pSMB->TotalDataCount = 0;
4384 pSMB->MaxParameterCount = cpu_to_le16(2);
4385 pSMB->MaxDataCount = cpu_to_le16(1000);
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(offsetof(
4395 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4396 pSMB->DataCount = 0;
4397 pSMB->DataOffset = 0;
4398 pSMB->SetupCount = 1;
4399 pSMB->Reserved3 = 0;
4400 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4401 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4402 pSMB->hdr.smb_buf_length += byte_count;
4403 pSMB->ByteCount = cpu_to_le16(byte_count);
4405 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4406 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4407 if (rc) {
4408 cFYI(1, "Send error in QFSInfo = %d", rc);
4409 } else { /* decode response */
4410 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4412 if (rc || (pSMBr->ByteCount < 24))
4413 rc = -EIO; /* bad smb */
4414 else {
4415 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4417 response_data =
4418 (FILE_SYSTEM_INFO
4419 *) (((char *) &pSMBr->hdr.Protocol) +
4420 data_offset);
4421 FSData->f_bsize =
4422 le32_to_cpu(response_data->BytesPerSector) *
4423 le32_to_cpu(response_data->
4424 SectorsPerAllocationUnit);
4425 FSData->f_blocks =
4426 le64_to_cpu(response_data->TotalAllocationUnits);
4427 FSData->f_bfree = FSData->f_bavail =
4428 le64_to_cpu(response_data->FreeAllocationUnits);
4429 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4430 (unsigned long long)FSData->f_blocks,
4431 (unsigned long long)FSData->f_bfree,
4432 FSData->f_bsize);
4435 cifs_buf_release(pSMB);
4437 if (rc == -EAGAIN)
4438 goto QFSInfoRetry;
4440 return rc;
4444 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4446 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4447 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4448 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4449 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4450 int rc = 0;
4451 int bytes_returned = 0;
4452 __u16 params, byte_count;
4454 cFYI(1, "In QFSAttributeInfo");
4455 QFSAttributeRetry:
4456 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4457 (void **) &pSMBr);
4458 if (rc)
4459 return rc;
4461 params = 2; /* level */
4462 pSMB->TotalDataCount = 0;
4463 pSMB->MaxParameterCount = cpu_to_le16(2);
4464 /* BB find exact max SMB PDU from sess structure BB */
4465 pSMB->MaxDataCount = cpu_to_le16(1000);
4466 pSMB->MaxSetupCount = 0;
4467 pSMB->Reserved = 0;
4468 pSMB->Flags = 0;
4469 pSMB->Timeout = 0;
4470 pSMB->Reserved2 = 0;
4471 byte_count = params + 1 /* pad */ ;
4472 pSMB->TotalParameterCount = cpu_to_le16(params);
4473 pSMB->ParameterCount = pSMB->TotalParameterCount;
4474 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4475 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4476 pSMB->DataCount = 0;
4477 pSMB->DataOffset = 0;
4478 pSMB->SetupCount = 1;
4479 pSMB->Reserved3 = 0;
4480 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4481 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4482 pSMB->hdr.smb_buf_length += byte_count;
4483 pSMB->ByteCount = cpu_to_le16(byte_count);
4485 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4486 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4487 if (rc) {
4488 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
4489 } else { /* decode response */
4490 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4492 if (rc || (pSMBr->ByteCount < 13)) {
4493 /* BB also check if enough bytes returned */
4494 rc = -EIO; /* bad smb */
4495 } else {
4496 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4497 response_data =
4498 (FILE_SYSTEM_ATTRIBUTE_INFO
4499 *) (((char *) &pSMBr->hdr.Protocol) +
4500 data_offset);
4501 memcpy(&tcon->fsAttrInfo, response_data,
4502 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4505 cifs_buf_release(pSMB);
4507 if (rc == -EAGAIN)
4508 goto QFSAttributeRetry;
4510 return rc;
4514 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4516 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4517 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4518 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4519 FILE_SYSTEM_DEVICE_INFO *response_data;
4520 int rc = 0;
4521 int bytes_returned = 0;
4522 __u16 params, byte_count;
4524 cFYI(1, "In QFSDeviceInfo");
4525 QFSDeviceRetry:
4526 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4527 (void **) &pSMBr);
4528 if (rc)
4529 return rc;
4531 params = 2; /* level */
4532 pSMB->TotalDataCount = 0;
4533 pSMB->MaxParameterCount = cpu_to_le16(2);
4534 /* BB find exact max SMB PDU from sess structure BB */
4535 pSMB->MaxDataCount = cpu_to_le16(1000);
4536 pSMB->MaxSetupCount = 0;
4537 pSMB->Reserved = 0;
4538 pSMB->Flags = 0;
4539 pSMB->Timeout = 0;
4540 pSMB->Reserved2 = 0;
4541 byte_count = params + 1 /* pad */ ;
4542 pSMB->TotalParameterCount = cpu_to_le16(params);
4543 pSMB->ParameterCount = pSMB->TotalParameterCount;
4544 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4545 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4547 pSMB->DataCount = 0;
4548 pSMB->DataOffset = 0;
4549 pSMB->SetupCount = 1;
4550 pSMB->Reserved3 = 0;
4551 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4552 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4553 pSMB->hdr.smb_buf_length += byte_count;
4554 pSMB->ByteCount = cpu_to_le16(byte_count);
4556 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4557 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4558 if (rc) {
4559 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
4560 } else { /* decode response */
4561 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4563 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4564 rc = -EIO; /* bad smb */
4565 else {
4566 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4567 response_data =
4568 (FILE_SYSTEM_DEVICE_INFO *)
4569 (((char *) &pSMBr->hdr.Protocol) +
4570 data_offset);
4571 memcpy(&tcon->fsDevInfo, response_data,
4572 sizeof(FILE_SYSTEM_DEVICE_INFO));
4575 cifs_buf_release(pSMB);
4577 if (rc == -EAGAIN)
4578 goto QFSDeviceRetry;
4580 return rc;
4584 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4586 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4587 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4588 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4589 FILE_SYSTEM_UNIX_INFO *response_data;
4590 int rc = 0;
4591 int bytes_returned = 0;
4592 __u16 params, byte_count;
4594 cFYI(1, "In QFSUnixInfo");
4595 QFSUnixRetry:
4596 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4597 (void **) &pSMB, (void **) &pSMBr);
4598 if (rc)
4599 return rc;
4601 params = 2; /* level */
4602 pSMB->TotalDataCount = 0;
4603 pSMB->DataCount = 0;
4604 pSMB->DataOffset = 0;
4605 pSMB->MaxParameterCount = cpu_to_le16(2);
4606 /* BB find exact max SMB PDU from sess structure BB */
4607 pSMB->MaxDataCount = cpu_to_le16(100);
4608 pSMB->MaxSetupCount = 0;
4609 pSMB->Reserved = 0;
4610 pSMB->Flags = 0;
4611 pSMB->Timeout = 0;
4612 pSMB->Reserved2 = 0;
4613 byte_count = params + 1 /* pad */ ;
4614 pSMB->ParameterCount = cpu_to_le16(params);
4615 pSMB->TotalParameterCount = pSMB->ParameterCount;
4616 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4617 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4618 pSMB->SetupCount = 1;
4619 pSMB->Reserved3 = 0;
4620 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4621 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4622 pSMB->hdr.smb_buf_length += byte_count;
4623 pSMB->ByteCount = cpu_to_le16(byte_count);
4625 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4626 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4627 if (rc) {
4628 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
4629 } else { /* decode response */
4630 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4632 if (rc || (pSMBr->ByteCount < 13)) {
4633 rc = -EIO; /* bad smb */
4634 } else {
4635 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4636 response_data =
4637 (FILE_SYSTEM_UNIX_INFO
4638 *) (((char *) &pSMBr->hdr.Protocol) +
4639 data_offset);
4640 memcpy(&tcon->fsUnixInfo, response_data,
4641 sizeof(FILE_SYSTEM_UNIX_INFO));
4644 cifs_buf_release(pSMB);
4646 if (rc == -EAGAIN)
4647 goto QFSUnixRetry;
4650 return rc;
4654 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4656 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4657 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4658 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4659 int rc = 0;
4660 int bytes_returned = 0;
4661 __u16 params, param_offset, offset, byte_count;
4663 cFYI(1, "In SETFSUnixInfo");
4664 SETFSUnixRetry:
4665 /* BB switch to small buf init to save memory */
4666 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4667 (void **) &pSMB, (void **) &pSMBr);
4668 if (rc)
4669 return rc;
4671 params = 4; /* 2 bytes zero followed by info level. */
4672 pSMB->MaxSetupCount = 0;
4673 pSMB->Reserved = 0;
4674 pSMB->Flags = 0;
4675 pSMB->Timeout = 0;
4676 pSMB->Reserved2 = 0;
4677 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4678 - 4;
4679 offset = param_offset + params;
4681 pSMB->MaxParameterCount = cpu_to_le16(4);
4682 /* BB find exact max SMB PDU from sess structure BB */
4683 pSMB->MaxDataCount = cpu_to_le16(100);
4684 pSMB->SetupCount = 1;
4685 pSMB->Reserved3 = 0;
4686 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4687 byte_count = 1 /* pad */ + params + 12;
4689 pSMB->DataCount = cpu_to_le16(12);
4690 pSMB->ParameterCount = cpu_to_le16(params);
4691 pSMB->TotalDataCount = pSMB->DataCount;
4692 pSMB->TotalParameterCount = pSMB->ParameterCount;
4693 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4694 pSMB->DataOffset = cpu_to_le16(offset);
4696 /* Params. */
4697 pSMB->FileNum = 0;
4698 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4700 /* Data. */
4701 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4702 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4703 pSMB->ClientUnixCap = cpu_to_le64(cap);
4705 pSMB->hdr.smb_buf_length += byte_count;
4706 pSMB->ByteCount = cpu_to_le16(byte_count);
4708 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4709 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4710 if (rc) {
4711 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
4712 } else { /* decode response */
4713 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4714 if (rc)
4715 rc = -EIO; /* bad smb */
4717 cifs_buf_release(pSMB);
4719 if (rc == -EAGAIN)
4720 goto SETFSUnixRetry;
4722 return rc;
4728 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4729 struct kstatfs *FSData)
4731 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4732 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4733 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4734 FILE_SYSTEM_POSIX_INFO *response_data;
4735 int rc = 0;
4736 int bytes_returned = 0;
4737 __u16 params, byte_count;
4739 cFYI(1, "In QFSPosixInfo");
4740 QFSPosixRetry:
4741 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4742 (void **) &pSMBr);
4743 if (rc)
4744 return rc;
4746 params = 2; /* level */
4747 pSMB->TotalDataCount = 0;
4748 pSMB->DataCount = 0;
4749 pSMB->DataOffset = 0;
4750 pSMB->MaxParameterCount = cpu_to_le16(2);
4751 /* BB find exact max SMB PDU from sess structure BB */
4752 pSMB->MaxDataCount = cpu_to_le16(100);
4753 pSMB->MaxSetupCount = 0;
4754 pSMB->Reserved = 0;
4755 pSMB->Flags = 0;
4756 pSMB->Timeout = 0;
4757 pSMB->Reserved2 = 0;
4758 byte_count = params + 1 /* pad */ ;
4759 pSMB->ParameterCount = cpu_to_le16(params);
4760 pSMB->TotalParameterCount = pSMB->ParameterCount;
4761 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4762 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4763 pSMB->SetupCount = 1;
4764 pSMB->Reserved3 = 0;
4765 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4766 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4767 pSMB->hdr.smb_buf_length += byte_count;
4768 pSMB->ByteCount = cpu_to_le16(byte_count);
4770 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4771 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4772 if (rc) {
4773 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
4774 } else { /* decode response */
4775 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4777 if (rc || (pSMBr->ByteCount < 13)) {
4778 rc = -EIO; /* bad smb */
4779 } else {
4780 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4781 response_data =
4782 (FILE_SYSTEM_POSIX_INFO
4783 *) (((char *) &pSMBr->hdr.Protocol) +
4784 data_offset);
4785 FSData->f_bsize =
4786 le32_to_cpu(response_data->BlockSize);
4787 FSData->f_blocks =
4788 le64_to_cpu(response_data->TotalBlocks);
4789 FSData->f_bfree =
4790 le64_to_cpu(response_data->BlocksAvail);
4791 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4792 FSData->f_bavail = FSData->f_bfree;
4793 } else {
4794 FSData->f_bavail =
4795 le64_to_cpu(response_data->UserBlocksAvail);
4797 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4798 FSData->f_files =
4799 le64_to_cpu(response_data->TotalFileNodes);
4800 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4801 FSData->f_ffree =
4802 le64_to_cpu(response_data->FreeFileNodes);
4805 cifs_buf_release(pSMB);
4807 if (rc == -EAGAIN)
4808 goto QFSPosixRetry;
4810 return rc;
4814 /* We can not use write of zero bytes trick to
4815 set file size due to need for large file support. Also note that
4816 this SetPathInfo is preferred to SetFileInfo based method in next
4817 routine which is only needed to work around a sharing violation bug
4818 in Samba which this routine can run into */
4821 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4822 __u64 size, bool SetAllocation,
4823 const struct nls_table *nls_codepage, int remap)
4825 struct smb_com_transaction2_spi_req *pSMB = NULL;
4826 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4827 struct file_end_of_file_info *parm_data;
4828 int name_len;
4829 int rc = 0;
4830 int bytes_returned = 0;
4831 __u16 params, byte_count, data_count, param_offset, offset;
4833 cFYI(1, "In SetEOF");
4834 SetEOFRetry:
4835 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4836 (void **) &pSMBr);
4837 if (rc)
4838 return rc;
4840 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4841 name_len =
4842 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4843 PATH_MAX, nls_codepage, remap);
4844 name_len++; /* trailing null */
4845 name_len *= 2;
4846 } else { /* BB improve the check for buffer overruns BB */
4847 name_len = strnlen(fileName, PATH_MAX);
4848 name_len++; /* trailing null */
4849 strncpy(pSMB->FileName, fileName, name_len);
4851 params = 6 + name_len;
4852 data_count = sizeof(struct file_end_of_file_info);
4853 pSMB->MaxParameterCount = cpu_to_le16(2);
4854 pSMB->MaxDataCount = cpu_to_le16(4100);
4855 pSMB->MaxSetupCount = 0;
4856 pSMB->Reserved = 0;
4857 pSMB->Flags = 0;
4858 pSMB->Timeout = 0;
4859 pSMB->Reserved2 = 0;
4860 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4861 InformationLevel) - 4;
4862 offset = param_offset + params;
4863 if (SetAllocation) {
4864 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4865 pSMB->InformationLevel =
4866 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4867 else
4868 pSMB->InformationLevel =
4869 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4870 } else /* Set File Size */ {
4871 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4872 pSMB->InformationLevel =
4873 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4874 else
4875 pSMB->InformationLevel =
4876 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4879 parm_data =
4880 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4881 offset);
4882 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4883 pSMB->DataOffset = cpu_to_le16(offset);
4884 pSMB->SetupCount = 1;
4885 pSMB->Reserved3 = 0;
4886 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4887 byte_count = 3 /* pad */ + params + data_count;
4888 pSMB->DataCount = cpu_to_le16(data_count);
4889 pSMB->TotalDataCount = pSMB->DataCount;
4890 pSMB->ParameterCount = cpu_to_le16(params);
4891 pSMB->TotalParameterCount = pSMB->ParameterCount;
4892 pSMB->Reserved4 = 0;
4893 pSMB->hdr.smb_buf_length += byte_count;
4894 parm_data->FileSize = cpu_to_le64(size);
4895 pSMB->ByteCount = cpu_to_le16(byte_count);
4896 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4897 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4898 if (rc)
4899 cFYI(1, "SetPathInfo (file size) returned %d", rc);
4901 cifs_buf_release(pSMB);
4903 if (rc == -EAGAIN)
4904 goto SetEOFRetry;
4906 return rc;
4910 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4911 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4913 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4914 struct file_end_of_file_info *parm_data;
4915 int rc = 0;
4916 __u16 params, param_offset, offset, byte_count, count;
4918 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4919 (long long)size);
4920 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4922 if (rc)
4923 return rc;
4925 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4926 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4928 params = 6;
4929 pSMB->MaxSetupCount = 0;
4930 pSMB->Reserved = 0;
4931 pSMB->Flags = 0;
4932 pSMB->Timeout = 0;
4933 pSMB->Reserved2 = 0;
4934 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4935 offset = param_offset + params;
4937 count = sizeof(struct file_end_of_file_info);
4938 pSMB->MaxParameterCount = cpu_to_le16(2);
4939 /* BB find exact max SMB PDU from sess structure BB */
4940 pSMB->MaxDataCount = cpu_to_le16(1000);
4941 pSMB->SetupCount = 1;
4942 pSMB->Reserved3 = 0;
4943 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4944 byte_count = 3 /* pad */ + params + count;
4945 pSMB->DataCount = cpu_to_le16(count);
4946 pSMB->ParameterCount = cpu_to_le16(params);
4947 pSMB->TotalDataCount = pSMB->DataCount;
4948 pSMB->TotalParameterCount = pSMB->ParameterCount;
4949 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4950 parm_data =
4951 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4952 + offset);
4953 pSMB->DataOffset = cpu_to_le16(offset);
4954 parm_data->FileSize = cpu_to_le64(size);
4955 pSMB->Fid = fid;
4956 if (SetAllocation) {
4957 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4958 pSMB->InformationLevel =
4959 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4960 else
4961 pSMB->InformationLevel =
4962 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4963 } else /* Set File Size */ {
4964 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4965 pSMB->InformationLevel =
4966 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4967 else
4968 pSMB->InformationLevel =
4969 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4971 pSMB->Reserved4 = 0;
4972 pSMB->hdr.smb_buf_length += byte_count;
4973 pSMB->ByteCount = cpu_to_le16(byte_count);
4974 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4975 if (rc) {
4976 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
4979 /* Note: On -EAGAIN error only caller can retry on handle based calls
4980 since file handle passed in no longer valid */
4982 return rc;
4985 /* Some legacy servers such as NT4 require that the file times be set on
4986 an open handle, rather than by pathname - this is awkward due to
4987 potential access conflicts on the open, but it is unavoidable for these
4988 old servers since the only other choice is to go from 100 nanosecond DCE
4989 time and resort to the original setpathinfo level which takes the ancient
4990 DOS time format with 2 second granularity */
4992 CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4993 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4995 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4996 char *data_offset;
4997 int rc = 0;
4998 __u16 params, param_offset, offset, byte_count, count;
5000 cFYI(1, "Set Times (via SetFileInfo)");
5001 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5003 if (rc)
5004 return rc;
5006 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5007 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5009 params = 6;
5010 pSMB->MaxSetupCount = 0;
5011 pSMB->Reserved = 0;
5012 pSMB->Flags = 0;
5013 pSMB->Timeout = 0;
5014 pSMB->Reserved2 = 0;
5015 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5016 offset = param_offset + params;
5018 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5020 count = sizeof(FILE_BASIC_INFO);
5021 pSMB->MaxParameterCount = cpu_to_le16(2);
5022 /* BB find max SMB PDU from sess */
5023 pSMB->MaxDataCount = cpu_to_le16(1000);
5024 pSMB->SetupCount = 1;
5025 pSMB->Reserved3 = 0;
5026 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5027 byte_count = 3 /* pad */ + params + count;
5028 pSMB->DataCount = cpu_to_le16(count);
5029 pSMB->ParameterCount = cpu_to_le16(params);
5030 pSMB->TotalDataCount = pSMB->DataCount;
5031 pSMB->TotalParameterCount = pSMB->ParameterCount;
5032 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5033 pSMB->DataOffset = cpu_to_le16(offset);
5034 pSMB->Fid = fid;
5035 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5036 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5037 else
5038 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5039 pSMB->Reserved4 = 0;
5040 pSMB->hdr.smb_buf_length += byte_count;
5041 pSMB->ByteCount = cpu_to_le16(byte_count);
5042 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5043 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5044 if (rc)
5045 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
5047 /* Note: On -EAGAIN error only caller can retry on handle based calls
5048 since file handle passed in no longer valid */
5050 return rc;
5054 CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5055 bool delete_file, __u16 fid, __u32 pid_of_opener)
5057 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5058 char *data_offset;
5059 int rc = 0;
5060 __u16 params, param_offset, offset, byte_count, count;
5062 cFYI(1, "Set File Disposition (via SetFileInfo)");
5063 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5065 if (rc)
5066 return rc;
5068 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5069 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5071 params = 6;
5072 pSMB->MaxSetupCount = 0;
5073 pSMB->Reserved = 0;
5074 pSMB->Flags = 0;
5075 pSMB->Timeout = 0;
5076 pSMB->Reserved2 = 0;
5077 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5078 offset = param_offset + params;
5080 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5082 count = 1;
5083 pSMB->MaxParameterCount = cpu_to_le16(2);
5084 /* BB find max SMB PDU from sess */
5085 pSMB->MaxDataCount = cpu_to_le16(1000);
5086 pSMB->SetupCount = 1;
5087 pSMB->Reserved3 = 0;
5088 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5089 byte_count = 3 /* pad */ + params + count;
5090 pSMB->DataCount = cpu_to_le16(count);
5091 pSMB->ParameterCount = cpu_to_le16(params);
5092 pSMB->TotalDataCount = pSMB->DataCount;
5093 pSMB->TotalParameterCount = pSMB->ParameterCount;
5094 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5095 pSMB->DataOffset = cpu_to_le16(offset);
5096 pSMB->Fid = fid;
5097 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5098 pSMB->Reserved4 = 0;
5099 pSMB->hdr.smb_buf_length += byte_count;
5100 pSMB->ByteCount = cpu_to_le16(byte_count);
5101 *data_offset = delete_file ? 1 : 0;
5102 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5103 if (rc)
5104 cFYI(1, "Send error in SetFileDisposition = %d", rc);
5106 return rc;
5110 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5111 const char *fileName, const FILE_BASIC_INFO *data,
5112 const struct nls_table *nls_codepage, int remap)
5114 TRANSACTION2_SPI_REQ *pSMB = NULL;
5115 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5116 int name_len;
5117 int rc = 0;
5118 int bytes_returned = 0;
5119 char *data_offset;
5120 __u16 params, param_offset, offset, byte_count, count;
5122 cFYI(1, "In SetTimes");
5124 SetTimesRetry:
5125 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5126 (void **) &pSMBr);
5127 if (rc)
5128 return rc;
5130 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5131 name_len =
5132 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5133 PATH_MAX, nls_codepage, remap);
5134 name_len++; /* trailing null */
5135 name_len *= 2;
5136 } else { /* BB improve the check for buffer overruns BB */
5137 name_len = strnlen(fileName, PATH_MAX);
5138 name_len++; /* trailing null */
5139 strncpy(pSMB->FileName, fileName, name_len);
5142 params = 6 + name_len;
5143 count = sizeof(FILE_BASIC_INFO);
5144 pSMB->MaxParameterCount = cpu_to_le16(2);
5145 /* BB find 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 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5153 InformationLevel) - 4;
5154 offset = param_offset + params;
5155 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5156 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5157 pSMB->DataOffset = cpu_to_le16(offset);
5158 pSMB->SetupCount = 1;
5159 pSMB->Reserved3 = 0;
5160 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5161 byte_count = 3 /* pad */ + params + count;
5163 pSMB->DataCount = cpu_to_le16(count);
5164 pSMB->ParameterCount = cpu_to_le16(params);
5165 pSMB->TotalDataCount = pSMB->DataCount;
5166 pSMB->TotalParameterCount = pSMB->ParameterCount;
5167 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5168 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5169 else
5170 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5171 pSMB->Reserved4 = 0;
5172 pSMB->hdr.smb_buf_length += byte_count;
5173 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5174 pSMB->ByteCount = cpu_to_le16(byte_count);
5175 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5176 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5177 if (rc)
5178 cFYI(1, "SetPathInfo (times) returned %d", rc);
5180 cifs_buf_release(pSMB);
5182 if (rc == -EAGAIN)
5183 goto SetTimesRetry;
5185 return rc;
5188 /* Can not be used to set time stamps yet (due to old DOS time format) */
5189 /* Can be used to set attributes */
5190 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5191 handling it anyway and NT4 was what we thought it would be needed for
5192 Do not delete it until we prove whether needed for Win9x though */
5194 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5195 __u16 dos_attrs, const struct nls_table *nls_codepage)
5197 SETATTR_REQ *pSMB = NULL;
5198 SETATTR_RSP *pSMBr = NULL;
5199 int rc = 0;
5200 int bytes_returned;
5201 int name_len;
5203 cFYI(1, "In SetAttrLegacy");
5205 SetAttrLgcyRetry:
5206 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5207 (void **) &pSMBr);
5208 if (rc)
5209 return rc;
5211 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5212 name_len =
5213 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
5214 PATH_MAX, nls_codepage);
5215 name_len++; /* trailing null */
5216 name_len *= 2;
5217 } else { /* BB improve the check for buffer overruns BB */
5218 name_len = strnlen(fileName, PATH_MAX);
5219 name_len++; /* trailing null */
5220 strncpy(pSMB->fileName, fileName, name_len);
5222 pSMB->attr = cpu_to_le16(dos_attrs);
5223 pSMB->BufferFormat = 0x04;
5224 pSMB->hdr.smb_buf_length += name_len + 1;
5225 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5226 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5227 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5228 if (rc)
5229 cFYI(1, "Error in LegacySetAttr = %d", rc);
5231 cifs_buf_release(pSMB);
5233 if (rc == -EAGAIN)
5234 goto SetAttrLgcyRetry;
5236 return rc;
5238 #endif /* temporarily unneeded SetAttr legacy function */
5240 static void
5241 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5242 const struct cifs_unix_set_info_args *args)
5244 u64 mode = args->mode;
5247 * Samba server ignores set of file size to zero due to bugs in some
5248 * older clients, but we should be precise - we use SetFileSize to
5249 * set file size and do not want to truncate file size to zero
5250 * accidentally as happened on one Samba server beta by putting
5251 * zero instead of -1 here
5253 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5254 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5255 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5256 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5257 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5258 data_offset->Uid = cpu_to_le64(args->uid);
5259 data_offset->Gid = cpu_to_le64(args->gid);
5260 /* better to leave device as zero when it is */
5261 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5262 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5263 data_offset->Permissions = cpu_to_le64(mode);
5265 if (S_ISREG(mode))
5266 data_offset->Type = cpu_to_le32(UNIX_FILE);
5267 else if (S_ISDIR(mode))
5268 data_offset->Type = cpu_to_le32(UNIX_DIR);
5269 else if (S_ISLNK(mode))
5270 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5271 else if (S_ISCHR(mode))
5272 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5273 else if (S_ISBLK(mode))
5274 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5275 else if (S_ISFIFO(mode))
5276 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5277 else if (S_ISSOCK(mode))
5278 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5282 CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5283 const struct cifs_unix_set_info_args *args,
5284 u16 fid, u32 pid_of_opener)
5286 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5287 FILE_UNIX_BASIC_INFO *data_offset;
5288 int rc = 0;
5289 u16 params, param_offset, offset, byte_count, count;
5291 cFYI(1, "Set Unix Info (via SetFileInfo)");
5292 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5294 if (rc)
5295 return rc;
5297 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5298 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5300 params = 6;
5301 pSMB->MaxSetupCount = 0;
5302 pSMB->Reserved = 0;
5303 pSMB->Flags = 0;
5304 pSMB->Timeout = 0;
5305 pSMB->Reserved2 = 0;
5306 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5307 offset = param_offset + params;
5309 data_offset = (FILE_UNIX_BASIC_INFO *)
5310 ((char *)(&pSMB->hdr.Protocol) + offset);
5311 count = sizeof(FILE_UNIX_BASIC_INFO);
5313 pSMB->MaxParameterCount = cpu_to_le16(2);
5314 /* BB find max SMB PDU from sess */
5315 pSMB->MaxDataCount = cpu_to_le16(1000);
5316 pSMB->SetupCount = 1;
5317 pSMB->Reserved3 = 0;
5318 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5319 byte_count = 3 /* pad */ + params + count;
5320 pSMB->DataCount = cpu_to_le16(count);
5321 pSMB->ParameterCount = cpu_to_le16(params);
5322 pSMB->TotalDataCount = pSMB->DataCount;
5323 pSMB->TotalParameterCount = pSMB->ParameterCount;
5324 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5325 pSMB->DataOffset = cpu_to_le16(offset);
5326 pSMB->Fid = fid;
5327 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5328 pSMB->Reserved4 = 0;
5329 pSMB->hdr.smb_buf_length += byte_count;
5330 pSMB->ByteCount = cpu_to_le16(byte_count);
5332 cifs_fill_unix_set_info(data_offset, args);
5334 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5335 if (rc)
5336 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
5338 /* Note: On -EAGAIN error only caller can retry on handle based calls
5339 since file handle passed in no longer valid */
5341 return rc;
5345 CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5346 const struct cifs_unix_set_info_args *args,
5347 const struct nls_table *nls_codepage, int remap)
5349 TRANSACTION2_SPI_REQ *pSMB = NULL;
5350 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5351 int name_len;
5352 int rc = 0;
5353 int bytes_returned = 0;
5354 FILE_UNIX_BASIC_INFO *data_offset;
5355 __u16 params, param_offset, offset, count, byte_count;
5357 cFYI(1, "In SetUID/GID/Mode");
5358 setPermsRetry:
5359 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5360 (void **) &pSMBr);
5361 if (rc)
5362 return rc;
5364 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5365 name_len =
5366 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5367 PATH_MAX, nls_codepage, remap);
5368 name_len++; /* trailing null */
5369 name_len *= 2;
5370 } else { /* BB improve the check for buffer overruns BB */
5371 name_len = strnlen(fileName, PATH_MAX);
5372 name_len++; /* trailing null */
5373 strncpy(pSMB->FileName, fileName, name_len);
5376 params = 6 + name_len;
5377 count = sizeof(FILE_UNIX_BASIC_INFO);
5378 pSMB->MaxParameterCount = cpu_to_le16(2);
5379 /* BB find max SMB PDU from sess structure BB */
5380 pSMB->MaxDataCount = cpu_to_le16(1000);
5381 pSMB->MaxSetupCount = 0;
5382 pSMB->Reserved = 0;
5383 pSMB->Flags = 0;
5384 pSMB->Timeout = 0;
5385 pSMB->Reserved2 = 0;
5386 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5387 InformationLevel) - 4;
5388 offset = param_offset + params;
5389 data_offset =
5390 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5391 offset);
5392 memset(data_offset, 0, count);
5393 pSMB->DataOffset = cpu_to_le16(offset);
5394 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5395 pSMB->SetupCount = 1;
5396 pSMB->Reserved3 = 0;
5397 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5398 byte_count = 3 /* pad */ + params + count;
5399 pSMB->ParameterCount = cpu_to_le16(params);
5400 pSMB->DataCount = cpu_to_le16(count);
5401 pSMB->TotalParameterCount = pSMB->ParameterCount;
5402 pSMB->TotalDataCount = pSMB->DataCount;
5403 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5404 pSMB->Reserved4 = 0;
5405 pSMB->hdr.smb_buf_length += byte_count;
5407 cifs_fill_unix_set_info(data_offset, args);
5409 pSMB->ByteCount = cpu_to_le16(byte_count);
5410 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5411 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5412 if (rc)
5413 cFYI(1, "SetPathInfo (perms) returned %d", rc);
5415 cifs_buf_release(pSMB);
5416 if (rc == -EAGAIN)
5417 goto setPermsRetry;
5418 return rc;
5421 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5422 const int notify_subdirs, const __u16 netfid,
5423 __u32 filter, struct file *pfile, int multishot,
5424 const struct nls_table *nls_codepage)
5426 int rc = 0;
5427 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5428 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5429 struct dir_notify_req *dnotify_req;
5430 int bytes_returned;
5432 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
5433 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5434 (void **) &pSMBr);
5435 if (rc)
5436 return rc;
5438 pSMB->TotalParameterCount = 0 ;
5439 pSMB->TotalDataCount = 0;
5440 pSMB->MaxParameterCount = cpu_to_le32(2);
5441 /* BB find exact data count max from sess structure BB */
5442 pSMB->MaxDataCount = 0; /* same in little endian or be */
5443 /* BB VERIFY verify which is correct for above BB */
5444 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5445 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5447 pSMB->MaxSetupCount = 4;
5448 pSMB->Reserved = 0;
5449 pSMB->ParameterOffset = 0;
5450 pSMB->DataCount = 0;
5451 pSMB->DataOffset = 0;
5452 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5453 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5454 pSMB->ParameterCount = pSMB->TotalParameterCount;
5455 if (notify_subdirs)
5456 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5457 pSMB->Reserved2 = 0;
5458 pSMB->CompletionFilter = cpu_to_le32(filter);
5459 pSMB->Fid = netfid; /* file handle always le */
5460 pSMB->ByteCount = 0;
5462 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5463 (struct smb_hdr *)pSMBr, &bytes_returned,
5464 CIFS_ASYNC_OP);
5465 if (rc) {
5466 cFYI(1, "Error in Notify = %d", rc);
5467 } else {
5468 /* Add file to outstanding requests */
5469 /* BB change to kmem cache alloc */
5470 dnotify_req = kmalloc(
5471 sizeof(struct dir_notify_req),
5472 GFP_KERNEL);
5473 if (dnotify_req) {
5474 dnotify_req->Pid = pSMB->hdr.Pid;
5475 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5476 dnotify_req->Mid = pSMB->hdr.Mid;
5477 dnotify_req->Tid = pSMB->hdr.Tid;
5478 dnotify_req->Uid = pSMB->hdr.Uid;
5479 dnotify_req->netfid = netfid;
5480 dnotify_req->pfile = pfile;
5481 dnotify_req->filter = filter;
5482 dnotify_req->multishot = multishot;
5483 spin_lock(&GlobalMid_Lock);
5484 list_add_tail(&dnotify_req->lhead,
5485 &GlobalDnotifyReqList);
5486 spin_unlock(&GlobalMid_Lock);
5487 } else
5488 rc = -ENOMEM;
5490 cifs_buf_release(pSMB);
5491 return rc;
5494 #ifdef CONFIG_CIFS_XATTR
5496 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5497 * function used by listxattr and getxattr type calls. When ea_name is set,
5498 * it looks for that attribute name and stuffs that value into the EAData
5499 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5500 * buffer. In both cases, the return value is either the length of the
5501 * resulting data or a negative error code. If EAData is a NULL pointer then
5502 * the data isn't copied to it, but the length is returned.
5504 ssize_t
5505 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5506 const unsigned char *searchName, const unsigned char *ea_name,
5507 char *EAData, size_t buf_size,
5508 const struct nls_table *nls_codepage, int remap)
5510 /* BB assumes one setup word */
5511 TRANSACTION2_QPI_REQ *pSMB = NULL;
5512 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5513 int rc = 0;
5514 int bytes_returned;
5515 int list_len;
5516 struct fealist *ea_response_data;
5517 struct fea *temp_fea;
5518 char *temp_ptr;
5519 char *end_of_smb;
5520 __u16 params, byte_count, data_offset;
5522 cFYI(1, "In Query All EAs path %s", searchName);
5523 QAllEAsRetry:
5524 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5525 (void **) &pSMBr);
5526 if (rc)
5527 return rc;
5529 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5530 list_len =
5531 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5532 PATH_MAX, nls_codepage, remap);
5533 list_len++; /* trailing null */
5534 list_len *= 2;
5535 } else { /* BB improve the check for buffer overruns BB */
5536 list_len = strnlen(searchName, PATH_MAX);
5537 list_len++; /* trailing null */
5538 strncpy(pSMB->FileName, searchName, list_len);
5541 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
5542 pSMB->TotalDataCount = 0;
5543 pSMB->MaxParameterCount = cpu_to_le16(2);
5544 /* BB find exact max SMB PDU from sess structure BB */
5545 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
5546 pSMB->MaxSetupCount = 0;
5547 pSMB->Reserved = 0;
5548 pSMB->Flags = 0;
5549 pSMB->Timeout = 0;
5550 pSMB->Reserved2 = 0;
5551 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5552 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5553 pSMB->DataCount = 0;
5554 pSMB->DataOffset = 0;
5555 pSMB->SetupCount = 1;
5556 pSMB->Reserved3 = 0;
5557 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5558 byte_count = params + 1 /* pad */ ;
5559 pSMB->TotalParameterCount = cpu_to_le16(params);
5560 pSMB->ParameterCount = pSMB->TotalParameterCount;
5561 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5562 pSMB->Reserved4 = 0;
5563 pSMB->hdr.smb_buf_length += byte_count;
5564 pSMB->ByteCount = cpu_to_le16(byte_count);
5566 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5567 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5568 if (rc) {
5569 cFYI(1, "Send error in QueryAllEAs = %d", rc);
5570 goto QAllEAsOut;
5574 /* BB also check enough total bytes returned */
5575 /* BB we need to improve the validity checking
5576 of these trans2 responses */
5578 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5579 if (rc || (pSMBr->ByteCount < 4)) {
5580 rc = -EIO; /* bad smb */
5581 goto QAllEAsOut;
5584 /* check that length of list is not more than bcc */
5585 /* check that each entry does not go beyond length
5586 of list */
5587 /* check that each element of each entry does not
5588 go beyond end of list */
5589 /* validate_trans2_offsets() */
5590 /* BB check if start of smb + data_offset > &bcc+ bcc */
5592 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5593 ea_response_data = (struct fealist *)
5594 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5596 list_len = le32_to_cpu(ea_response_data->list_len);
5597 cFYI(1, "ea length %d", list_len);
5598 if (list_len <= 8) {
5599 cFYI(1, "empty EA list returned from server");
5600 goto QAllEAsOut;
5603 /* make sure list_len doesn't go past end of SMB */
5604 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
5605 if ((char *)ea_response_data + list_len > end_of_smb) {
5606 cFYI(1, "EA list appears to go beyond SMB");
5607 rc = -EIO;
5608 goto QAllEAsOut;
5611 /* account for ea list len */
5612 list_len -= 4;
5613 temp_fea = ea_response_data->list;
5614 temp_ptr = (char *)temp_fea;
5615 while (list_len > 0) {
5616 unsigned int name_len;
5617 __u16 value_len;
5619 list_len -= 4;
5620 temp_ptr += 4;
5621 /* make sure we can read name_len and value_len */
5622 if (list_len < 0) {
5623 cFYI(1, "EA entry goes beyond length of list");
5624 rc = -EIO;
5625 goto QAllEAsOut;
5628 name_len = temp_fea->name_len;
5629 value_len = le16_to_cpu(temp_fea->value_len);
5630 list_len -= name_len + 1 + value_len;
5631 if (list_len < 0) {
5632 cFYI(1, "EA entry goes beyond length of list");
5633 rc = -EIO;
5634 goto QAllEAsOut;
5637 if (ea_name) {
5638 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5639 temp_ptr += name_len + 1;
5640 rc = value_len;
5641 if (buf_size == 0)
5642 goto QAllEAsOut;
5643 if ((size_t)value_len > buf_size) {
5644 rc = -ERANGE;
5645 goto QAllEAsOut;
5647 memcpy(EAData, temp_ptr, value_len);
5648 goto QAllEAsOut;
5650 } else {
5651 /* account for prefix user. and trailing null */
5652 rc += (5 + 1 + name_len);
5653 if (rc < (int) buf_size) {
5654 memcpy(EAData, "user.", 5);
5655 EAData += 5;
5656 memcpy(EAData, temp_ptr, name_len);
5657 EAData += name_len;
5658 /* null terminate name */
5659 *EAData = 0;
5660 ++EAData;
5661 } else if (buf_size == 0) {
5662 /* skip copy - calc size only */
5663 } else {
5664 /* stop before overrun buffer */
5665 rc = -ERANGE;
5666 break;
5669 temp_ptr += name_len + 1 + value_len;
5670 temp_fea = (struct fea *)temp_ptr;
5673 /* didn't find the named attribute */
5674 if (ea_name)
5675 rc = -ENODATA;
5677 QAllEAsOut:
5678 cifs_buf_release(pSMB);
5679 if (rc == -EAGAIN)
5680 goto QAllEAsRetry;
5682 return (ssize_t)rc;
5686 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5687 const char *ea_name, const void *ea_value,
5688 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5689 int remap)
5691 struct smb_com_transaction2_spi_req *pSMB = NULL;
5692 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5693 struct fealist *parm_data;
5694 int name_len;
5695 int rc = 0;
5696 int bytes_returned = 0;
5697 __u16 params, param_offset, byte_count, offset, count;
5699 cFYI(1, "In SetEA");
5700 SetEARetry:
5701 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5702 (void **) &pSMBr);
5703 if (rc)
5704 return rc;
5706 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5707 name_len =
5708 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5709 PATH_MAX, nls_codepage, remap);
5710 name_len++; /* trailing null */
5711 name_len *= 2;
5712 } else { /* BB improve the check for buffer overruns BB */
5713 name_len = strnlen(fileName, PATH_MAX);
5714 name_len++; /* trailing null */
5715 strncpy(pSMB->FileName, fileName, name_len);
5718 params = 6 + name_len;
5720 /* done calculating parms using name_len of file name,
5721 now use name_len to calculate length of ea name
5722 we are going to create in the inode xattrs */
5723 if (ea_name == NULL)
5724 name_len = 0;
5725 else
5726 name_len = strnlen(ea_name, 255);
5728 count = sizeof(*parm_data) + ea_value_len + name_len;
5729 pSMB->MaxParameterCount = cpu_to_le16(2);
5730 /* BB find max SMB PDU from sess */
5731 pSMB->MaxDataCount = cpu_to_le16(1000);
5732 pSMB->MaxSetupCount = 0;
5733 pSMB->Reserved = 0;
5734 pSMB->Flags = 0;
5735 pSMB->Timeout = 0;
5736 pSMB->Reserved2 = 0;
5737 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5738 InformationLevel) - 4;
5739 offset = param_offset + params;
5740 pSMB->InformationLevel =
5741 cpu_to_le16(SMB_SET_FILE_EA);
5743 parm_data =
5744 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5745 offset);
5746 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5747 pSMB->DataOffset = cpu_to_le16(offset);
5748 pSMB->SetupCount = 1;
5749 pSMB->Reserved3 = 0;
5750 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5751 byte_count = 3 /* pad */ + params + count;
5752 pSMB->DataCount = cpu_to_le16(count);
5753 parm_data->list_len = cpu_to_le32(count);
5754 parm_data->list[0].EA_flags = 0;
5755 /* we checked above that name len is less than 255 */
5756 parm_data->list[0].name_len = (__u8)name_len;
5757 /* EA names are always ASCII */
5758 if (ea_name)
5759 strncpy(parm_data->list[0].name, ea_name, name_len);
5760 parm_data->list[0].name[name_len] = 0;
5761 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5762 /* caller ensures that ea_value_len is less than 64K but
5763 we need to ensure that it fits within the smb */
5765 /*BB add length check to see if it would fit in
5766 negotiated SMB buffer size BB */
5767 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5768 if (ea_value_len)
5769 memcpy(parm_data->list[0].name+name_len+1,
5770 ea_value, ea_value_len);
5772 pSMB->TotalDataCount = pSMB->DataCount;
5773 pSMB->ParameterCount = cpu_to_le16(params);
5774 pSMB->TotalParameterCount = pSMB->ParameterCount;
5775 pSMB->Reserved4 = 0;
5776 pSMB->hdr.smb_buf_length += byte_count;
5777 pSMB->ByteCount = cpu_to_le16(byte_count);
5778 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5779 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5780 if (rc)
5781 cFYI(1, "SetPathInfo (EA) returned %d", rc);
5783 cifs_buf_release(pSMB);
5785 if (rc == -EAGAIN)
5786 goto SetEARetry;
5788 return rc;
5791 #endif