cifs: add ignore_pend flag to cifs_call_async
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / cifs / cifssmb.c
blobe0d24135b3c69f400e96efedb180094be646f36d
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 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
343 if (total_size >= 512)
344 goto vt2_err;
346 /* check that bcc is at least as big as parms + data, and that it is
347 * less than negotiated smb buffer
349 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
350 if (total_size > get_bcc(&pSMB->hdr) ||
351 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
352 goto vt2_err;
354 return 0;
355 vt2_err:
356 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
357 sizeof(struct smb_t2_rsp) + 16);
358 return -EINVAL;
361 static inline void inc_rfc1001_len(void *pSMB, int count)
363 struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
365 be32_add_cpu(&hdr->smb_buf_length, count);
369 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
371 NEGOTIATE_REQ *pSMB;
372 NEGOTIATE_RSP *pSMBr;
373 int rc = 0;
374 int bytes_returned;
375 int i;
376 struct TCP_Server_Info *server;
377 u16 count;
378 unsigned int secFlags;
380 if (ses->server)
381 server = ses->server;
382 else {
383 rc = -EIO;
384 return rc;
386 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
387 (void **) &pSMB, (void **) &pSMBr);
388 if (rc)
389 return rc;
391 /* if any of auth flags (ie not sign or seal) are overriden use them */
392 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
393 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
394 else /* if override flags set only sign/seal OR them with global auth */
395 secFlags = global_secflags | ses->overrideSecFlg;
397 cFYI(1, "secFlags 0x%x", secFlags);
399 pSMB->hdr.Mid = GetNextMid(server);
400 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
402 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
403 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
404 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
405 cFYI(1, "Kerberos only mechanism, enable extended security");
406 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
407 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
408 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
409 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
410 cFYI(1, "NTLMSSP only mechanism, enable extended security");
411 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
414 count = 0;
415 for (i = 0; i < CIFS_NUM_PROT; i++) {
416 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
417 count += strlen(protocols[i].name) + 1;
418 /* null at end of source and target buffers anyway */
420 inc_rfc1001_len(pSMB, count);
421 pSMB->ByteCount = cpu_to_le16(count);
423 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
424 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
425 if (rc != 0)
426 goto neg_err_exit;
428 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
429 cFYI(1, "Dialect: %d", server->dialect);
430 /* Check wct = 1 error case */
431 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
432 /* core returns wct = 1, but we do not ask for core - otherwise
433 small wct just comes when dialect index is -1 indicating we
434 could not negotiate a common dialect */
435 rc = -EOPNOTSUPP;
436 goto neg_err_exit;
437 #ifdef CONFIG_CIFS_WEAK_PW_HASH
438 } else if ((pSMBr->hdr.WordCount == 13)
439 && ((server->dialect == LANMAN_PROT)
440 || (server->dialect == LANMAN2_PROT))) {
441 __s16 tmp;
442 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
444 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
445 (secFlags & CIFSSEC_MAY_PLNTXT))
446 server->secType = LANMAN;
447 else {
448 cERROR(1, "mount failed weak security disabled"
449 " in /proc/fs/cifs/SecurityFlags");
450 rc = -EOPNOTSUPP;
451 goto neg_err_exit;
453 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
454 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
455 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
456 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
457 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
458 /* even though we do not use raw we might as well set this
459 accurately, in case we ever find a need for it */
460 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
461 server->max_rw = 0xFF00;
462 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
463 } else {
464 server->max_rw = 0;/* do not need to use raw anyway */
465 server->capabilities = CAP_MPX_MODE;
467 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
468 if (tmp == -1) {
469 /* OS/2 often does not set timezone therefore
470 * we must use server time to calc time zone.
471 * Could deviate slightly from the right zone.
472 * Smallest defined timezone difference is 15 minutes
473 * (i.e. Nepal). Rounding up/down is done to match
474 * this requirement.
476 int val, seconds, remain, result;
477 struct timespec ts, utc;
478 utc = CURRENT_TIME;
479 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
480 rsp->SrvTime.Time, 0);
481 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
482 (int)ts.tv_sec, (int)utc.tv_sec,
483 (int)(utc.tv_sec - ts.tv_sec));
484 val = (int)(utc.tv_sec - ts.tv_sec);
485 seconds = abs(val);
486 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
487 remain = seconds % MIN_TZ_ADJ;
488 if (remain >= (MIN_TZ_ADJ / 2))
489 result += MIN_TZ_ADJ;
490 if (val < 0)
491 result = -result;
492 server->timeAdj = result;
493 } else {
494 server->timeAdj = (int)tmp;
495 server->timeAdj *= 60; /* also in seconds */
497 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
500 /* BB get server time for time conversions and add
501 code to use it and timezone since this is not UTC */
503 if (rsp->EncryptionKeyLength ==
504 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
505 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
506 CIFS_CRYPTO_KEY_SIZE);
507 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
508 rc = -EIO; /* need cryptkey unless plain text */
509 goto neg_err_exit;
512 cFYI(1, "LANMAN negotiated");
513 /* we will not end up setting signing flags - as no signing
514 was in LANMAN and server did not return the flags on */
515 goto signing_check;
516 #else /* weak security disabled */
517 } else if (pSMBr->hdr.WordCount == 13) {
518 cERROR(1, "mount failed, cifs module not built "
519 "with CIFS_WEAK_PW_HASH support");
520 rc = -EOPNOTSUPP;
521 #endif /* WEAK_PW_HASH */
522 goto neg_err_exit;
523 } else if (pSMBr->hdr.WordCount != 17) {
524 /* unknown wct */
525 rc = -EOPNOTSUPP;
526 goto neg_err_exit;
528 /* else wct == 17 NTLM */
529 server->secMode = pSMBr->SecurityMode;
530 if ((server->secMode & SECMODE_USER) == 0)
531 cFYI(1, "share mode security");
533 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
534 #ifdef CONFIG_CIFS_WEAK_PW_HASH
535 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
536 #endif /* CIFS_WEAK_PW_HASH */
537 cERROR(1, "Server requests plain text password"
538 " but client support disabled");
540 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
541 server->secType = NTLMv2;
542 else if (secFlags & CIFSSEC_MAY_NTLM)
543 server->secType = NTLM;
544 else if (secFlags & CIFSSEC_MAY_NTLMV2)
545 server->secType = NTLMv2;
546 else if (secFlags & CIFSSEC_MAY_KRB5)
547 server->secType = Kerberos;
548 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
549 server->secType = RawNTLMSSP;
550 else if (secFlags & CIFSSEC_MAY_LANMAN)
551 server->secType = LANMAN;
552 else {
553 rc = -EOPNOTSUPP;
554 cERROR(1, "Invalid security type");
555 goto neg_err_exit;
557 /* else ... any others ...? */
559 /* one byte, so no need to convert this or EncryptionKeyLen from
560 little endian */
561 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
562 /* probably no need to store and check maxvcs */
563 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
564 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
565 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
566 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
567 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
568 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
569 server->timeAdj *= 60;
570 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
571 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
572 CIFS_CRYPTO_KEY_SIZE);
573 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
574 && (pSMBr->EncryptionKeyLength == 0)) {
575 /* decode security blob */
576 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
577 rc = -EIO; /* no crypt key only if plain text pwd */
578 goto neg_err_exit;
581 /* BB might be helpful to save off the domain of server here */
583 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
584 (server->capabilities & CAP_EXTENDED_SECURITY)) {
585 count = get_bcc(&pSMBr->hdr);
586 if (count < 16) {
587 rc = -EIO;
588 goto neg_err_exit;
590 spin_lock(&cifs_tcp_ses_lock);
591 if (server->srv_count > 1) {
592 spin_unlock(&cifs_tcp_ses_lock);
593 if (memcmp(server->server_GUID,
594 pSMBr->u.extended_response.
595 GUID, 16) != 0) {
596 cFYI(1, "server UID changed");
597 memcpy(server->server_GUID,
598 pSMBr->u.extended_response.GUID,
599 16);
601 } else {
602 spin_unlock(&cifs_tcp_ses_lock);
603 memcpy(server->server_GUID,
604 pSMBr->u.extended_response.GUID, 16);
607 if (count == 16) {
608 server->secType = RawNTLMSSP;
609 } else {
610 rc = decode_negTokenInit(pSMBr->u.extended_response.
611 SecurityBlob, count - 16,
612 server);
613 if (rc == 1)
614 rc = 0;
615 else
616 rc = -EINVAL;
617 if (server->secType == Kerberos) {
618 if (!server->sec_kerberos &&
619 !server->sec_mskerberos)
620 rc = -EOPNOTSUPP;
621 } else if (server->secType == RawNTLMSSP) {
622 if (!server->sec_ntlmssp)
623 rc = -EOPNOTSUPP;
624 } else
625 rc = -EOPNOTSUPP;
627 } else
628 server->capabilities &= ~CAP_EXTENDED_SECURITY;
630 #ifdef CONFIG_CIFS_WEAK_PW_HASH
631 signing_check:
632 #endif
633 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
634 /* MUST_SIGN already includes the MAY_SIGN FLAG
635 so if this is zero it means that signing is disabled */
636 cFYI(1, "Signing disabled");
637 if (server->secMode & SECMODE_SIGN_REQUIRED) {
638 cERROR(1, "Server requires "
639 "packet signing to be enabled in "
640 "/proc/fs/cifs/SecurityFlags.");
641 rc = -EOPNOTSUPP;
643 server->secMode &=
644 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
645 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
646 /* signing required */
647 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
648 if ((server->secMode &
649 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
650 cERROR(1, "signing required but server lacks support");
651 rc = -EOPNOTSUPP;
652 } else
653 server->secMode |= SECMODE_SIGN_REQUIRED;
654 } else {
655 /* signing optional ie CIFSSEC_MAY_SIGN */
656 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
657 server->secMode &=
658 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
661 neg_err_exit:
662 cifs_buf_release(pSMB);
664 cFYI(1, "negprot rc %d", rc);
665 return rc;
669 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
671 struct smb_hdr *smb_buffer;
672 int rc = 0;
674 cFYI(1, "In tree disconnect");
676 /* BB: do we need to check this? These should never be NULL. */
677 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
678 return -EIO;
681 * No need to return error on this operation if tid invalidated and
682 * closed on server already e.g. due to tcp session crashing. Also,
683 * the tcon is no longer on the list, so no need to take lock before
684 * checking this.
686 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
687 return 0;
689 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
690 (void **)&smb_buffer);
691 if (rc)
692 return rc;
694 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
695 if (rc)
696 cFYI(1, "Tree disconnect failed %d", rc);
698 /* No need to return error on this operation if tid invalidated and
699 closed on server already e.g. due to tcp session crashing */
700 if (rc == -EAGAIN)
701 rc = 0;
703 return rc;
707 * This is a no-op for now. We're not really interested in the reply, but
708 * rather in the fact that the server sent one and that server->lstrp
709 * gets updated.
711 * FIXME: maybe we should consider checking that the reply matches request?
713 static void
714 cifs_echo_callback(struct mid_q_entry *mid)
716 struct TCP_Server_Info *server = mid->callback_data;
718 DeleteMidQEntry(mid);
719 atomic_dec(&server->inFlight);
720 wake_up(&server->request_q);
724 CIFSSMBEcho(struct TCP_Server_Info *server)
726 ECHO_REQ *smb;
727 int rc = 0;
728 struct kvec iov;
730 cFYI(1, "In echo request");
732 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
733 if (rc)
734 return rc;
736 /* set up echo request */
737 smb->hdr.Tid = 0xffff;
738 smb->hdr.WordCount = 1;
739 put_unaligned_le16(1, &smb->EchoCount);
740 put_bcc(1, &smb->hdr);
741 smb->Data[0] = 'a';
742 inc_rfc1001_len(smb, 3);
743 iov.iov_base = smb;
744 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
746 rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true);
747 if (rc)
748 cFYI(1, "Echo request failed: %d", rc);
750 cifs_small_buf_release(smb);
752 return rc;
756 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
758 LOGOFF_ANDX_REQ *pSMB;
759 int rc = 0;
761 cFYI(1, "In SMBLogoff for session disconnect");
764 * BB: do we need to check validity of ses and server? They should
765 * always be valid since we have an active reference. If not, that
766 * should probably be a BUG()
768 if (!ses || !ses->server)
769 return -EIO;
771 mutex_lock(&ses->session_mutex);
772 if (ses->need_reconnect)
773 goto session_already_dead; /* no need to send SMBlogoff if uid
774 already closed due to reconnect */
775 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
776 if (rc) {
777 mutex_unlock(&ses->session_mutex);
778 return rc;
781 pSMB->hdr.Mid = GetNextMid(ses->server);
783 if (ses->server->secMode &
784 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
785 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
787 pSMB->hdr.Uid = ses->Suid;
789 pSMB->AndXCommand = 0xFF;
790 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
791 session_already_dead:
792 mutex_unlock(&ses->session_mutex);
794 /* if session dead then we do not need to do ulogoff,
795 since server closed smb session, no sense reporting
796 error */
797 if (rc == -EAGAIN)
798 rc = 0;
799 return rc;
803 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
804 __u16 type, const struct nls_table *nls_codepage, int remap)
806 TRANSACTION2_SPI_REQ *pSMB = NULL;
807 TRANSACTION2_SPI_RSP *pSMBr = NULL;
808 struct unlink_psx_rq *pRqD;
809 int name_len;
810 int rc = 0;
811 int bytes_returned = 0;
812 __u16 params, param_offset, offset, byte_count;
814 cFYI(1, "In POSIX delete");
815 PsxDelete:
816 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
817 (void **) &pSMBr);
818 if (rc)
819 return rc;
821 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
822 name_len =
823 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
824 PATH_MAX, nls_codepage, remap);
825 name_len++; /* trailing null */
826 name_len *= 2;
827 } else { /* BB add path length overrun check */
828 name_len = strnlen(fileName, PATH_MAX);
829 name_len++; /* trailing null */
830 strncpy(pSMB->FileName, fileName, name_len);
833 params = 6 + name_len;
834 pSMB->MaxParameterCount = cpu_to_le16(2);
835 pSMB->MaxDataCount = 0; /* BB double check this with jra */
836 pSMB->MaxSetupCount = 0;
837 pSMB->Reserved = 0;
838 pSMB->Flags = 0;
839 pSMB->Timeout = 0;
840 pSMB->Reserved2 = 0;
841 param_offset = offsetof(struct smb_com_transaction2_spi_req,
842 InformationLevel) - 4;
843 offset = param_offset + params;
845 /* Setup pointer to Request Data (inode type) */
846 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
847 pRqD->type = cpu_to_le16(type);
848 pSMB->ParameterOffset = cpu_to_le16(param_offset);
849 pSMB->DataOffset = cpu_to_le16(offset);
850 pSMB->SetupCount = 1;
851 pSMB->Reserved3 = 0;
852 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
853 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
855 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
856 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
857 pSMB->ParameterCount = cpu_to_le16(params);
858 pSMB->TotalParameterCount = pSMB->ParameterCount;
859 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
860 pSMB->Reserved4 = 0;
861 inc_rfc1001_len(pSMB, byte_count);
862 pSMB->ByteCount = cpu_to_le16(byte_count);
863 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
864 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
865 if (rc)
866 cFYI(1, "Posix delete returned %d", rc);
867 cifs_buf_release(pSMB);
869 cifs_stats_inc(&tcon->num_deletes);
871 if (rc == -EAGAIN)
872 goto PsxDelete;
874 return rc;
878 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
879 const struct nls_table *nls_codepage, int remap)
881 DELETE_FILE_REQ *pSMB = NULL;
882 DELETE_FILE_RSP *pSMBr = NULL;
883 int rc = 0;
884 int bytes_returned;
885 int name_len;
887 DelFileRetry:
888 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
889 (void **) &pSMBr);
890 if (rc)
891 return rc;
893 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
894 name_len =
895 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
896 PATH_MAX, nls_codepage, remap);
897 name_len++; /* trailing null */
898 name_len *= 2;
899 } else { /* BB improve check for buffer overruns BB */
900 name_len = strnlen(fileName, PATH_MAX);
901 name_len++; /* trailing null */
902 strncpy(pSMB->fileName, fileName, name_len);
904 pSMB->SearchAttributes =
905 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
906 pSMB->BufferFormat = 0x04;
907 inc_rfc1001_len(pSMB, name_len + 1);
908 pSMB->ByteCount = cpu_to_le16(name_len + 1);
909 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
910 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
911 cifs_stats_inc(&tcon->num_deletes);
912 if (rc)
913 cFYI(1, "Error in RMFile = %d", rc);
915 cifs_buf_release(pSMB);
916 if (rc == -EAGAIN)
917 goto DelFileRetry;
919 return rc;
923 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
924 const struct nls_table *nls_codepage, int remap)
926 DELETE_DIRECTORY_REQ *pSMB = NULL;
927 DELETE_DIRECTORY_RSP *pSMBr = NULL;
928 int rc = 0;
929 int bytes_returned;
930 int name_len;
932 cFYI(1, "In CIFSSMBRmDir");
933 RmDirRetry:
934 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
935 (void **) &pSMBr);
936 if (rc)
937 return rc;
939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
940 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
941 PATH_MAX, nls_codepage, remap);
942 name_len++; /* trailing null */
943 name_len *= 2;
944 } else { /* BB improve check for buffer overruns BB */
945 name_len = strnlen(dirName, PATH_MAX);
946 name_len++; /* trailing null */
947 strncpy(pSMB->DirName, dirName, name_len);
950 pSMB->BufferFormat = 0x04;
951 inc_rfc1001_len(pSMB, name_len + 1);
952 pSMB->ByteCount = cpu_to_le16(name_len + 1);
953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
955 cifs_stats_inc(&tcon->num_rmdirs);
956 if (rc)
957 cFYI(1, "Error in RMDir = %d", rc);
959 cifs_buf_release(pSMB);
960 if (rc == -EAGAIN)
961 goto RmDirRetry;
962 return rc;
966 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
967 const char *name, const struct nls_table *nls_codepage, int remap)
969 int rc = 0;
970 CREATE_DIRECTORY_REQ *pSMB = NULL;
971 CREATE_DIRECTORY_RSP *pSMBr = NULL;
972 int bytes_returned;
973 int name_len;
975 cFYI(1, "In CIFSSMBMkDir");
976 MkDirRetry:
977 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
978 (void **) &pSMBr);
979 if (rc)
980 return rc;
982 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
983 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
984 PATH_MAX, nls_codepage, remap);
985 name_len++; /* trailing null */
986 name_len *= 2;
987 } else { /* BB improve check for buffer overruns BB */
988 name_len = strnlen(name, PATH_MAX);
989 name_len++; /* trailing null */
990 strncpy(pSMB->DirName, name, name_len);
993 pSMB->BufferFormat = 0x04;
994 inc_rfc1001_len(pSMB, name_len + 1);
995 pSMB->ByteCount = cpu_to_le16(name_len + 1);
996 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
997 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
998 cifs_stats_inc(&tcon->num_mkdirs);
999 if (rc)
1000 cFYI(1, "Error in Mkdir = %d", rc);
1002 cifs_buf_release(pSMB);
1003 if (rc == -EAGAIN)
1004 goto MkDirRetry;
1005 return rc;
1009 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1010 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
1011 __u32 *pOplock, const char *name,
1012 const struct nls_table *nls_codepage, int remap)
1014 TRANSACTION2_SPI_REQ *pSMB = NULL;
1015 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1016 int name_len;
1017 int rc = 0;
1018 int bytes_returned = 0;
1019 __u16 params, param_offset, offset, byte_count, count;
1020 OPEN_PSX_REQ *pdata;
1021 OPEN_PSX_RSP *psx_rsp;
1023 cFYI(1, "In POSIX Create");
1024 PsxCreat:
1025 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1026 (void **) &pSMBr);
1027 if (rc)
1028 return rc;
1030 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1031 name_len =
1032 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1033 PATH_MAX, nls_codepage, remap);
1034 name_len++; /* trailing null */
1035 name_len *= 2;
1036 } else { /* BB improve the check for buffer overruns BB */
1037 name_len = strnlen(name, PATH_MAX);
1038 name_len++; /* trailing null */
1039 strncpy(pSMB->FileName, name, name_len);
1042 params = 6 + name_len;
1043 count = sizeof(OPEN_PSX_REQ);
1044 pSMB->MaxParameterCount = cpu_to_le16(2);
1045 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1046 pSMB->MaxSetupCount = 0;
1047 pSMB->Reserved = 0;
1048 pSMB->Flags = 0;
1049 pSMB->Timeout = 0;
1050 pSMB->Reserved2 = 0;
1051 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1052 InformationLevel) - 4;
1053 offset = param_offset + params;
1054 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1055 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1056 pdata->Permissions = cpu_to_le64(mode);
1057 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1058 pdata->OpenFlags = cpu_to_le32(*pOplock);
1059 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1060 pSMB->DataOffset = cpu_to_le16(offset);
1061 pSMB->SetupCount = 1;
1062 pSMB->Reserved3 = 0;
1063 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1064 byte_count = 3 /* pad */ + params + count;
1066 pSMB->DataCount = cpu_to_le16(count);
1067 pSMB->ParameterCount = cpu_to_le16(params);
1068 pSMB->TotalDataCount = pSMB->DataCount;
1069 pSMB->TotalParameterCount = pSMB->ParameterCount;
1070 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1071 pSMB->Reserved4 = 0;
1072 inc_rfc1001_len(pSMB, byte_count);
1073 pSMB->ByteCount = cpu_to_le16(byte_count);
1074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1075 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1076 if (rc) {
1077 cFYI(1, "Posix create returned %d", rc);
1078 goto psx_create_err;
1081 cFYI(1, "copying inode info");
1082 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1084 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
1085 rc = -EIO; /* bad smb */
1086 goto psx_create_err;
1089 /* copy return information to pRetData */
1090 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1091 + le16_to_cpu(pSMBr->t2.DataOffset));
1093 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1094 if (netfid)
1095 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1096 /* Let caller know file was created so we can set the mode. */
1097 /* Do we care about the CreateAction in any other cases? */
1098 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1099 *pOplock |= CIFS_CREATE_ACTION;
1100 /* check to make sure response data is there */
1101 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1102 pRetData->Type = cpu_to_le32(-1); /* unknown */
1103 cFYI(DBG2, "unknown type");
1104 } else {
1105 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
1106 + sizeof(FILE_UNIX_BASIC_INFO)) {
1107 cERROR(1, "Open response data too small");
1108 pRetData->Type = cpu_to_le32(-1);
1109 goto psx_create_err;
1111 memcpy((char *) pRetData,
1112 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1113 sizeof(FILE_UNIX_BASIC_INFO));
1116 psx_create_err:
1117 cifs_buf_release(pSMB);
1119 if (posix_flags & SMB_O_DIRECTORY)
1120 cifs_stats_inc(&tcon->num_posixmkdirs);
1121 else
1122 cifs_stats_inc(&tcon->num_posixopens);
1124 if (rc == -EAGAIN)
1125 goto PsxCreat;
1127 return rc;
1130 static __u16 convert_disposition(int disposition)
1132 __u16 ofun = 0;
1134 switch (disposition) {
1135 case FILE_SUPERSEDE:
1136 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1137 break;
1138 case FILE_OPEN:
1139 ofun = SMBOPEN_OAPPEND;
1140 break;
1141 case FILE_CREATE:
1142 ofun = SMBOPEN_OCREATE;
1143 break;
1144 case FILE_OPEN_IF:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1146 break;
1147 case FILE_OVERWRITE:
1148 ofun = SMBOPEN_OTRUNC;
1149 break;
1150 case FILE_OVERWRITE_IF:
1151 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1152 break;
1153 default:
1154 cFYI(1, "unknown disposition %d", disposition);
1155 ofun = SMBOPEN_OAPPEND; /* regular open */
1157 return ofun;
1160 static int
1161 access_flags_to_smbopen_mode(const int access_flags)
1163 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1165 if (masked_flags == GENERIC_READ)
1166 return SMBOPEN_READ;
1167 else if (masked_flags == GENERIC_WRITE)
1168 return SMBOPEN_WRITE;
1170 /* just go for read/write */
1171 return SMBOPEN_READWRITE;
1175 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1176 const char *fileName, const int openDisposition,
1177 const int access_flags, const int create_options, __u16 *netfid,
1178 int *pOplock, FILE_ALL_INFO *pfile_info,
1179 const struct nls_table *nls_codepage, int remap)
1181 int rc = -EACCES;
1182 OPENX_REQ *pSMB = NULL;
1183 OPENX_RSP *pSMBr = NULL;
1184 int bytes_returned;
1185 int name_len;
1186 __u16 count;
1188 OldOpenRetry:
1189 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1190 (void **) &pSMBr);
1191 if (rc)
1192 return rc;
1194 pSMB->AndXCommand = 0xFF; /* none */
1196 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1197 count = 1; /* account for one byte pad to word boundary */
1198 name_len =
1199 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1200 fileName, PATH_MAX, nls_codepage, remap);
1201 name_len++; /* trailing null */
1202 name_len *= 2;
1203 } else { /* BB improve check for buffer overruns BB */
1204 count = 0; /* no pad */
1205 name_len = strnlen(fileName, PATH_MAX);
1206 name_len++; /* trailing null */
1207 strncpy(pSMB->fileName, fileName, name_len);
1209 if (*pOplock & REQ_OPLOCK)
1210 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1211 else if (*pOplock & REQ_BATCHOPLOCK)
1212 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1214 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1215 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1216 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1217 /* set file as system file if special file such
1218 as fifo and server expecting SFU style and
1219 no Unix extensions */
1221 if (create_options & CREATE_OPTION_SPECIAL)
1222 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1223 else /* BB FIXME BB */
1224 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1226 if (create_options & CREATE_OPTION_READONLY)
1227 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1229 /* BB FIXME BB */
1230 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1231 CREATE_OPTIONS_MASK); */
1232 /* BB FIXME END BB */
1234 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1235 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1236 count += name_len;
1237 inc_rfc1001_len(pSMB, count);
1239 pSMB->ByteCount = cpu_to_le16(count);
1240 /* long_op set to 1 to allow for oplock break timeouts */
1241 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1242 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1243 cifs_stats_inc(&tcon->num_opens);
1244 if (rc) {
1245 cFYI(1, "Error in Open = %d", rc);
1246 } else {
1247 /* BB verify if wct == 15 */
1249 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1251 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1252 /* Let caller know file was created so we can set the mode. */
1253 /* Do we care about the CreateAction in any other cases? */
1254 /* BB FIXME BB */
1255 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1256 *pOplock |= CIFS_CREATE_ACTION; */
1257 /* BB FIXME END */
1259 if (pfile_info) {
1260 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1261 pfile_info->LastAccessTime = 0; /* BB fixme */
1262 pfile_info->LastWriteTime = 0; /* BB fixme */
1263 pfile_info->ChangeTime = 0; /* BB fixme */
1264 pfile_info->Attributes =
1265 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1266 /* the file_info buf is endian converted by caller */
1267 pfile_info->AllocationSize =
1268 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1269 pfile_info->EndOfFile = pfile_info->AllocationSize;
1270 pfile_info->NumberOfLinks = cpu_to_le32(1);
1271 pfile_info->DeletePending = 0;
1275 cifs_buf_release(pSMB);
1276 if (rc == -EAGAIN)
1277 goto OldOpenRetry;
1278 return rc;
1282 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1283 const char *fileName, const int openDisposition,
1284 const int access_flags, const int create_options, __u16 *netfid,
1285 int *pOplock, FILE_ALL_INFO *pfile_info,
1286 const struct nls_table *nls_codepage, int remap)
1288 int rc = -EACCES;
1289 OPEN_REQ *pSMB = NULL;
1290 OPEN_RSP *pSMBr = NULL;
1291 int bytes_returned;
1292 int name_len;
1293 __u16 count;
1295 openRetry:
1296 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1297 (void **) &pSMBr);
1298 if (rc)
1299 return rc;
1301 pSMB->AndXCommand = 0xFF; /* none */
1303 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1304 count = 1; /* account for one byte pad to word boundary */
1305 name_len =
1306 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1307 fileName, PATH_MAX, nls_codepage, remap);
1308 name_len++; /* trailing null */
1309 name_len *= 2;
1310 pSMB->NameLength = cpu_to_le16(name_len);
1311 } else { /* BB improve check for buffer overruns BB */
1312 count = 0; /* no pad */
1313 name_len = strnlen(fileName, PATH_MAX);
1314 name_len++; /* trailing null */
1315 pSMB->NameLength = cpu_to_le16(name_len);
1316 strncpy(pSMB->fileName, fileName, name_len);
1318 if (*pOplock & REQ_OPLOCK)
1319 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1320 else if (*pOplock & REQ_BATCHOPLOCK)
1321 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1322 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1323 pSMB->AllocationSize = 0;
1324 /* set file as system file if special file such
1325 as fifo and server expecting SFU style and
1326 no Unix extensions */
1327 if (create_options & CREATE_OPTION_SPECIAL)
1328 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1329 else
1330 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1332 /* XP does not handle ATTR_POSIX_SEMANTICS */
1333 /* but it helps speed up case sensitive checks for other
1334 servers such as Samba */
1335 if (tcon->ses->capabilities & CAP_UNIX)
1336 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1338 if (create_options & CREATE_OPTION_READONLY)
1339 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1341 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1342 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1343 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1344 /* BB Expirement with various impersonation levels and verify */
1345 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1346 pSMB->SecurityFlags =
1347 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1349 count += name_len;
1350 inc_rfc1001_len(pSMB, count);
1352 pSMB->ByteCount = cpu_to_le16(count);
1353 /* long_op set to 1 to allow for oplock break timeouts */
1354 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1355 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1356 cifs_stats_inc(&tcon->num_opens);
1357 if (rc) {
1358 cFYI(1, "Error in Open = %d", rc);
1359 } else {
1360 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1361 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1362 /* Let caller know file was created so we can set the mode. */
1363 /* Do we care about the CreateAction in any other cases? */
1364 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1365 *pOplock |= CIFS_CREATE_ACTION;
1366 if (pfile_info) {
1367 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1368 36 /* CreationTime to Attributes */);
1369 /* the file_info buf is endian converted by caller */
1370 pfile_info->AllocationSize = pSMBr->AllocationSize;
1371 pfile_info->EndOfFile = pSMBr->EndOfFile;
1372 pfile_info->NumberOfLinks = cpu_to_le32(1);
1373 pfile_info->DeletePending = 0;
1377 cifs_buf_release(pSMB);
1378 if (rc == -EAGAIN)
1379 goto openRetry;
1380 return rc;
1384 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1385 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1386 char **buf, int *pbuf_type)
1388 int rc = -EACCES;
1389 READ_REQ *pSMB = NULL;
1390 READ_RSP *pSMBr = NULL;
1391 char *pReadData = NULL;
1392 int wct;
1393 int resp_buf_type = 0;
1394 struct kvec iov[1];
1396 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
1397 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1398 wct = 12;
1399 else {
1400 wct = 10; /* old style read */
1401 if ((lseek >> 32) > 0) {
1402 /* can not handle this big offset for old */
1403 return -EIO;
1407 *nbytes = 0;
1408 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1409 if (rc)
1410 return rc;
1412 /* tcon and ses pointer are checked in smb_init */
1413 if (tcon->ses->server == NULL)
1414 return -ECONNABORTED;
1416 pSMB->AndXCommand = 0xFF; /* none */
1417 pSMB->Fid = netfid;
1418 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1419 if (wct == 12)
1420 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1422 pSMB->Remaining = 0;
1423 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1424 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1425 if (wct == 12)
1426 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1427 else {
1428 /* old style read */
1429 struct smb_com_readx_req *pSMBW =
1430 (struct smb_com_readx_req *)pSMB;
1431 pSMBW->ByteCount = 0;
1434 iov[0].iov_base = (char *)pSMB;
1435 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
1436 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1437 &resp_buf_type, CIFS_LOG_ERROR);
1438 cifs_stats_inc(&tcon->num_reads);
1439 pSMBr = (READ_RSP *)iov[0].iov_base;
1440 if (rc) {
1441 cERROR(1, "Send error in read = %d", rc);
1442 } else {
1443 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1444 data_length = data_length << 16;
1445 data_length += le16_to_cpu(pSMBr->DataLength);
1446 *nbytes = data_length;
1448 /*check that DataLength would not go beyond end of SMB */
1449 if ((data_length > CIFSMaxBufSize)
1450 || (data_length > count)) {
1451 cFYI(1, "bad length %d for count %d",
1452 data_length, count);
1453 rc = -EIO;
1454 *nbytes = 0;
1455 } else {
1456 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1457 le16_to_cpu(pSMBr->DataOffset);
1458 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1459 cERROR(1, "Faulting on read rc = %d",rc);
1460 rc = -EFAULT;
1461 }*/ /* can not use copy_to_user when using page cache*/
1462 if (*buf)
1463 memcpy(*buf, pReadData, data_length);
1467 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1468 if (*buf) {
1469 if (resp_buf_type == CIFS_SMALL_BUFFER)
1470 cifs_small_buf_release(iov[0].iov_base);
1471 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1472 cifs_buf_release(iov[0].iov_base);
1473 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1474 /* return buffer to caller to free */
1475 *buf = iov[0].iov_base;
1476 if (resp_buf_type == CIFS_SMALL_BUFFER)
1477 *pbuf_type = CIFS_SMALL_BUFFER;
1478 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1479 *pbuf_type = CIFS_LARGE_BUFFER;
1480 } /* else no valid buffer on return - leave as null */
1482 /* Note: On -EAGAIN error only caller can retry on handle based calls
1483 since file handle passed in no longer valid */
1484 return rc;
1489 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1490 const int netfid, const unsigned int count,
1491 const __u64 offset, unsigned int *nbytes, const char *buf,
1492 const char __user *ubuf, const int long_op)
1494 int rc = -EACCES;
1495 WRITE_REQ *pSMB = NULL;
1496 WRITE_RSP *pSMBr = NULL;
1497 int bytes_returned, wct;
1498 __u32 bytes_sent;
1499 __u16 byte_count;
1501 *nbytes = 0;
1503 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
1504 if (tcon->ses == NULL)
1505 return -ECONNABORTED;
1507 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1508 wct = 14;
1509 else {
1510 wct = 12;
1511 if ((offset >> 32) > 0) {
1512 /* can not handle big offset for old srv */
1513 return -EIO;
1517 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1518 (void **) &pSMBr);
1519 if (rc)
1520 return rc;
1521 /* tcon and ses pointer are checked in smb_init */
1522 if (tcon->ses->server == NULL)
1523 return -ECONNABORTED;
1525 pSMB->AndXCommand = 0xFF; /* none */
1526 pSMB->Fid = netfid;
1527 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1528 if (wct == 14)
1529 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1531 pSMB->Reserved = 0xFFFFFFFF;
1532 pSMB->WriteMode = 0;
1533 pSMB->Remaining = 0;
1535 /* Can increase buffer size if buffer is big enough in some cases ie we
1536 can send more if LARGE_WRITE_X capability returned by the server and if
1537 our buffer is big enough or if we convert to iovecs on socket writes
1538 and eliminate the copy to the CIFS buffer */
1539 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1540 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1541 } else {
1542 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1543 & ~0xFF;
1546 if (bytes_sent > count)
1547 bytes_sent = count;
1548 pSMB->DataOffset =
1549 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1550 if (buf)
1551 memcpy(pSMB->Data, buf, bytes_sent);
1552 else if (ubuf) {
1553 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1554 cifs_buf_release(pSMB);
1555 return -EFAULT;
1557 } else if (count != 0) {
1558 /* No buffer */
1559 cifs_buf_release(pSMB);
1560 return -EINVAL;
1561 } /* else setting file size with write of zero bytes */
1562 if (wct == 14)
1563 byte_count = bytes_sent + 1; /* pad */
1564 else /* wct == 12 */
1565 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1567 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1568 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1569 inc_rfc1001_len(pSMB, byte_count);
1571 if (wct == 14)
1572 pSMB->ByteCount = cpu_to_le16(byte_count);
1573 else { /* old style write has byte count 4 bytes earlier
1574 so 4 bytes pad */
1575 struct smb_com_writex_req *pSMBW =
1576 (struct smb_com_writex_req *)pSMB;
1577 pSMBW->ByteCount = cpu_to_le16(byte_count);
1580 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1581 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1582 cifs_stats_inc(&tcon->num_writes);
1583 if (rc) {
1584 cFYI(1, "Send error in write = %d", rc);
1585 } else {
1586 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1587 *nbytes = (*nbytes) << 16;
1588 *nbytes += le16_to_cpu(pSMBr->Count);
1591 * Mask off high 16 bits when bytes written as returned by the
1592 * server is greater than bytes requested by the client. Some
1593 * OS/2 servers are known to set incorrect CountHigh values.
1595 if (*nbytes > count)
1596 *nbytes &= 0xFFFF;
1599 cifs_buf_release(pSMB);
1601 /* Note: On -EAGAIN error only caller can retry on handle based calls
1602 since file handle passed in no longer valid */
1604 return rc;
1608 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1609 const int netfid, const unsigned int count,
1610 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1611 int n_vec, const int long_op)
1613 int rc = -EACCES;
1614 WRITE_REQ *pSMB = NULL;
1615 int wct;
1616 int smb_hdr_len;
1617 int resp_buf_type = 0;
1619 *nbytes = 0;
1621 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
1623 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1624 wct = 14;
1625 } else {
1626 wct = 12;
1627 if ((offset >> 32) > 0) {
1628 /* can not handle big offset for old srv */
1629 return -EIO;
1632 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1633 if (rc)
1634 return rc;
1635 /* tcon and ses pointer are checked in smb_init */
1636 if (tcon->ses->server == NULL)
1637 return -ECONNABORTED;
1639 pSMB->AndXCommand = 0xFF; /* none */
1640 pSMB->Fid = netfid;
1641 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1642 if (wct == 14)
1643 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1644 pSMB->Reserved = 0xFFFFFFFF;
1645 pSMB->WriteMode = 0;
1646 pSMB->Remaining = 0;
1648 pSMB->DataOffset =
1649 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1651 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1652 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1653 /* header + 1 byte pad */
1654 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
1655 if (wct == 14)
1656 inc_rfc1001_len(pSMB, count + 1);
1657 else /* wct == 12 */
1658 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
1659 if (wct == 14)
1660 pSMB->ByteCount = cpu_to_le16(count + 1);
1661 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1662 struct smb_com_writex_req *pSMBW =
1663 (struct smb_com_writex_req *)pSMB;
1664 pSMBW->ByteCount = cpu_to_le16(count + 5);
1666 iov[0].iov_base = pSMB;
1667 if (wct == 14)
1668 iov[0].iov_len = smb_hdr_len + 4;
1669 else /* wct == 12 pad bigger by four bytes */
1670 iov[0].iov_len = smb_hdr_len + 8;
1673 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1674 long_op);
1675 cifs_stats_inc(&tcon->num_writes);
1676 if (rc) {
1677 cFYI(1, "Send error Write2 = %d", rc);
1678 } else if (resp_buf_type == 0) {
1679 /* presumably this can not happen, but best to be safe */
1680 rc = -EIO;
1681 } else {
1682 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1683 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1684 *nbytes = (*nbytes) << 16;
1685 *nbytes += le16_to_cpu(pSMBr->Count);
1688 * Mask off high 16 bits when bytes written as returned by the
1689 * server is greater than bytes requested by the client. OS/2
1690 * servers are known to set incorrect CountHigh values.
1692 if (*nbytes > count)
1693 *nbytes &= 0xFFFF;
1696 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1697 if (resp_buf_type == CIFS_SMALL_BUFFER)
1698 cifs_small_buf_release(iov[0].iov_base);
1699 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1700 cifs_buf_release(iov[0].iov_base);
1702 /* Note: On -EAGAIN error only caller can retry on handle based calls
1703 since file handle passed in no longer valid */
1705 return rc;
1710 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1711 const __u16 smb_file_id, const __u64 len,
1712 const __u64 offset, const __u32 numUnlock,
1713 const __u32 numLock, const __u8 lockType,
1714 const bool waitFlag, const __u8 oplock_level)
1716 int rc = 0;
1717 LOCK_REQ *pSMB = NULL;
1718 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1719 int bytes_returned;
1720 int timeout = 0;
1721 __u16 count;
1723 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
1724 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1726 if (rc)
1727 return rc;
1729 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1730 timeout = CIFS_ASYNC_OP; /* no response expected */
1731 pSMB->Timeout = 0;
1732 } else if (waitFlag) {
1733 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1734 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1735 } else {
1736 pSMB->Timeout = 0;
1739 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1740 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1741 pSMB->LockType = lockType;
1742 pSMB->OplockLevel = oplock_level;
1743 pSMB->AndXCommand = 0xFF; /* none */
1744 pSMB->Fid = smb_file_id; /* netfid stays le */
1746 if ((numLock != 0) || (numUnlock != 0)) {
1747 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1748 /* BB where to store pid high? */
1749 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1750 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1751 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1752 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1753 count = sizeof(LOCKING_ANDX_RANGE);
1754 } else {
1755 /* oplock break */
1756 count = 0;
1758 inc_rfc1001_len(pSMB, count);
1759 pSMB->ByteCount = cpu_to_le16(count);
1761 if (waitFlag) {
1762 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1763 (struct smb_hdr *) pSMB, &bytes_returned);
1764 cifs_small_buf_release(pSMB);
1765 } else {
1766 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1767 timeout);
1768 /* SMB buffer freed by function above */
1770 cifs_stats_inc(&tcon->num_locks);
1771 if (rc)
1772 cFYI(1, "Send error in Lock = %d", rc);
1774 /* Note: On -EAGAIN error only caller can retry on handle based calls
1775 since file handle passed in no longer valid */
1776 return rc;
1780 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1781 const __u16 smb_file_id, const int get_flag, const __u64 len,
1782 struct file_lock *pLockData, const __u16 lock_type,
1783 const bool waitFlag)
1785 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1786 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1787 struct cifs_posix_lock *parm_data;
1788 int rc = 0;
1789 int timeout = 0;
1790 int bytes_returned = 0;
1791 int resp_buf_type = 0;
1792 __u16 params, param_offset, offset, byte_count, count;
1793 struct kvec iov[1];
1795 cFYI(1, "Posix Lock");
1797 if (pLockData == NULL)
1798 return -EINVAL;
1800 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1802 if (rc)
1803 return rc;
1805 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1807 params = 6;
1808 pSMB->MaxSetupCount = 0;
1809 pSMB->Reserved = 0;
1810 pSMB->Flags = 0;
1811 pSMB->Reserved2 = 0;
1812 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1813 offset = param_offset + params;
1815 count = sizeof(struct cifs_posix_lock);
1816 pSMB->MaxParameterCount = cpu_to_le16(2);
1817 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1818 pSMB->SetupCount = 1;
1819 pSMB->Reserved3 = 0;
1820 if (get_flag)
1821 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1822 else
1823 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1824 byte_count = 3 /* pad */ + params + count;
1825 pSMB->DataCount = cpu_to_le16(count);
1826 pSMB->ParameterCount = cpu_to_le16(params);
1827 pSMB->TotalDataCount = pSMB->DataCount;
1828 pSMB->TotalParameterCount = pSMB->ParameterCount;
1829 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1830 parm_data = (struct cifs_posix_lock *)
1831 (((char *) &pSMB->hdr.Protocol) + offset);
1833 parm_data->lock_type = cpu_to_le16(lock_type);
1834 if (waitFlag) {
1835 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1836 parm_data->lock_flags = cpu_to_le16(1);
1837 pSMB->Timeout = cpu_to_le32(-1);
1838 } else
1839 pSMB->Timeout = 0;
1841 parm_data->pid = cpu_to_le32(current->tgid);
1842 parm_data->start = cpu_to_le64(pLockData->fl_start);
1843 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1845 pSMB->DataOffset = cpu_to_le16(offset);
1846 pSMB->Fid = smb_file_id;
1847 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1848 pSMB->Reserved4 = 0;
1849 inc_rfc1001_len(pSMB, byte_count);
1850 pSMB->ByteCount = cpu_to_le16(byte_count);
1851 if (waitFlag) {
1852 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1853 (struct smb_hdr *) pSMBr, &bytes_returned);
1854 } else {
1855 iov[0].iov_base = (char *)pSMB;
1856 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
1857 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1858 &resp_buf_type, timeout);
1859 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1860 not try to free it twice below on exit */
1861 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1864 if (rc) {
1865 cFYI(1, "Send error in Posix Lock = %d", rc);
1866 } else if (get_flag) {
1867 /* lock structure can be returned on get */
1868 __u16 data_offset;
1869 __u16 data_count;
1870 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1872 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
1873 rc = -EIO; /* bad smb */
1874 goto plk_err_exit;
1876 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1877 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1878 if (data_count < sizeof(struct cifs_posix_lock)) {
1879 rc = -EIO;
1880 goto plk_err_exit;
1882 parm_data = (struct cifs_posix_lock *)
1883 ((char *)&pSMBr->hdr.Protocol + data_offset);
1884 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
1885 pLockData->fl_type = F_UNLCK;
1886 else {
1887 if (parm_data->lock_type ==
1888 __constant_cpu_to_le16(CIFS_RDLCK))
1889 pLockData->fl_type = F_RDLCK;
1890 else if (parm_data->lock_type ==
1891 __constant_cpu_to_le16(CIFS_WRLCK))
1892 pLockData->fl_type = F_WRLCK;
1894 pLockData->fl_start = le64_to_cpu(parm_data->start);
1895 pLockData->fl_end = pLockData->fl_start +
1896 le64_to_cpu(parm_data->length) - 1;
1897 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
1901 plk_err_exit:
1902 if (pSMB)
1903 cifs_small_buf_release(pSMB);
1905 if (resp_buf_type == CIFS_SMALL_BUFFER)
1906 cifs_small_buf_release(iov[0].iov_base);
1907 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1908 cifs_buf_release(iov[0].iov_base);
1910 /* Note: On -EAGAIN error only caller can retry on handle based calls
1911 since file handle passed in no longer valid */
1913 return rc;
1918 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1920 int rc = 0;
1921 CLOSE_REQ *pSMB = NULL;
1922 cFYI(1, "In CIFSSMBClose");
1924 /* do not retry on dead session on close */
1925 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1926 if (rc == -EAGAIN)
1927 return 0;
1928 if (rc)
1929 return rc;
1931 pSMB->FileID = (__u16) smb_file_id;
1932 pSMB->LastWriteTime = 0xFFFFFFFF;
1933 pSMB->ByteCount = 0;
1934 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1935 cifs_stats_inc(&tcon->num_closes);
1936 if (rc) {
1937 if (rc != -EINTR) {
1938 /* EINTR is expected when user ctl-c to kill app */
1939 cERROR(1, "Send error in Close = %d", rc);
1943 /* Since session is dead, file will be closed on server already */
1944 if (rc == -EAGAIN)
1945 rc = 0;
1947 return rc;
1951 CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1953 int rc = 0;
1954 FLUSH_REQ *pSMB = NULL;
1955 cFYI(1, "In CIFSSMBFlush");
1957 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1958 if (rc)
1959 return rc;
1961 pSMB->FileID = (__u16) smb_file_id;
1962 pSMB->ByteCount = 0;
1963 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1964 cifs_stats_inc(&tcon->num_flushes);
1965 if (rc)
1966 cERROR(1, "Send error in Flush = %d", rc);
1968 return rc;
1972 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1973 const char *fromName, const char *toName,
1974 const struct nls_table *nls_codepage, int remap)
1976 int rc = 0;
1977 RENAME_REQ *pSMB = NULL;
1978 RENAME_RSP *pSMBr = NULL;
1979 int bytes_returned;
1980 int name_len, name_len2;
1981 __u16 count;
1983 cFYI(1, "In CIFSSMBRename");
1984 renameRetry:
1985 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1986 (void **) &pSMBr);
1987 if (rc)
1988 return rc;
1990 pSMB->BufferFormat = 0x04;
1991 pSMB->SearchAttributes =
1992 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1993 ATTR_DIRECTORY);
1995 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1996 name_len =
1997 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1998 PATH_MAX, nls_codepage, remap);
1999 name_len++; /* trailing null */
2000 name_len *= 2;
2001 pSMB->OldFileName[name_len] = 0x04; /* pad */
2002 /* protocol requires ASCII signature byte on Unicode string */
2003 pSMB->OldFileName[name_len + 1] = 0x00;
2004 name_len2 =
2005 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2006 toName, PATH_MAX, nls_codepage, remap);
2007 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2008 name_len2 *= 2; /* convert to bytes */
2009 } else { /* BB improve the check for buffer overruns BB */
2010 name_len = strnlen(fromName, PATH_MAX);
2011 name_len++; /* trailing null */
2012 strncpy(pSMB->OldFileName, fromName, name_len);
2013 name_len2 = strnlen(toName, PATH_MAX);
2014 name_len2++; /* trailing null */
2015 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2016 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2017 name_len2++; /* trailing null */
2018 name_len2++; /* signature byte */
2021 count = 1 /* 1st signature byte */ + name_len + name_len2;
2022 inc_rfc1001_len(pSMB, count);
2023 pSMB->ByteCount = cpu_to_le16(count);
2025 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2026 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2027 cifs_stats_inc(&tcon->num_renames);
2028 if (rc)
2029 cFYI(1, "Send error in rename = %d", rc);
2031 cifs_buf_release(pSMB);
2033 if (rc == -EAGAIN)
2034 goto renameRetry;
2036 return rc;
2039 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2040 int netfid, const char *target_name,
2041 const struct nls_table *nls_codepage, int remap)
2043 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2044 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2045 struct set_file_rename *rename_info;
2046 char *data_offset;
2047 char dummy_string[30];
2048 int rc = 0;
2049 int bytes_returned = 0;
2050 int len_of_str;
2051 __u16 params, param_offset, offset, count, byte_count;
2053 cFYI(1, "Rename to File by handle");
2054 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2055 (void **) &pSMBr);
2056 if (rc)
2057 return rc;
2059 params = 6;
2060 pSMB->MaxSetupCount = 0;
2061 pSMB->Reserved = 0;
2062 pSMB->Flags = 0;
2063 pSMB->Timeout = 0;
2064 pSMB->Reserved2 = 0;
2065 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2066 offset = param_offset + params;
2068 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2069 rename_info = (struct set_file_rename *) data_offset;
2070 pSMB->MaxParameterCount = cpu_to_le16(2);
2071 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2072 pSMB->SetupCount = 1;
2073 pSMB->Reserved3 = 0;
2074 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2075 byte_count = 3 /* pad */ + params;
2076 pSMB->ParameterCount = cpu_to_le16(params);
2077 pSMB->TotalParameterCount = pSMB->ParameterCount;
2078 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2079 pSMB->DataOffset = cpu_to_le16(offset);
2080 /* construct random name ".cifs_tmp<inodenum><mid>" */
2081 rename_info->overwrite = cpu_to_le32(1);
2082 rename_info->root_fid = 0;
2083 /* unicode only call */
2084 if (target_name == NULL) {
2085 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2086 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2087 dummy_string, 24, nls_codepage, remap);
2088 } else {
2089 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2090 target_name, PATH_MAX, nls_codepage,
2091 remap);
2093 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2094 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2095 byte_count += count;
2096 pSMB->DataCount = cpu_to_le16(count);
2097 pSMB->TotalDataCount = pSMB->DataCount;
2098 pSMB->Fid = netfid;
2099 pSMB->InformationLevel =
2100 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2101 pSMB->Reserved4 = 0;
2102 inc_rfc1001_len(pSMB, byte_count);
2103 pSMB->ByteCount = cpu_to_le16(byte_count);
2104 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2105 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2106 cifs_stats_inc(&pTcon->num_t2renames);
2107 if (rc)
2108 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
2110 cifs_buf_release(pSMB);
2112 /* Note: On -EAGAIN error only caller can retry on handle based calls
2113 since file handle passed in no longer valid */
2115 return rc;
2119 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2120 const __u16 target_tid, const char *toName, const int flags,
2121 const struct nls_table *nls_codepage, int remap)
2123 int rc = 0;
2124 COPY_REQ *pSMB = NULL;
2125 COPY_RSP *pSMBr = NULL;
2126 int bytes_returned;
2127 int name_len, name_len2;
2128 __u16 count;
2130 cFYI(1, "In CIFSSMBCopy");
2131 copyRetry:
2132 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2133 (void **) &pSMBr);
2134 if (rc)
2135 return rc;
2137 pSMB->BufferFormat = 0x04;
2138 pSMB->Tid2 = target_tid;
2140 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2142 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2143 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2144 fromName, PATH_MAX, nls_codepage,
2145 remap);
2146 name_len++; /* trailing null */
2147 name_len *= 2;
2148 pSMB->OldFileName[name_len] = 0x04; /* pad */
2149 /* protocol requires ASCII signature byte on Unicode string */
2150 pSMB->OldFileName[name_len + 1] = 0x00;
2151 name_len2 =
2152 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2153 toName, PATH_MAX, nls_codepage, remap);
2154 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2155 name_len2 *= 2; /* convert to bytes */
2156 } else { /* BB improve the check for buffer overruns BB */
2157 name_len = strnlen(fromName, PATH_MAX);
2158 name_len++; /* trailing null */
2159 strncpy(pSMB->OldFileName, fromName, name_len);
2160 name_len2 = strnlen(toName, PATH_MAX);
2161 name_len2++; /* trailing null */
2162 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2163 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2164 name_len2++; /* trailing null */
2165 name_len2++; /* signature byte */
2168 count = 1 /* 1st signature byte */ + name_len + name_len2;
2169 inc_rfc1001_len(pSMB, count);
2170 pSMB->ByteCount = cpu_to_le16(count);
2172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2174 if (rc) {
2175 cFYI(1, "Send error in copy = %d with %d files copied",
2176 rc, le16_to_cpu(pSMBr->CopyCount));
2178 cifs_buf_release(pSMB);
2180 if (rc == -EAGAIN)
2181 goto copyRetry;
2183 return rc;
2187 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2188 const char *fromName, const char *toName,
2189 const struct nls_table *nls_codepage)
2191 TRANSACTION2_SPI_REQ *pSMB = NULL;
2192 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2193 char *data_offset;
2194 int name_len;
2195 int name_len_target;
2196 int rc = 0;
2197 int bytes_returned = 0;
2198 __u16 params, param_offset, offset, byte_count;
2200 cFYI(1, "In Symlink Unix style");
2201 createSymLinkRetry:
2202 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2203 (void **) &pSMBr);
2204 if (rc)
2205 return rc;
2207 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2208 name_len =
2209 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2210 /* find define for this maxpathcomponent */
2211 , nls_codepage);
2212 name_len++; /* trailing null */
2213 name_len *= 2;
2215 } else { /* BB improve the check for buffer overruns BB */
2216 name_len = strnlen(fromName, PATH_MAX);
2217 name_len++; /* trailing null */
2218 strncpy(pSMB->FileName, fromName, name_len);
2220 params = 6 + name_len;
2221 pSMB->MaxSetupCount = 0;
2222 pSMB->Reserved = 0;
2223 pSMB->Flags = 0;
2224 pSMB->Timeout = 0;
2225 pSMB->Reserved2 = 0;
2226 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2227 InformationLevel) - 4;
2228 offset = param_offset + params;
2230 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2231 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2232 name_len_target =
2233 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2234 /* find define for this maxpathcomponent */
2235 , nls_codepage);
2236 name_len_target++; /* trailing null */
2237 name_len_target *= 2;
2238 } else { /* BB improve the check for buffer overruns BB */
2239 name_len_target = strnlen(toName, PATH_MAX);
2240 name_len_target++; /* trailing null */
2241 strncpy(data_offset, toName, name_len_target);
2244 pSMB->MaxParameterCount = cpu_to_le16(2);
2245 /* BB find exact max on data count below from sess */
2246 pSMB->MaxDataCount = cpu_to_le16(1000);
2247 pSMB->SetupCount = 1;
2248 pSMB->Reserved3 = 0;
2249 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2250 byte_count = 3 /* pad */ + params + name_len_target;
2251 pSMB->DataCount = cpu_to_le16(name_len_target);
2252 pSMB->ParameterCount = cpu_to_le16(params);
2253 pSMB->TotalDataCount = pSMB->DataCount;
2254 pSMB->TotalParameterCount = pSMB->ParameterCount;
2255 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2256 pSMB->DataOffset = cpu_to_le16(offset);
2257 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2258 pSMB->Reserved4 = 0;
2259 inc_rfc1001_len(pSMB, byte_count);
2260 pSMB->ByteCount = cpu_to_le16(byte_count);
2261 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2262 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2263 cifs_stats_inc(&tcon->num_symlinks);
2264 if (rc)
2265 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
2267 cifs_buf_release(pSMB);
2269 if (rc == -EAGAIN)
2270 goto createSymLinkRetry;
2272 return rc;
2276 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2277 const char *fromName, const char *toName,
2278 const struct nls_table *nls_codepage, int remap)
2280 TRANSACTION2_SPI_REQ *pSMB = NULL;
2281 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2282 char *data_offset;
2283 int name_len;
2284 int name_len_target;
2285 int rc = 0;
2286 int bytes_returned = 0;
2287 __u16 params, param_offset, offset, byte_count;
2289 cFYI(1, "In Create Hard link Unix style");
2290 createHardLinkRetry:
2291 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2292 (void **) &pSMBr);
2293 if (rc)
2294 return rc;
2296 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2297 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2298 PATH_MAX, nls_codepage, remap);
2299 name_len++; /* trailing null */
2300 name_len *= 2;
2302 } else { /* BB improve the check for buffer overruns BB */
2303 name_len = strnlen(toName, PATH_MAX);
2304 name_len++; /* trailing null */
2305 strncpy(pSMB->FileName, toName, name_len);
2307 params = 6 + name_len;
2308 pSMB->MaxSetupCount = 0;
2309 pSMB->Reserved = 0;
2310 pSMB->Flags = 0;
2311 pSMB->Timeout = 0;
2312 pSMB->Reserved2 = 0;
2313 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2314 InformationLevel) - 4;
2315 offset = param_offset + params;
2317 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2318 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2319 name_len_target =
2320 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2321 nls_codepage, remap);
2322 name_len_target++; /* trailing null */
2323 name_len_target *= 2;
2324 } else { /* BB improve the check for buffer overruns BB */
2325 name_len_target = strnlen(fromName, PATH_MAX);
2326 name_len_target++; /* trailing null */
2327 strncpy(data_offset, fromName, name_len_target);
2330 pSMB->MaxParameterCount = cpu_to_le16(2);
2331 /* BB find exact max on data count below from sess*/
2332 pSMB->MaxDataCount = cpu_to_le16(1000);
2333 pSMB->SetupCount = 1;
2334 pSMB->Reserved3 = 0;
2335 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2336 byte_count = 3 /* pad */ + params + name_len_target;
2337 pSMB->ParameterCount = cpu_to_le16(params);
2338 pSMB->TotalParameterCount = pSMB->ParameterCount;
2339 pSMB->DataCount = cpu_to_le16(name_len_target);
2340 pSMB->TotalDataCount = pSMB->DataCount;
2341 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2342 pSMB->DataOffset = cpu_to_le16(offset);
2343 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2344 pSMB->Reserved4 = 0;
2345 inc_rfc1001_len(pSMB, byte_count);
2346 pSMB->ByteCount = cpu_to_le16(byte_count);
2347 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2348 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2349 cifs_stats_inc(&tcon->num_hardlinks);
2350 if (rc)
2351 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
2353 cifs_buf_release(pSMB);
2354 if (rc == -EAGAIN)
2355 goto createHardLinkRetry;
2357 return rc;
2361 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2362 const char *fromName, const char *toName,
2363 const struct nls_table *nls_codepage, int remap)
2365 int rc = 0;
2366 NT_RENAME_REQ *pSMB = NULL;
2367 RENAME_RSP *pSMBr = NULL;
2368 int bytes_returned;
2369 int name_len, name_len2;
2370 __u16 count;
2372 cFYI(1, "In CIFSCreateHardLink");
2373 winCreateHardLinkRetry:
2375 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2376 (void **) &pSMBr);
2377 if (rc)
2378 return rc;
2380 pSMB->SearchAttributes =
2381 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2382 ATTR_DIRECTORY);
2383 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2384 pSMB->ClusterCount = 0;
2386 pSMB->BufferFormat = 0x04;
2388 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2389 name_len =
2390 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2391 PATH_MAX, nls_codepage, remap);
2392 name_len++; /* trailing null */
2393 name_len *= 2;
2395 /* protocol specifies ASCII buffer format (0x04) for unicode */
2396 pSMB->OldFileName[name_len] = 0x04;
2397 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2398 name_len2 =
2399 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2400 toName, PATH_MAX, nls_codepage, remap);
2401 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2402 name_len2 *= 2; /* convert to bytes */
2403 } else { /* BB improve the check for buffer overruns BB */
2404 name_len = strnlen(fromName, PATH_MAX);
2405 name_len++; /* trailing null */
2406 strncpy(pSMB->OldFileName, fromName, name_len);
2407 name_len2 = strnlen(toName, PATH_MAX);
2408 name_len2++; /* trailing null */
2409 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2410 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2411 name_len2++; /* trailing null */
2412 name_len2++; /* signature byte */
2415 count = 1 /* string type byte */ + name_len + name_len2;
2416 inc_rfc1001_len(pSMB, count);
2417 pSMB->ByteCount = cpu_to_le16(count);
2419 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2420 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2421 cifs_stats_inc(&tcon->num_hardlinks);
2422 if (rc)
2423 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
2425 cifs_buf_release(pSMB);
2426 if (rc == -EAGAIN)
2427 goto winCreateHardLinkRetry;
2429 return rc;
2433 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2434 const unsigned char *searchName, char **symlinkinfo,
2435 const struct nls_table *nls_codepage)
2437 /* SMB_QUERY_FILE_UNIX_LINK */
2438 TRANSACTION2_QPI_REQ *pSMB = NULL;
2439 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2440 int rc = 0;
2441 int bytes_returned;
2442 int name_len;
2443 __u16 params, byte_count;
2444 char *data_start;
2446 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
2448 querySymLinkRetry:
2449 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2450 (void **) &pSMBr);
2451 if (rc)
2452 return rc;
2454 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2455 name_len =
2456 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2457 PATH_MAX, nls_codepage);
2458 name_len++; /* trailing null */
2459 name_len *= 2;
2460 } else { /* BB improve the check for buffer overruns BB */
2461 name_len = strnlen(searchName, PATH_MAX);
2462 name_len++; /* trailing null */
2463 strncpy(pSMB->FileName, searchName, name_len);
2466 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2467 pSMB->TotalDataCount = 0;
2468 pSMB->MaxParameterCount = cpu_to_le16(2);
2469 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
2470 pSMB->MaxSetupCount = 0;
2471 pSMB->Reserved = 0;
2472 pSMB->Flags = 0;
2473 pSMB->Timeout = 0;
2474 pSMB->Reserved2 = 0;
2475 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2476 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2477 pSMB->DataCount = 0;
2478 pSMB->DataOffset = 0;
2479 pSMB->SetupCount = 1;
2480 pSMB->Reserved3 = 0;
2481 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2482 byte_count = params + 1 /* pad */ ;
2483 pSMB->TotalParameterCount = cpu_to_le16(params);
2484 pSMB->ParameterCount = pSMB->TotalParameterCount;
2485 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2486 pSMB->Reserved4 = 0;
2487 inc_rfc1001_len(pSMB, byte_count);
2488 pSMB->ByteCount = cpu_to_le16(byte_count);
2490 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2491 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2492 if (rc) {
2493 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
2494 } else {
2495 /* decode response */
2497 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2498 /* BB also check enough total bytes returned */
2499 if (rc || get_bcc(&pSMBr->hdr) < 2)
2500 rc = -EIO;
2501 else {
2502 bool is_unicode;
2503 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2505 data_start = ((char *) &pSMBr->hdr.Protocol) +
2506 le16_to_cpu(pSMBr->t2.DataOffset);
2508 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2509 is_unicode = true;
2510 else
2511 is_unicode = false;
2513 /* BB FIXME investigate remapping reserved chars here */
2514 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
2515 is_unicode, nls_codepage);
2516 if (!*symlinkinfo)
2517 rc = -ENOMEM;
2520 cifs_buf_release(pSMB);
2521 if (rc == -EAGAIN)
2522 goto querySymLinkRetry;
2523 return rc;
2526 #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
2528 * Recent Windows versions now create symlinks more frequently
2529 * and they use the "reparse point" mechanism below. We can of course
2530 * do symlinks nicely to Samba and other servers which support the
2531 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2532 * "MF" symlinks optionally, but for recent Windows we really need to
2533 * reenable the code below and fix the cifs_symlink callers to handle this.
2534 * In the interim this code has been moved to its own config option so
2535 * it is not compiled in by default until callers fixed up and more tested.
2538 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2539 const unsigned char *searchName,
2540 char *symlinkinfo, const int buflen, __u16 fid,
2541 const struct nls_table *nls_codepage)
2543 int rc = 0;
2544 int bytes_returned;
2545 struct smb_com_transaction_ioctl_req *pSMB;
2546 struct smb_com_transaction_ioctl_rsp *pSMBr;
2548 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
2549 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2550 (void **) &pSMBr);
2551 if (rc)
2552 return rc;
2554 pSMB->TotalParameterCount = 0 ;
2555 pSMB->TotalDataCount = 0;
2556 pSMB->MaxParameterCount = cpu_to_le32(2);
2557 /* BB find exact data count max from sess structure BB */
2558 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2559 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2560 pSMB->MaxSetupCount = 4;
2561 pSMB->Reserved = 0;
2562 pSMB->ParameterOffset = 0;
2563 pSMB->DataCount = 0;
2564 pSMB->DataOffset = 0;
2565 pSMB->SetupCount = 4;
2566 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2567 pSMB->ParameterCount = pSMB->TotalParameterCount;
2568 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2569 pSMB->IsFsctl = 1; /* FSCTL */
2570 pSMB->IsRootFlag = 0;
2571 pSMB->Fid = fid; /* file handle always le */
2572 pSMB->ByteCount = 0;
2574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2575 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2576 if (rc) {
2577 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
2578 } else { /* decode response */
2579 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2580 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2581 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
2582 /* BB also check enough total bytes returned */
2583 rc = -EIO; /* bad smb */
2584 goto qreparse_out;
2586 if (data_count && (data_count < 2048)) {
2587 char *end_of_smb = 2 /* sizeof byte count */ +
2588 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
2590 struct reparse_data *reparse_buf =
2591 (struct reparse_data *)
2592 ((char *)&pSMBr->hdr.Protocol
2593 + data_offset);
2594 if ((char *)reparse_buf >= end_of_smb) {
2595 rc = -EIO;
2596 goto qreparse_out;
2598 if ((reparse_buf->LinkNamesBuf +
2599 reparse_buf->TargetNameOffset +
2600 reparse_buf->TargetNameLen) > end_of_smb) {
2601 cFYI(1, "reparse buf beyond SMB");
2602 rc = -EIO;
2603 goto qreparse_out;
2606 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2607 cifs_from_ucs2(symlinkinfo, (__le16 *)
2608 (reparse_buf->LinkNamesBuf +
2609 reparse_buf->TargetNameOffset),
2610 buflen,
2611 reparse_buf->TargetNameLen,
2612 nls_codepage, 0);
2613 } else { /* ASCII names */
2614 strncpy(symlinkinfo,
2615 reparse_buf->LinkNamesBuf +
2616 reparse_buf->TargetNameOffset,
2617 min_t(const int, buflen,
2618 reparse_buf->TargetNameLen));
2620 } else {
2621 rc = -EIO;
2622 cFYI(1, "Invalid return data count on "
2623 "get reparse info ioctl");
2625 symlinkinfo[buflen] = 0; /* just in case so the caller
2626 does not go off the end of the buffer */
2627 cFYI(1, "readlink result - %s", symlinkinfo);
2630 qreparse_out:
2631 cifs_buf_release(pSMB);
2633 /* Note: On -EAGAIN error only caller can retry on handle based calls
2634 since file handle passed in no longer valid */
2636 return rc;
2638 #endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
2640 #ifdef CONFIG_CIFS_POSIX
2642 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2643 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2644 struct cifs_posix_ace *cifs_ace)
2646 /* u8 cifs fields do not need le conversion */
2647 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2648 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2649 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2650 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
2652 return;
2655 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2656 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2657 const int acl_type, const int size_of_data_area)
2659 int size = 0;
2660 int i;
2661 __u16 count;
2662 struct cifs_posix_ace *pACE;
2663 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2664 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2666 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2667 return -EOPNOTSUPP;
2669 if (acl_type & ACL_TYPE_ACCESS) {
2670 count = le16_to_cpu(cifs_acl->access_entry_count);
2671 pACE = &cifs_acl->ace_array[0];
2672 size = sizeof(struct cifs_posix_acl);
2673 size += sizeof(struct cifs_posix_ace) * count;
2674 /* check if we would go beyond end of SMB */
2675 if (size_of_data_area < size) {
2676 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2677 size_of_data_area, size);
2678 return -EINVAL;
2680 } else if (acl_type & ACL_TYPE_DEFAULT) {
2681 count = le16_to_cpu(cifs_acl->access_entry_count);
2682 size = sizeof(struct cifs_posix_acl);
2683 size += sizeof(struct cifs_posix_ace) * count;
2684 /* skip past access ACEs to get to default ACEs */
2685 pACE = &cifs_acl->ace_array[count];
2686 count = le16_to_cpu(cifs_acl->default_entry_count);
2687 size += sizeof(struct cifs_posix_ace) * count;
2688 /* check if we would go beyond end of SMB */
2689 if (size_of_data_area < size)
2690 return -EINVAL;
2691 } else {
2692 /* illegal type */
2693 return -EINVAL;
2696 size = posix_acl_xattr_size(count);
2697 if ((buflen == 0) || (local_acl == NULL)) {
2698 /* used to query ACL EA size */
2699 } else if (size > buflen) {
2700 return -ERANGE;
2701 } else /* buffer big enough */ {
2702 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2703 for (i = 0; i < count ; i++) {
2704 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2705 pACE++;
2708 return size;
2711 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2712 const posix_acl_xattr_entry *local_ace)
2714 __u16 rc = 0; /* 0 = ACL converted ok */
2716 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2717 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2718 /* BB is there a better way to handle the large uid? */
2719 if (local_ace->e_id == cpu_to_le32(-1)) {
2720 /* Probably no need to le convert -1 on any arch but can not hurt */
2721 cifs_ace->cifs_uid = cpu_to_le64(-1);
2722 } else
2723 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2724 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
2725 return rc;
2728 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2729 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2730 const int buflen, const int acl_type)
2732 __u16 rc = 0;
2733 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2734 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2735 int count;
2736 int i;
2738 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2739 return 0;
2741 count = posix_acl_xattr_count((size_t)buflen);
2742 cFYI(1, "setting acl with %d entries from buf of length %d and "
2743 "version of %d",
2744 count, buflen, le32_to_cpu(local_acl->a_version));
2745 if (le32_to_cpu(local_acl->a_version) != 2) {
2746 cFYI(1, "unknown POSIX ACL version %d",
2747 le32_to_cpu(local_acl->a_version));
2748 return 0;
2750 cifs_acl->version = cpu_to_le16(1);
2751 if (acl_type == ACL_TYPE_ACCESS)
2752 cifs_acl->access_entry_count = cpu_to_le16(count);
2753 else if (acl_type == ACL_TYPE_DEFAULT)
2754 cifs_acl->default_entry_count = cpu_to_le16(count);
2755 else {
2756 cFYI(1, "unknown ACL type %d", acl_type);
2757 return 0;
2759 for (i = 0; i < count; i++) {
2760 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2761 &local_acl->a_entries[i]);
2762 if (rc != 0) {
2763 /* ACE not converted */
2764 break;
2767 if (rc == 0) {
2768 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2769 rc += sizeof(struct cifs_posix_acl);
2770 /* BB add check to make sure ACL does not overflow SMB */
2772 return rc;
2776 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2777 const unsigned char *searchName,
2778 char *acl_inf, const int buflen, const int acl_type,
2779 const struct nls_table *nls_codepage, int remap)
2781 /* SMB_QUERY_POSIX_ACL */
2782 TRANSACTION2_QPI_REQ *pSMB = NULL;
2783 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2784 int rc = 0;
2785 int bytes_returned;
2786 int name_len;
2787 __u16 params, byte_count;
2789 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
2791 queryAclRetry:
2792 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2793 (void **) &pSMBr);
2794 if (rc)
2795 return rc;
2797 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2798 name_len =
2799 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2800 PATH_MAX, nls_codepage, remap);
2801 name_len++; /* trailing null */
2802 name_len *= 2;
2803 pSMB->FileName[name_len] = 0;
2804 pSMB->FileName[name_len+1] = 0;
2805 } else { /* BB improve the check for buffer overruns BB */
2806 name_len = strnlen(searchName, PATH_MAX);
2807 name_len++; /* trailing null */
2808 strncpy(pSMB->FileName, searchName, name_len);
2811 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2812 pSMB->TotalDataCount = 0;
2813 pSMB->MaxParameterCount = cpu_to_le16(2);
2814 /* BB find exact max data count below from sess structure BB */
2815 pSMB->MaxDataCount = cpu_to_le16(4000);
2816 pSMB->MaxSetupCount = 0;
2817 pSMB->Reserved = 0;
2818 pSMB->Flags = 0;
2819 pSMB->Timeout = 0;
2820 pSMB->Reserved2 = 0;
2821 pSMB->ParameterOffset = cpu_to_le16(
2822 offsetof(struct smb_com_transaction2_qpi_req,
2823 InformationLevel) - 4);
2824 pSMB->DataCount = 0;
2825 pSMB->DataOffset = 0;
2826 pSMB->SetupCount = 1;
2827 pSMB->Reserved3 = 0;
2828 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2829 byte_count = params + 1 /* pad */ ;
2830 pSMB->TotalParameterCount = cpu_to_le16(params);
2831 pSMB->ParameterCount = pSMB->TotalParameterCount;
2832 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2833 pSMB->Reserved4 = 0;
2834 inc_rfc1001_len(pSMB, byte_count);
2835 pSMB->ByteCount = cpu_to_le16(byte_count);
2837 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2838 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2839 cifs_stats_inc(&tcon->num_acl_get);
2840 if (rc) {
2841 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
2842 } else {
2843 /* decode response */
2845 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2846 /* BB also check enough total bytes returned */
2847 if (rc || get_bcc(&pSMBr->hdr) < 2)
2848 rc = -EIO; /* bad smb */
2849 else {
2850 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2851 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2852 rc = cifs_copy_posix_acl(acl_inf,
2853 (char *)&pSMBr->hdr.Protocol+data_offset,
2854 buflen, acl_type, count);
2857 cifs_buf_release(pSMB);
2858 if (rc == -EAGAIN)
2859 goto queryAclRetry;
2860 return rc;
2864 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2865 const unsigned char *fileName,
2866 const char *local_acl, const int buflen,
2867 const int acl_type,
2868 const struct nls_table *nls_codepage, int remap)
2870 struct smb_com_transaction2_spi_req *pSMB = NULL;
2871 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2872 char *parm_data;
2873 int name_len;
2874 int rc = 0;
2875 int bytes_returned = 0;
2876 __u16 params, byte_count, data_count, param_offset, offset;
2878 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
2879 setAclRetry:
2880 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2881 (void **) &pSMBr);
2882 if (rc)
2883 return rc;
2884 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2885 name_len =
2886 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2887 PATH_MAX, nls_codepage, remap);
2888 name_len++; /* trailing null */
2889 name_len *= 2;
2890 } else { /* BB improve the check for buffer overruns BB */
2891 name_len = strnlen(fileName, PATH_MAX);
2892 name_len++; /* trailing null */
2893 strncpy(pSMB->FileName, fileName, name_len);
2895 params = 6 + name_len;
2896 pSMB->MaxParameterCount = cpu_to_le16(2);
2897 /* BB find max SMB size from sess */
2898 pSMB->MaxDataCount = cpu_to_le16(1000);
2899 pSMB->MaxSetupCount = 0;
2900 pSMB->Reserved = 0;
2901 pSMB->Flags = 0;
2902 pSMB->Timeout = 0;
2903 pSMB->Reserved2 = 0;
2904 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2905 InformationLevel) - 4;
2906 offset = param_offset + params;
2907 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2908 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2910 /* convert to on the wire format for POSIX ACL */
2911 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2913 if (data_count == 0) {
2914 rc = -EOPNOTSUPP;
2915 goto setACLerrorExit;
2917 pSMB->DataOffset = cpu_to_le16(offset);
2918 pSMB->SetupCount = 1;
2919 pSMB->Reserved3 = 0;
2920 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2921 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2922 byte_count = 3 /* pad */ + params + data_count;
2923 pSMB->DataCount = cpu_to_le16(data_count);
2924 pSMB->TotalDataCount = pSMB->DataCount;
2925 pSMB->ParameterCount = cpu_to_le16(params);
2926 pSMB->TotalParameterCount = pSMB->ParameterCount;
2927 pSMB->Reserved4 = 0;
2928 inc_rfc1001_len(pSMB, byte_count);
2929 pSMB->ByteCount = cpu_to_le16(byte_count);
2930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2932 if (rc)
2933 cFYI(1, "Set POSIX ACL returned %d", rc);
2935 setACLerrorExit:
2936 cifs_buf_release(pSMB);
2937 if (rc == -EAGAIN)
2938 goto setAclRetry;
2939 return rc;
2942 /* BB fix tabs in this function FIXME BB */
2944 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2945 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2947 int rc = 0;
2948 struct smb_t2_qfi_req *pSMB = NULL;
2949 struct smb_t2_qfi_rsp *pSMBr = NULL;
2950 int bytes_returned;
2951 __u16 params, byte_count;
2953 cFYI(1, "In GetExtAttr");
2954 if (tcon == NULL)
2955 return -ENODEV;
2957 GetExtAttrRetry:
2958 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2959 (void **) &pSMBr);
2960 if (rc)
2961 return rc;
2963 params = 2 /* level */ + 2 /* fid */;
2964 pSMB->t2.TotalDataCount = 0;
2965 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2966 /* BB find exact max data count below from sess structure BB */
2967 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2968 pSMB->t2.MaxSetupCount = 0;
2969 pSMB->t2.Reserved = 0;
2970 pSMB->t2.Flags = 0;
2971 pSMB->t2.Timeout = 0;
2972 pSMB->t2.Reserved2 = 0;
2973 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2974 Fid) - 4);
2975 pSMB->t2.DataCount = 0;
2976 pSMB->t2.DataOffset = 0;
2977 pSMB->t2.SetupCount = 1;
2978 pSMB->t2.Reserved3 = 0;
2979 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2980 byte_count = params + 1 /* pad */ ;
2981 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2982 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2983 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2984 pSMB->Pad = 0;
2985 pSMB->Fid = netfid;
2986 inc_rfc1001_len(pSMB, byte_count);
2987 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2989 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2990 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2991 if (rc) {
2992 cFYI(1, "error %d in GetExtAttr", rc);
2993 } else {
2994 /* decode response */
2995 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2996 /* BB also check enough total bytes returned */
2997 if (rc || get_bcc(&pSMBr->hdr) < 2)
2998 /* If rc should we check for EOPNOSUPP and
2999 disable the srvino flag? or in caller? */
3000 rc = -EIO; /* bad smb */
3001 else {
3002 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3003 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3004 struct file_chattr_info *pfinfo;
3005 /* BB Do we need a cast or hash here ? */
3006 if (count != 16) {
3007 cFYI(1, "Illegal size ret in GetExtAttr");
3008 rc = -EIO;
3009 goto GetExtAttrOut;
3011 pfinfo = (struct file_chattr_info *)
3012 (data_offset + (char *) &pSMBr->hdr.Protocol);
3013 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3014 *pMask = le64_to_cpu(pfinfo->mask);
3017 GetExtAttrOut:
3018 cifs_buf_release(pSMB);
3019 if (rc == -EAGAIN)
3020 goto GetExtAttrRetry;
3021 return rc;
3024 #endif /* CONFIG_POSIX */
3026 #ifdef CONFIG_CIFS_ACL
3028 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3029 * all NT TRANSACTS that we init here have total parm and data under about 400
3030 * bytes (to fit in small cifs buffer size), which is the case so far, it
3031 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3032 * returned setup area) and MaxParameterCount (returned parms size) must be set
3033 * by caller
3035 static int
3036 smb_init_nttransact(const __u16 sub_command, const int setup_count,
3037 const int parm_len, struct cifsTconInfo *tcon,
3038 void **ret_buf)
3040 int rc;
3041 __u32 temp_offset;
3042 struct smb_com_ntransact_req *pSMB;
3044 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3045 (void **)&pSMB);
3046 if (rc)
3047 return rc;
3048 *ret_buf = (void *)pSMB;
3049 pSMB->Reserved = 0;
3050 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3051 pSMB->TotalDataCount = 0;
3052 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3053 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3054 pSMB->ParameterCount = pSMB->TotalParameterCount;
3055 pSMB->DataCount = pSMB->TotalDataCount;
3056 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3057 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3058 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3059 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3060 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3061 pSMB->SubCommand = cpu_to_le16(sub_command);
3062 return 0;
3065 static int
3066 validate_ntransact(char *buf, char **ppparm, char **ppdata,
3067 __u32 *pparmlen, __u32 *pdatalen)
3069 char *end_of_smb;
3070 __u32 data_count, data_offset, parm_count, parm_offset;
3071 struct smb_com_ntransact_rsp *pSMBr;
3072 u16 bcc;
3074 *pdatalen = 0;
3075 *pparmlen = 0;
3077 if (buf == NULL)
3078 return -EINVAL;
3080 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3082 bcc = get_bcc(&pSMBr->hdr);
3083 end_of_smb = 2 /* sizeof byte count */ + bcc +
3084 (char *)&pSMBr->ByteCount;
3086 data_offset = le32_to_cpu(pSMBr->DataOffset);
3087 data_count = le32_to_cpu(pSMBr->DataCount);
3088 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3089 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3091 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3092 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3094 /* should we also check that parm and data areas do not overlap? */
3095 if (*ppparm > end_of_smb) {
3096 cFYI(1, "parms start after end of smb");
3097 return -EINVAL;
3098 } else if (parm_count + *ppparm > end_of_smb) {
3099 cFYI(1, "parm end after end of smb");
3100 return -EINVAL;
3101 } else if (*ppdata > end_of_smb) {
3102 cFYI(1, "data starts after end of smb");
3103 return -EINVAL;
3104 } else if (data_count + *ppdata > end_of_smb) {
3105 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3106 *ppdata, data_count, (data_count + *ppdata),
3107 end_of_smb, pSMBr);
3108 return -EINVAL;
3109 } else if (parm_count + data_count > bcc) {
3110 cFYI(1, "parm count and data count larger than SMB");
3111 return -EINVAL;
3113 *pdatalen = data_count;
3114 *pparmlen = parm_count;
3115 return 0;
3118 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3120 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3121 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3123 int rc = 0;
3124 int buf_type = 0;
3125 QUERY_SEC_DESC_REQ *pSMB;
3126 struct kvec iov[1];
3128 cFYI(1, "GetCifsACL");
3130 *pbuflen = 0;
3131 *acl_inf = NULL;
3133 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3134 8 /* parm len */, tcon, (void **) &pSMB);
3135 if (rc)
3136 return rc;
3138 pSMB->MaxParameterCount = cpu_to_le32(4);
3139 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3140 pSMB->MaxSetupCount = 0;
3141 pSMB->Fid = fid; /* file handle always le */
3142 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3143 CIFS_ACL_DACL);
3144 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3145 inc_rfc1001_len(pSMB, 11);
3146 iov[0].iov_base = (char *)pSMB;
3147 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
3149 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3151 cifs_stats_inc(&tcon->num_acl_get);
3152 if (rc) {
3153 cFYI(1, "Send error in QuerySecDesc = %d", rc);
3154 } else { /* decode response */
3155 __le32 *parm;
3156 __u32 parm_len;
3157 __u32 acl_len;
3158 struct smb_com_ntransact_rsp *pSMBr;
3159 char *pdata;
3161 /* validate_nttransact */
3162 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3163 &pdata, &parm_len, pbuflen);
3164 if (rc)
3165 goto qsec_out;
3166 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3168 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
3170 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3171 rc = -EIO; /* bad smb */
3172 *pbuflen = 0;
3173 goto qsec_out;
3176 /* BB check that data area is minimum length and as big as acl_len */
3178 acl_len = le32_to_cpu(*parm);
3179 if (acl_len != *pbuflen) {
3180 cERROR(1, "acl length %d does not match %d",
3181 acl_len, *pbuflen);
3182 if (*pbuflen > acl_len)
3183 *pbuflen = acl_len;
3186 /* check if buffer is big enough for the acl
3187 header followed by the smallest SID */
3188 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3189 (*pbuflen >= 64 * 1024)) {
3190 cERROR(1, "bad acl length %d", *pbuflen);
3191 rc = -EINVAL;
3192 *pbuflen = 0;
3193 } else {
3194 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3195 if (*acl_inf == NULL) {
3196 *pbuflen = 0;
3197 rc = -ENOMEM;
3199 memcpy(*acl_inf, pdata, *pbuflen);
3202 qsec_out:
3203 if (buf_type == CIFS_SMALL_BUFFER)
3204 cifs_small_buf_release(iov[0].iov_base);
3205 else if (buf_type == CIFS_LARGE_BUFFER)
3206 cifs_buf_release(iov[0].iov_base);
3207 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3208 return rc;
3212 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3213 struct cifs_ntsd *pntsd, __u32 acllen)
3215 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3216 int rc = 0;
3217 int bytes_returned = 0;
3218 SET_SEC_DESC_REQ *pSMB = NULL;
3219 NTRANSACT_RSP *pSMBr = NULL;
3221 setCifsAclRetry:
3222 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3223 (void **) &pSMBr);
3224 if (rc)
3225 return (rc);
3227 pSMB->MaxSetupCount = 0;
3228 pSMB->Reserved = 0;
3230 param_count = 8;
3231 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3232 data_count = acllen;
3233 data_offset = param_offset + param_count;
3234 byte_count = 3 /* pad */ + param_count;
3236 pSMB->DataCount = cpu_to_le32(data_count);
3237 pSMB->TotalDataCount = pSMB->DataCount;
3238 pSMB->MaxParameterCount = cpu_to_le32(4);
3239 pSMB->MaxDataCount = cpu_to_le32(16384);
3240 pSMB->ParameterCount = cpu_to_le32(param_count);
3241 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3242 pSMB->TotalParameterCount = pSMB->ParameterCount;
3243 pSMB->DataOffset = cpu_to_le32(data_offset);
3244 pSMB->SetupCount = 0;
3245 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3246 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3248 pSMB->Fid = fid; /* file handle always le */
3249 pSMB->Reserved2 = 0;
3250 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3252 if (pntsd && acllen) {
3253 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3254 (char *) pntsd,
3255 acllen);
3256 inc_rfc1001_len(pSMB, byte_count + data_count);
3257 } else
3258 inc_rfc1001_len(pSMB, byte_count);
3260 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3261 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3263 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
3264 if (rc)
3265 cFYI(1, "Set CIFS ACL returned %d", rc);
3266 cifs_buf_release(pSMB);
3268 if (rc == -EAGAIN)
3269 goto setCifsAclRetry;
3271 return (rc);
3274 #endif /* CONFIG_CIFS_ACL */
3276 /* Legacy Query Path Information call for lookup to old servers such
3277 as Win9x/WinME */
3278 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3279 const unsigned char *searchName,
3280 FILE_ALL_INFO *pFinfo,
3281 const struct nls_table *nls_codepage, int remap)
3283 QUERY_INFORMATION_REQ *pSMB;
3284 QUERY_INFORMATION_RSP *pSMBr;
3285 int rc = 0;
3286 int bytes_returned;
3287 int name_len;
3289 cFYI(1, "In SMBQPath path %s", searchName);
3290 QInfRetry:
3291 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3292 (void **) &pSMBr);
3293 if (rc)
3294 return rc;
3296 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3297 name_len =
3298 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3299 PATH_MAX, nls_codepage, remap);
3300 name_len++; /* trailing null */
3301 name_len *= 2;
3302 } else {
3303 name_len = strnlen(searchName, PATH_MAX);
3304 name_len++; /* trailing null */
3305 strncpy(pSMB->FileName, searchName, name_len);
3307 pSMB->BufferFormat = 0x04;
3308 name_len++; /* account for buffer type byte */
3309 inc_rfc1001_len(pSMB, (__u16)name_len);
3310 pSMB->ByteCount = cpu_to_le16(name_len);
3312 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3313 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3314 if (rc) {
3315 cFYI(1, "Send error in QueryInfo = %d", rc);
3316 } else if (pFinfo) {
3317 struct timespec ts;
3318 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3320 /* decode response */
3321 /* BB FIXME - add time zone adjustment BB */
3322 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3323 ts.tv_nsec = 0;
3324 ts.tv_sec = time;
3325 /* decode time fields */
3326 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3327 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3328 pFinfo->LastAccessTime = 0;
3329 pFinfo->AllocationSize =
3330 cpu_to_le64(le32_to_cpu(pSMBr->size));
3331 pFinfo->EndOfFile = pFinfo->AllocationSize;
3332 pFinfo->Attributes =
3333 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3334 } else
3335 rc = -EIO; /* bad buffer passed in */
3337 cifs_buf_release(pSMB);
3339 if (rc == -EAGAIN)
3340 goto QInfRetry;
3342 return rc;
3346 CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3347 u16 netfid, FILE_ALL_INFO *pFindData)
3349 struct smb_t2_qfi_req *pSMB = NULL;
3350 struct smb_t2_qfi_rsp *pSMBr = NULL;
3351 int rc = 0;
3352 int bytes_returned;
3353 __u16 params, byte_count;
3355 QFileInfoRetry:
3356 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3357 (void **) &pSMBr);
3358 if (rc)
3359 return rc;
3361 params = 2 /* level */ + 2 /* fid */;
3362 pSMB->t2.TotalDataCount = 0;
3363 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3364 /* BB find exact max data count below from sess structure BB */
3365 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3366 pSMB->t2.MaxSetupCount = 0;
3367 pSMB->t2.Reserved = 0;
3368 pSMB->t2.Flags = 0;
3369 pSMB->t2.Timeout = 0;
3370 pSMB->t2.Reserved2 = 0;
3371 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3372 Fid) - 4);
3373 pSMB->t2.DataCount = 0;
3374 pSMB->t2.DataOffset = 0;
3375 pSMB->t2.SetupCount = 1;
3376 pSMB->t2.Reserved3 = 0;
3377 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3378 byte_count = params + 1 /* pad */ ;
3379 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3380 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3381 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3382 pSMB->Pad = 0;
3383 pSMB->Fid = netfid;
3384 inc_rfc1001_len(pSMB, byte_count);
3386 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3387 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3388 if (rc) {
3389 cFYI(1, "Send error in QPathInfo = %d", rc);
3390 } else { /* decode response */
3391 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3393 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3394 rc = -EIO;
3395 else if (get_bcc(&pSMBr->hdr) < 40)
3396 rc = -EIO; /* bad smb */
3397 else if (pFindData) {
3398 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3399 memcpy((char *) pFindData,
3400 (char *) &pSMBr->hdr.Protocol +
3401 data_offset, sizeof(FILE_ALL_INFO));
3402 } else
3403 rc = -ENOMEM;
3405 cifs_buf_release(pSMB);
3406 if (rc == -EAGAIN)
3407 goto QFileInfoRetry;
3409 return rc;
3413 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3414 const unsigned char *searchName,
3415 FILE_ALL_INFO *pFindData,
3416 int legacy /* old style infolevel */,
3417 const struct nls_table *nls_codepage, int remap)
3419 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3420 TRANSACTION2_QPI_REQ *pSMB = NULL;
3421 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3422 int rc = 0;
3423 int bytes_returned;
3424 int name_len;
3425 __u16 params, byte_count;
3427 /* cFYI(1, "In QPathInfo path %s", searchName); */
3428 QPathInfoRetry:
3429 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3430 (void **) &pSMBr);
3431 if (rc)
3432 return rc;
3434 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3435 name_len =
3436 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3437 PATH_MAX, nls_codepage, remap);
3438 name_len++; /* trailing null */
3439 name_len *= 2;
3440 } else { /* BB improve the check for buffer overruns BB */
3441 name_len = strnlen(searchName, PATH_MAX);
3442 name_len++; /* trailing null */
3443 strncpy(pSMB->FileName, searchName, name_len);
3446 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3447 pSMB->TotalDataCount = 0;
3448 pSMB->MaxParameterCount = cpu_to_le16(2);
3449 /* BB find exact max SMB PDU from sess structure BB */
3450 pSMB->MaxDataCount = cpu_to_le16(4000);
3451 pSMB->MaxSetupCount = 0;
3452 pSMB->Reserved = 0;
3453 pSMB->Flags = 0;
3454 pSMB->Timeout = 0;
3455 pSMB->Reserved2 = 0;
3456 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3457 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3458 pSMB->DataCount = 0;
3459 pSMB->DataOffset = 0;
3460 pSMB->SetupCount = 1;
3461 pSMB->Reserved3 = 0;
3462 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3463 byte_count = params + 1 /* pad */ ;
3464 pSMB->TotalParameterCount = cpu_to_le16(params);
3465 pSMB->ParameterCount = pSMB->TotalParameterCount;
3466 if (legacy)
3467 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3468 else
3469 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3470 pSMB->Reserved4 = 0;
3471 inc_rfc1001_len(pSMB, byte_count);
3472 pSMB->ByteCount = cpu_to_le16(byte_count);
3474 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3475 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3476 if (rc) {
3477 cFYI(1, "Send error in QPathInfo = %d", rc);
3478 } else { /* decode response */
3479 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3481 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3482 rc = -EIO;
3483 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
3484 rc = -EIO; /* bad smb */
3485 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
3486 rc = -EIO; /* 24 or 26 expected but we do not read
3487 last field */
3488 else if (pFindData) {
3489 int size;
3490 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3492 /* On legacy responses we do not read the last field,
3493 EAsize, fortunately since it varies by subdialect and
3494 also note it differs on Set vs. Get, ie two bytes or 4
3495 bytes depending but we don't care here */
3496 if (legacy)
3497 size = sizeof(FILE_INFO_STANDARD);
3498 else
3499 size = sizeof(FILE_ALL_INFO);
3500 memcpy((char *) pFindData,
3501 (char *) &pSMBr->hdr.Protocol +
3502 data_offset, size);
3503 } else
3504 rc = -ENOMEM;
3506 cifs_buf_release(pSMB);
3507 if (rc == -EAGAIN)
3508 goto QPathInfoRetry;
3510 return rc;
3514 CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3515 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3517 struct smb_t2_qfi_req *pSMB = NULL;
3518 struct smb_t2_qfi_rsp *pSMBr = NULL;
3519 int rc = 0;
3520 int bytes_returned;
3521 __u16 params, byte_count;
3523 UnixQFileInfoRetry:
3524 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3525 (void **) &pSMBr);
3526 if (rc)
3527 return rc;
3529 params = 2 /* level */ + 2 /* fid */;
3530 pSMB->t2.TotalDataCount = 0;
3531 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3532 /* BB find exact max data count below from sess structure BB */
3533 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3534 pSMB->t2.MaxSetupCount = 0;
3535 pSMB->t2.Reserved = 0;
3536 pSMB->t2.Flags = 0;
3537 pSMB->t2.Timeout = 0;
3538 pSMB->t2.Reserved2 = 0;
3539 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3540 Fid) - 4);
3541 pSMB->t2.DataCount = 0;
3542 pSMB->t2.DataOffset = 0;
3543 pSMB->t2.SetupCount = 1;
3544 pSMB->t2.Reserved3 = 0;
3545 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3546 byte_count = params + 1 /* pad */ ;
3547 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3548 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3549 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3550 pSMB->Pad = 0;
3551 pSMB->Fid = netfid;
3552 inc_rfc1001_len(pSMB, byte_count);
3554 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3555 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3556 if (rc) {
3557 cFYI(1, "Send error in QPathInfo = %d", rc);
3558 } else { /* decode response */
3559 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3561 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
3562 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
3563 "Unix Extensions can be disabled on mount "
3564 "by specifying the nosfu mount option.");
3565 rc = -EIO; /* bad smb */
3566 } else {
3567 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3568 memcpy((char *) pFindData,
3569 (char *) &pSMBr->hdr.Protocol +
3570 data_offset,
3571 sizeof(FILE_UNIX_BASIC_INFO));
3575 cifs_buf_release(pSMB);
3576 if (rc == -EAGAIN)
3577 goto UnixQFileInfoRetry;
3579 return rc;
3583 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3584 const unsigned char *searchName,
3585 FILE_UNIX_BASIC_INFO *pFindData,
3586 const struct nls_table *nls_codepage, int remap)
3588 /* SMB_QUERY_FILE_UNIX_BASIC */
3589 TRANSACTION2_QPI_REQ *pSMB = NULL;
3590 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3591 int rc = 0;
3592 int bytes_returned = 0;
3593 int name_len;
3594 __u16 params, byte_count;
3596 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
3597 UnixQPathInfoRetry:
3598 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3599 (void **) &pSMBr);
3600 if (rc)
3601 return rc;
3603 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3604 name_len =
3605 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3606 PATH_MAX, nls_codepage, remap);
3607 name_len++; /* trailing null */
3608 name_len *= 2;
3609 } else { /* BB improve the check for buffer overruns BB */
3610 name_len = strnlen(searchName, PATH_MAX);
3611 name_len++; /* trailing null */
3612 strncpy(pSMB->FileName, searchName, name_len);
3615 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3616 pSMB->TotalDataCount = 0;
3617 pSMB->MaxParameterCount = cpu_to_le16(2);
3618 /* BB find exact max SMB PDU from sess structure BB */
3619 pSMB->MaxDataCount = cpu_to_le16(4000);
3620 pSMB->MaxSetupCount = 0;
3621 pSMB->Reserved = 0;
3622 pSMB->Flags = 0;
3623 pSMB->Timeout = 0;
3624 pSMB->Reserved2 = 0;
3625 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3626 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3627 pSMB->DataCount = 0;
3628 pSMB->DataOffset = 0;
3629 pSMB->SetupCount = 1;
3630 pSMB->Reserved3 = 0;
3631 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3632 byte_count = params + 1 /* pad */ ;
3633 pSMB->TotalParameterCount = cpu_to_le16(params);
3634 pSMB->ParameterCount = pSMB->TotalParameterCount;
3635 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3636 pSMB->Reserved4 = 0;
3637 inc_rfc1001_len(pSMB, byte_count);
3638 pSMB->ByteCount = cpu_to_le16(byte_count);
3640 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3641 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3642 if (rc) {
3643 cFYI(1, "Send error in QPathInfo = %d", rc);
3644 } else { /* decode response */
3645 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3647 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
3648 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
3649 "Unix Extensions can be disabled on mount "
3650 "by specifying the nosfu mount option.");
3651 rc = -EIO; /* bad smb */
3652 } else {
3653 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3654 memcpy((char *) pFindData,
3655 (char *) &pSMBr->hdr.Protocol +
3656 data_offset,
3657 sizeof(FILE_UNIX_BASIC_INFO));
3660 cifs_buf_release(pSMB);
3661 if (rc == -EAGAIN)
3662 goto UnixQPathInfoRetry;
3664 return rc;
3667 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3669 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3670 const char *searchName,
3671 const struct nls_table *nls_codepage,
3672 __u16 *pnetfid,
3673 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3675 /* level 257 SMB_ */
3676 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3677 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3678 T2_FFIRST_RSP_PARMS *parms;
3679 int rc = 0;
3680 int bytes_returned = 0;
3681 int name_len;
3682 __u16 params, byte_count;
3684 cFYI(1, "In FindFirst for %s", searchName);
3686 findFirstRetry:
3687 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3688 (void **) &pSMBr);
3689 if (rc)
3690 return rc;
3692 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3693 name_len =
3694 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3695 PATH_MAX, nls_codepage, remap);
3696 /* We can not add the asterik earlier in case
3697 it got remapped to 0xF03A as if it were part of the
3698 directory name instead of a wildcard */
3699 name_len *= 2;
3700 pSMB->FileName[name_len] = dirsep;
3701 pSMB->FileName[name_len+1] = 0;
3702 pSMB->FileName[name_len+2] = '*';
3703 pSMB->FileName[name_len+3] = 0;
3704 name_len += 4; /* now the trailing null */
3705 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3706 pSMB->FileName[name_len+1] = 0;
3707 name_len += 2;
3708 } else { /* BB add check for overrun of SMB buf BB */
3709 name_len = strnlen(searchName, PATH_MAX);
3710 /* BB fix here and in unicode clause above ie
3711 if (name_len > buffersize-header)
3712 free buffer exit; BB */
3713 strncpy(pSMB->FileName, searchName, name_len);
3714 pSMB->FileName[name_len] = dirsep;
3715 pSMB->FileName[name_len+1] = '*';
3716 pSMB->FileName[name_len+2] = 0;
3717 name_len += 3;
3720 params = 12 + name_len /* includes null */ ;
3721 pSMB->TotalDataCount = 0; /* no EAs */
3722 pSMB->MaxParameterCount = cpu_to_le16(10);
3723 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3724 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3725 pSMB->MaxSetupCount = 0;
3726 pSMB->Reserved = 0;
3727 pSMB->Flags = 0;
3728 pSMB->Timeout = 0;
3729 pSMB->Reserved2 = 0;
3730 byte_count = params + 1 /* pad */ ;
3731 pSMB->TotalParameterCount = cpu_to_le16(params);
3732 pSMB->ParameterCount = pSMB->TotalParameterCount;
3733 pSMB->ParameterOffset = cpu_to_le16(
3734 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3735 - 4);
3736 pSMB->DataCount = 0;
3737 pSMB->DataOffset = 0;
3738 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3739 pSMB->Reserved3 = 0;
3740 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3741 pSMB->SearchAttributes =
3742 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3743 ATTR_DIRECTORY);
3744 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3745 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3746 CIFS_SEARCH_RETURN_RESUME);
3747 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3749 /* BB what should we set StorageType to? Does it matter? BB */
3750 pSMB->SearchStorageType = 0;
3751 inc_rfc1001_len(pSMB, byte_count);
3752 pSMB->ByteCount = cpu_to_le16(byte_count);
3754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3756 cifs_stats_inc(&tcon->num_ffirst);
3758 if (rc) {/* BB add logic to retry regular search if Unix search
3759 rejected unexpectedly by server */
3760 /* BB Add code to handle unsupported level rc */
3761 cFYI(1, "Error in FindFirst = %d", rc);
3763 cifs_buf_release(pSMB);
3765 /* BB eventually could optimize out free and realloc of buf */
3766 /* for this case */
3767 if (rc == -EAGAIN)
3768 goto findFirstRetry;
3769 } else { /* decode response */
3770 /* BB remember to free buffer if error BB */
3771 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3772 if (rc == 0) {
3773 unsigned int lnoff;
3775 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3776 psrch_inf->unicode = true;
3777 else
3778 psrch_inf->unicode = false;
3780 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3781 psrch_inf->smallBuf = 0;
3782 psrch_inf->srch_entries_start =
3783 (char *) &pSMBr->hdr.Protocol +
3784 le16_to_cpu(pSMBr->t2.DataOffset);
3785 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3786 le16_to_cpu(pSMBr->t2.ParameterOffset));
3788 if (parms->EndofSearch)
3789 psrch_inf->endOfSearch = true;
3790 else
3791 psrch_inf->endOfSearch = false;
3793 psrch_inf->entries_in_buffer =
3794 le16_to_cpu(parms->SearchCount);
3795 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3796 psrch_inf->entries_in_buffer;
3797 lnoff = le16_to_cpu(parms->LastNameOffset);
3798 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3799 lnoff) {
3800 cERROR(1, "ignoring corrupt resume name");
3801 psrch_inf->last_entry = NULL;
3802 return rc;
3805 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3806 lnoff;
3808 *pnetfid = parms->SearchHandle;
3809 } else {
3810 cifs_buf_release(pSMB);
3814 return rc;
3817 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3818 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3820 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3821 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3822 T2_FNEXT_RSP_PARMS *parms;
3823 char *response_data;
3824 int rc = 0;
3825 int bytes_returned, name_len;
3826 __u16 params, byte_count;
3828 cFYI(1, "In FindNext");
3830 if (psrch_inf->endOfSearch)
3831 return -ENOENT;
3833 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3834 (void **) &pSMBr);
3835 if (rc)
3836 return rc;
3838 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3839 byte_count = 0;
3840 pSMB->TotalDataCount = 0; /* no EAs */
3841 pSMB->MaxParameterCount = cpu_to_le16(8);
3842 pSMB->MaxDataCount =
3843 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3844 0xFFFFFF00);
3845 pSMB->MaxSetupCount = 0;
3846 pSMB->Reserved = 0;
3847 pSMB->Flags = 0;
3848 pSMB->Timeout = 0;
3849 pSMB->Reserved2 = 0;
3850 pSMB->ParameterOffset = cpu_to_le16(
3851 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3852 pSMB->DataCount = 0;
3853 pSMB->DataOffset = 0;
3854 pSMB->SetupCount = 1;
3855 pSMB->Reserved3 = 0;
3856 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3857 pSMB->SearchHandle = searchHandle; /* always kept as le */
3858 pSMB->SearchCount =
3859 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3860 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3861 pSMB->ResumeKey = psrch_inf->resume_key;
3862 pSMB->SearchFlags =
3863 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3865 name_len = psrch_inf->resume_name_len;
3866 params += name_len;
3867 if (name_len < PATH_MAX) {
3868 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3869 byte_count += name_len;
3870 /* 14 byte parm len above enough for 2 byte null terminator */
3871 pSMB->ResumeFileName[name_len] = 0;
3872 pSMB->ResumeFileName[name_len+1] = 0;
3873 } else {
3874 rc = -EINVAL;
3875 goto FNext2_err_exit;
3877 byte_count = params + 1 /* pad */ ;
3878 pSMB->TotalParameterCount = cpu_to_le16(params);
3879 pSMB->ParameterCount = pSMB->TotalParameterCount;
3880 inc_rfc1001_len(pSMB, byte_count);
3881 pSMB->ByteCount = cpu_to_le16(byte_count);
3883 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3884 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3885 cifs_stats_inc(&tcon->num_fnext);
3886 if (rc) {
3887 if (rc == -EBADF) {
3888 psrch_inf->endOfSearch = true;
3889 cifs_buf_release(pSMB);
3890 rc = 0; /* search probably was closed at end of search*/
3891 } else
3892 cFYI(1, "FindNext returned = %d", rc);
3893 } else { /* decode response */
3894 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3896 if (rc == 0) {
3897 unsigned int lnoff;
3899 /* BB fixme add lock for file (srch_info) struct here */
3900 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3901 psrch_inf->unicode = true;
3902 else
3903 psrch_inf->unicode = false;
3904 response_data = (char *) &pSMBr->hdr.Protocol +
3905 le16_to_cpu(pSMBr->t2.ParameterOffset);
3906 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3907 response_data = (char *)&pSMBr->hdr.Protocol +
3908 le16_to_cpu(pSMBr->t2.DataOffset);
3909 if (psrch_inf->smallBuf)
3910 cifs_small_buf_release(
3911 psrch_inf->ntwrk_buf_start);
3912 else
3913 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3914 psrch_inf->srch_entries_start = response_data;
3915 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3916 psrch_inf->smallBuf = 0;
3917 if (parms->EndofSearch)
3918 psrch_inf->endOfSearch = true;
3919 else
3920 psrch_inf->endOfSearch = false;
3921 psrch_inf->entries_in_buffer =
3922 le16_to_cpu(parms->SearchCount);
3923 psrch_inf->index_of_last_entry +=
3924 psrch_inf->entries_in_buffer;
3925 lnoff = le16_to_cpu(parms->LastNameOffset);
3926 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3927 lnoff) {
3928 cERROR(1, "ignoring corrupt resume name");
3929 psrch_inf->last_entry = NULL;
3930 return rc;
3931 } else
3932 psrch_inf->last_entry =
3933 psrch_inf->srch_entries_start + lnoff;
3935 /* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3936 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
3938 /* BB fixme add unlock here */
3943 /* BB On error, should we leave previous search buf (and count and
3944 last entry fields) intact or free the previous one? */
3946 /* Note: On -EAGAIN error only caller can retry on handle based calls
3947 since file handle passed in no longer valid */
3948 FNext2_err_exit:
3949 if (rc != 0)
3950 cifs_buf_release(pSMB);
3951 return rc;
3955 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3956 const __u16 searchHandle)
3958 int rc = 0;
3959 FINDCLOSE_REQ *pSMB = NULL;
3961 cFYI(1, "In CIFSSMBFindClose");
3962 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3964 /* no sense returning error if session restarted
3965 as file handle has been closed */
3966 if (rc == -EAGAIN)
3967 return 0;
3968 if (rc)
3969 return rc;
3971 pSMB->FileID = searchHandle;
3972 pSMB->ByteCount = 0;
3973 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3974 if (rc)
3975 cERROR(1, "Send error in FindClose = %d", rc);
3977 cifs_stats_inc(&tcon->num_fclose);
3979 /* Since session is dead, search handle closed on server already */
3980 if (rc == -EAGAIN)
3981 rc = 0;
3983 return rc;
3987 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3988 const unsigned char *searchName,
3989 __u64 *inode_number,
3990 const struct nls_table *nls_codepage, int remap)
3992 int rc = 0;
3993 TRANSACTION2_QPI_REQ *pSMB = NULL;
3994 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3995 int name_len, bytes_returned;
3996 __u16 params, byte_count;
3998 cFYI(1, "In GetSrvInodeNum for %s", searchName);
3999 if (tcon == NULL)
4000 return -ENODEV;
4002 GetInodeNumberRetry:
4003 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4004 (void **) &pSMBr);
4005 if (rc)
4006 return rc;
4008 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4009 name_len =
4010 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4011 PATH_MAX, nls_codepage, remap);
4012 name_len++; /* trailing null */
4013 name_len *= 2;
4014 } else { /* BB improve the check for buffer overruns BB */
4015 name_len = strnlen(searchName, PATH_MAX);
4016 name_len++; /* trailing null */
4017 strncpy(pSMB->FileName, searchName, name_len);
4020 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4021 pSMB->TotalDataCount = 0;
4022 pSMB->MaxParameterCount = cpu_to_le16(2);
4023 /* BB find exact max data count below from sess structure BB */
4024 pSMB->MaxDataCount = cpu_to_le16(4000);
4025 pSMB->MaxSetupCount = 0;
4026 pSMB->Reserved = 0;
4027 pSMB->Flags = 0;
4028 pSMB->Timeout = 0;
4029 pSMB->Reserved2 = 0;
4030 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4031 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4032 pSMB->DataCount = 0;
4033 pSMB->DataOffset = 0;
4034 pSMB->SetupCount = 1;
4035 pSMB->Reserved3 = 0;
4036 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4037 byte_count = params + 1 /* pad */ ;
4038 pSMB->TotalParameterCount = cpu_to_le16(params);
4039 pSMB->ParameterCount = pSMB->TotalParameterCount;
4040 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4041 pSMB->Reserved4 = 0;
4042 inc_rfc1001_len(pSMB, byte_count);
4043 pSMB->ByteCount = cpu_to_le16(byte_count);
4045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4047 if (rc) {
4048 cFYI(1, "error %d in QueryInternalInfo", rc);
4049 } else {
4050 /* decode response */
4051 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4052 /* BB also check enough total bytes returned */
4053 if (rc || get_bcc(&pSMBr->hdr) < 2)
4054 /* If rc should we check for EOPNOSUPP and
4055 disable the srvino flag? or in caller? */
4056 rc = -EIO; /* bad smb */
4057 else {
4058 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4059 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
4060 struct file_internal_info *pfinfo;
4061 /* BB Do we need a cast or hash here ? */
4062 if (count < 8) {
4063 cFYI(1, "Illegal size ret in QryIntrnlInf");
4064 rc = -EIO;
4065 goto GetInodeNumOut;
4067 pfinfo = (struct file_internal_info *)
4068 (data_offset + (char *) &pSMBr->hdr.Protocol);
4069 *inode_number = le64_to_cpu(pfinfo->UniqueId);
4072 GetInodeNumOut:
4073 cifs_buf_release(pSMB);
4074 if (rc == -EAGAIN)
4075 goto GetInodeNumberRetry;
4076 return rc;
4079 /* parses DFS refferal V3 structure
4080 * caller is responsible for freeing target_nodes
4081 * returns:
4082 * on success - 0
4083 * on failure - errno
4085 static int
4086 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
4087 unsigned int *num_of_nodes,
4088 struct dfs_info3_param **target_nodes,
4089 const struct nls_table *nls_codepage, int remap,
4090 const char *searchName)
4092 int i, rc = 0;
4093 char *data_end;
4094 bool is_unicode;
4095 struct dfs_referral_level_3 *ref;
4097 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4098 is_unicode = true;
4099 else
4100 is_unicode = false;
4101 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4103 if (*num_of_nodes < 1) {
4104 cERROR(1, "num_referrals: must be at least > 0,"
4105 "but we get num_referrals = %d\n", *num_of_nodes);
4106 rc = -EINVAL;
4107 goto parse_DFS_referrals_exit;
4110 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
4111 if (ref->VersionNumber != cpu_to_le16(3)) {
4112 cERROR(1, "Referrals of V%d version are not supported,"
4113 "should be V3", le16_to_cpu(ref->VersionNumber));
4114 rc = -EINVAL;
4115 goto parse_DFS_referrals_exit;
4118 /* get the upper boundary of the resp buffer */
4119 data_end = (char *)(&(pSMBr->PathConsumed)) +
4120 le16_to_cpu(pSMBr->t2.DataCount);
4122 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
4123 *num_of_nodes,
4124 le32_to_cpu(pSMBr->DFSFlags));
4126 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4127 *num_of_nodes, GFP_KERNEL);
4128 if (*target_nodes == NULL) {
4129 cERROR(1, "Failed to allocate buffer for target_nodes\n");
4130 rc = -ENOMEM;
4131 goto parse_DFS_referrals_exit;
4134 /* collect necessary data from referrals */
4135 for (i = 0; i < *num_of_nodes; i++) {
4136 char *temp;
4137 int max_len;
4138 struct dfs_info3_param *node = (*target_nodes)+i;
4140 node->flags = le32_to_cpu(pSMBr->DFSFlags);
4141 if (is_unicode) {
4142 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4143 GFP_KERNEL);
4144 if (tmp == NULL) {
4145 rc = -ENOMEM;
4146 goto parse_DFS_referrals_exit;
4148 cifsConvertToUCS((__le16 *) tmp, searchName,
4149 PATH_MAX, nls_codepage, remap);
4150 node->path_consumed = cifs_ucs2_bytes(tmp,
4151 le16_to_cpu(pSMBr->PathConsumed),
4152 nls_codepage);
4153 kfree(tmp);
4154 } else
4155 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4157 node->server_type = le16_to_cpu(ref->ServerType);
4158 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4160 /* copy DfsPath */
4161 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4162 max_len = data_end - temp;
4163 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4164 is_unicode, nls_codepage);
4165 if (!node->path_name) {
4166 rc = -ENOMEM;
4167 goto parse_DFS_referrals_exit;
4170 /* copy link target UNC */
4171 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4172 max_len = data_end - temp;
4173 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4174 is_unicode, nls_codepage);
4175 if (!node->node_name)
4176 rc = -ENOMEM;
4179 parse_DFS_referrals_exit:
4180 if (rc) {
4181 free_dfs_info_array(*target_nodes, *num_of_nodes);
4182 *target_nodes = NULL;
4183 *num_of_nodes = 0;
4185 return rc;
4189 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4190 const unsigned char *searchName,
4191 struct dfs_info3_param **target_nodes,
4192 unsigned int *num_of_nodes,
4193 const struct nls_table *nls_codepage, int remap)
4195 /* TRANS2_GET_DFS_REFERRAL */
4196 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4197 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4198 int rc = 0;
4199 int bytes_returned;
4200 int name_len;
4201 __u16 params, byte_count;
4202 *num_of_nodes = 0;
4203 *target_nodes = NULL;
4205 cFYI(1, "In GetDFSRefer the path %s", searchName);
4206 if (ses == NULL)
4207 return -ENODEV;
4208 getDFSRetry:
4209 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4210 (void **) &pSMBr);
4211 if (rc)
4212 return rc;
4214 /* server pointer checked in called function,
4215 but should never be null here anyway */
4216 pSMB->hdr.Mid = GetNextMid(ses->server);
4217 pSMB->hdr.Tid = ses->ipc_tid;
4218 pSMB->hdr.Uid = ses->Suid;
4219 if (ses->capabilities & CAP_STATUS32)
4220 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4221 if (ses->capabilities & CAP_DFS)
4222 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4224 if (ses->capabilities & CAP_UNICODE) {
4225 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4226 name_len =
4227 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4228 searchName, PATH_MAX, nls_codepage, remap);
4229 name_len++; /* trailing null */
4230 name_len *= 2;
4231 } else { /* BB improve the check for buffer overruns BB */
4232 name_len = strnlen(searchName, PATH_MAX);
4233 name_len++; /* trailing null */
4234 strncpy(pSMB->RequestFileName, searchName, name_len);
4237 if (ses->server) {
4238 if (ses->server->secMode &
4239 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4240 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4243 pSMB->hdr.Uid = ses->Suid;
4245 params = 2 /* level */ + name_len /*includes null */ ;
4246 pSMB->TotalDataCount = 0;
4247 pSMB->DataCount = 0;
4248 pSMB->DataOffset = 0;
4249 pSMB->MaxParameterCount = 0;
4250 /* BB find exact max SMB PDU from sess structure BB */
4251 pSMB->MaxDataCount = cpu_to_le16(4000);
4252 pSMB->MaxSetupCount = 0;
4253 pSMB->Reserved = 0;
4254 pSMB->Flags = 0;
4255 pSMB->Timeout = 0;
4256 pSMB->Reserved2 = 0;
4257 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4258 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4259 pSMB->SetupCount = 1;
4260 pSMB->Reserved3 = 0;
4261 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4262 byte_count = params + 3 /* pad */ ;
4263 pSMB->ParameterCount = cpu_to_le16(params);
4264 pSMB->TotalParameterCount = pSMB->ParameterCount;
4265 pSMB->MaxReferralLevel = cpu_to_le16(3);
4266 inc_rfc1001_len(pSMB, byte_count);
4267 pSMB->ByteCount = cpu_to_le16(byte_count);
4269 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4270 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4271 if (rc) {
4272 cFYI(1, "Send error in GetDFSRefer = %d", rc);
4273 goto GetDFSRefExit;
4275 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4277 /* BB Also check if enough total bytes returned? */
4278 if (rc || get_bcc(&pSMBr->hdr) < 17) {
4279 rc = -EIO; /* bad smb */
4280 goto GetDFSRefExit;
4283 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
4284 get_bcc(&pSMBr->hdr),
4285 le16_to_cpu(pSMBr->t2.DataOffset));
4287 /* parse returned result into more usable form */
4288 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4289 target_nodes, nls_codepage, remap,
4290 searchName);
4292 GetDFSRefExit:
4293 cifs_buf_release(pSMB);
4295 if (rc == -EAGAIN)
4296 goto getDFSRetry;
4298 return rc;
4301 /* Query File System Info such as free space to old servers such as Win 9x */
4303 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4305 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4306 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4307 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4308 FILE_SYSTEM_ALLOC_INFO *response_data;
4309 int rc = 0;
4310 int bytes_returned = 0;
4311 __u16 params, byte_count;
4313 cFYI(1, "OldQFSInfo");
4314 oldQFSInfoRetry:
4315 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4316 (void **) &pSMBr);
4317 if (rc)
4318 return rc;
4320 params = 2; /* level */
4321 pSMB->TotalDataCount = 0;
4322 pSMB->MaxParameterCount = cpu_to_le16(2);
4323 pSMB->MaxDataCount = cpu_to_le16(1000);
4324 pSMB->MaxSetupCount = 0;
4325 pSMB->Reserved = 0;
4326 pSMB->Flags = 0;
4327 pSMB->Timeout = 0;
4328 pSMB->Reserved2 = 0;
4329 byte_count = params + 1 /* pad */ ;
4330 pSMB->TotalParameterCount = cpu_to_le16(params);
4331 pSMB->ParameterCount = pSMB->TotalParameterCount;
4332 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4333 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4334 pSMB->DataCount = 0;
4335 pSMB->DataOffset = 0;
4336 pSMB->SetupCount = 1;
4337 pSMB->Reserved3 = 0;
4338 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4339 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4340 inc_rfc1001_len(pSMB, byte_count);
4341 pSMB->ByteCount = cpu_to_le16(byte_count);
4343 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4344 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4345 if (rc) {
4346 cFYI(1, "Send error in QFSInfo = %d", rc);
4347 } else { /* decode response */
4348 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4350 if (rc || get_bcc(&pSMBr->hdr) < 18)
4351 rc = -EIO; /* bad smb */
4352 else {
4353 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4354 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4355 get_bcc(&pSMBr->hdr), data_offset);
4357 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4358 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4359 FSData->f_bsize =
4360 le16_to_cpu(response_data->BytesPerSector) *
4361 le32_to_cpu(response_data->
4362 SectorsPerAllocationUnit);
4363 FSData->f_blocks =
4364 le32_to_cpu(response_data->TotalAllocationUnits);
4365 FSData->f_bfree = FSData->f_bavail =
4366 le32_to_cpu(response_data->FreeAllocationUnits);
4367 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4368 (unsigned long long)FSData->f_blocks,
4369 (unsigned long long)FSData->f_bfree,
4370 FSData->f_bsize);
4373 cifs_buf_release(pSMB);
4375 if (rc == -EAGAIN)
4376 goto oldQFSInfoRetry;
4378 return rc;
4382 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4384 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4385 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4386 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4387 FILE_SYSTEM_INFO *response_data;
4388 int rc = 0;
4389 int bytes_returned = 0;
4390 __u16 params, byte_count;
4392 cFYI(1, "In QFSInfo");
4393 QFSInfoRetry:
4394 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4395 (void **) &pSMBr);
4396 if (rc)
4397 return rc;
4399 params = 2; /* level */
4400 pSMB->TotalDataCount = 0;
4401 pSMB->MaxParameterCount = cpu_to_le16(2);
4402 pSMB->MaxDataCount = cpu_to_le16(1000);
4403 pSMB->MaxSetupCount = 0;
4404 pSMB->Reserved = 0;
4405 pSMB->Flags = 0;
4406 pSMB->Timeout = 0;
4407 pSMB->Reserved2 = 0;
4408 byte_count = params + 1 /* pad */ ;
4409 pSMB->TotalParameterCount = cpu_to_le16(params);
4410 pSMB->ParameterCount = pSMB->TotalParameterCount;
4411 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4412 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4413 pSMB->DataCount = 0;
4414 pSMB->DataOffset = 0;
4415 pSMB->SetupCount = 1;
4416 pSMB->Reserved3 = 0;
4417 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4418 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4419 inc_rfc1001_len(pSMB, byte_count);
4420 pSMB->ByteCount = cpu_to_le16(byte_count);
4422 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4423 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4424 if (rc) {
4425 cFYI(1, "Send error in QFSInfo = %d", rc);
4426 } else { /* decode response */
4427 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4429 if (rc || get_bcc(&pSMBr->hdr) < 24)
4430 rc = -EIO; /* bad smb */
4431 else {
4432 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4434 response_data =
4435 (FILE_SYSTEM_INFO
4436 *) (((char *) &pSMBr->hdr.Protocol) +
4437 data_offset);
4438 FSData->f_bsize =
4439 le32_to_cpu(response_data->BytesPerSector) *
4440 le32_to_cpu(response_data->
4441 SectorsPerAllocationUnit);
4442 FSData->f_blocks =
4443 le64_to_cpu(response_data->TotalAllocationUnits);
4444 FSData->f_bfree = FSData->f_bavail =
4445 le64_to_cpu(response_data->FreeAllocationUnits);
4446 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4447 (unsigned long long)FSData->f_blocks,
4448 (unsigned long long)FSData->f_bfree,
4449 FSData->f_bsize);
4452 cifs_buf_release(pSMB);
4454 if (rc == -EAGAIN)
4455 goto QFSInfoRetry;
4457 return rc;
4461 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4463 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4464 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4465 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4466 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4467 int rc = 0;
4468 int bytes_returned = 0;
4469 __u16 params, byte_count;
4471 cFYI(1, "In QFSAttributeInfo");
4472 QFSAttributeRetry:
4473 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4474 (void **) &pSMBr);
4475 if (rc)
4476 return rc;
4478 params = 2; /* level */
4479 pSMB->TotalDataCount = 0;
4480 pSMB->MaxParameterCount = cpu_to_le16(2);
4481 /* BB find exact max SMB PDU from sess structure BB */
4482 pSMB->MaxDataCount = cpu_to_le16(1000);
4483 pSMB->MaxSetupCount = 0;
4484 pSMB->Reserved = 0;
4485 pSMB->Flags = 0;
4486 pSMB->Timeout = 0;
4487 pSMB->Reserved2 = 0;
4488 byte_count = params + 1 /* pad */ ;
4489 pSMB->TotalParameterCount = cpu_to_le16(params);
4490 pSMB->ParameterCount = pSMB->TotalParameterCount;
4491 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4492 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4493 pSMB->DataCount = 0;
4494 pSMB->DataOffset = 0;
4495 pSMB->SetupCount = 1;
4496 pSMB->Reserved3 = 0;
4497 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4498 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4499 inc_rfc1001_len(pSMB, byte_count);
4500 pSMB->ByteCount = cpu_to_le16(byte_count);
4502 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4504 if (rc) {
4505 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
4506 } else { /* decode response */
4507 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4509 if (rc || get_bcc(&pSMBr->hdr) < 13) {
4510 /* BB also check if enough bytes returned */
4511 rc = -EIO; /* bad smb */
4512 } else {
4513 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4514 response_data =
4515 (FILE_SYSTEM_ATTRIBUTE_INFO
4516 *) (((char *) &pSMBr->hdr.Protocol) +
4517 data_offset);
4518 memcpy(&tcon->fsAttrInfo, response_data,
4519 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4522 cifs_buf_release(pSMB);
4524 if (rc == -EAGAIN)
4525 goto QFSAttributeRetry;
4527 return rc;
4531 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4533 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4534 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4535 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4536 FILE_SYSTEM_DEVICE_INFO *response_data;
4537 int rc = 0;
4538 int bytes_returned = 0;
4539 __u16 params, byte_count;
4541 cFYI(1, "In QFSDeviceInfo");
4542 QFSDeviceRetry:
4543 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4544 (void **) &pSMBr);
4545 if (rc)
4546 return rc;
4548 params = 2; /* level */
4549 pSMB->TotalDataCount = 0;
4550 pSMB->MaxParameterCount = cpu_to_le16(2);
4551 /* BB find exact max SMB PDU from sess structure BB */
4552 pSMB->MaxDataCount = cpu_to_le16(1000);
4553 pSMB->MaxSetupCount = 0;
4554 pSMB->Reserved = 0;
4555 pSMB->Flags = 0;
4556 pSMB->Timeout = 0;
4557 pSMB->Reserved2 = 0;
4558 byte_count = params + 1 /* pad */ ;
4559 pSMB->TotalParameterCount = cpu_to_le16(params);
4560 pSMB->ParameterCount = pSMB->TotalParameterCount;
4561 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4562 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4564 pSMB->DataCount = 0;
4565 pSMB->DataOffset = 0;
4566 pSMB->SetupCount = 1;
4567 pSMB->Reserved3 = 0;
4568 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4569 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4570 inc_rfc1001_len(pSMB, byte_count);
4571 pSMB->ByteCount = cpu_to_le16(byte_count);
4573 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4574 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4575 if (rc) {
4576 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
4577 } else { /* decode response */
4578 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4580 if (rc || get_bcc(&pSMBr->hdr) <
4581 sizeof(FILE_SYSTEM_DEVICE_INFO))
4582 rc = -EIO; /* bad smb */
4583 else {
4584 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4585 response_data =
4586 (FILE_SYSTEM_DEVICE_INFO *)
4587 (((char *) &pSMBr->hdr.Protocol) +
4588 data_offset);
4589 memcpy(&tcon->fsDevInfo, response_data,
4590 sizeof(FILE_SYSTEM_DEVICE_INFO));
4593 cifs_buf_release(pSMB);
4595 if (rc == -EAGAIN)
4596 goto QFSDeviceRetry;
4598 return rc;
4602 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4604 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4605 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4606 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4607 FILE_SYSTEM_UNIX_INFO *response_data;
4608 int rc = 0;
4609 int bytes_returned = 0;
4610 __u16 params, byte_count;
4612 cFYI(1, "In QFSUnixInfo");
4613 QFSUnixRetry:
4614 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4615 (void **) &pSMB, (void **) &pSMBr);
4616 if (rc)
4617 return rc;
4619 params = 2; /* level */
4620 pSMB->TotalDataCount = 0;
4621 pSMB->DataCount = 0;
4622 pSMB->DataOffset = 0;
4623 pSMB->MaxParameterCount = cpu_to_le16(2);
4624 /* BB find exact max SMB PDU from sess structure BB */
4625 pSMB->MaxDataCount = cpu_to_le16(100);
4626 pSMB->MaxSetupCount = 0;
4627 pSMB->Reserved = 0;
4628 pSMB->Flags = 0;
4629 pSMB->Timeout = 0;
4630 pSMB->Reserved2 = 0;
4631 byte_count = params + 1 /* pad */ ;
4632 pSMB->ParameterCount = cpu_to_le16(params);
4633 pSMB->TotalParameterCount = pSMB->ParameterCount;
4634 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4635 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4636 pSMB->SetupCount = 1;
4637 pSMB->Reserved3 = 0;
4638 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4639 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4640 inc_rfc1001_len(pSMB, byte_count);
4641 pSMB->ByteCount = cpu_to_le16(byte_count);
4643 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4644 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4645 if (rc) {
4646 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
4647 } else { /* decode response */
4648 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4650 if (rc || get_bcc(&pSMBr->hdr) < 13) {
4651 rc = -EIO; /* bad smb */
4652 } else {
4653 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4654 response_data =
4655 (FILE_SYSTEM_UNIX_INFO
4656 *) (((char *) &pSMBr->hdr.Protocol) +
4657 data_offset);
4658 memcpy(&tcon->fsUnixInfo, response_data,
4659 sizeof(FILE_SYSTEM_UNIX_INFO));
4662 cifs_buf_release(pSMB);
4664 if (rc == -EAGAIN)
4665 goto QFSUnixRetry;
4668 return rc;
4672 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4674 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4675 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4676 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4677 int rc = 0;
4678 int bytes_returned = 0;
4679 __u16 params, param_offset, offset, byte_count;
4681 cFYI(1, "In SETFSUnixInfo");
4682 SETFSUnixRetry:
4683 /* BB switch to small buf init to save memory */
4684 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4685 (void **) &pSMB, (void **) &pSMBr);
4686 if (rc)
4687 return rc;
4689 params = 4; /* 2 bytes zero followed by info level. */
4690 pSMB->MaxSetupCount = 0;
4691 pSMB->Reserved = 0;
4692 pSMB->Flags = 0;
4693 pSMB->Timeout = 0;
4694 pSMB->Reserved2 = 0;
4695 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4696 - 4;
4697 offset = param_offset + params;
4699 pSMB->MaxParameterCount = cpu_to_le16(4);
4700 /* BB find exact max SMB PDU from sess structure BB */
4701 pSMB->MaxDataCount = cpu_to_le16(100);
4702 pSMB->SetupCount = 1;
4703 pSMB->Reserved3 = 0;
4704 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4705 byte_count = 1 /* pad */ + params + 12;
4707 pSMB->DataCount = cpu_to_le16(12);
4708 pSMB->ParameterCount = cpu_to_le16(params);
4709 pSMB->TotalDataCount = pSMB->DataCount;
4710 pSMB->TotalParameterCount = pSMB->ParameterCount;
4711 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4712 pSMB->DataOffset = cpu_to_le16(offset);
4714 /* Params. */
4715 pSMB->FileNum = 0;
4716 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4718 /* Data. */
4719 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4720 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4721 pSMB->ClientUnixCap = cpu_to_le64(cap);
4723 inc_rfc1001_len(pSMB, byte_count);
4724 pSMB->ByteCount = cpu_to_le16(byte_count);
4726 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4727 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4728 if (rc) {
4729 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
4730 } else { /* decode response */
4731 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4732 if (rc)
4733 rc = -EIO; /* bad smb */
4735 cifs_buf_release(pSMB);
4737 if (rc == -EAGAIN)
4738 goto SETFSUnixRetry;
4740 return rc;
4746 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4747 struct kstatfs *FSData)
4749 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4750 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4751 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4752 FILE_SYSTEM_POSIX_INFO *response_data;
4753 int rc = 0;
4754 int bytes_returned = 0;
4755 __u16 params, byte_count;
4757 cFYI(1, "In QFSPosixInfo");
4758 QFSPosixRetry:
4759 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4760 (void **) &pSMBr);
4761 if (rc)
4762 return rc;
4764 params = 2; /* level */
4765 pSMB->TotalDataCount = 0;
4766 pSMB->DataCount = 0;
4767 pSMB->DataOffset = 0;
4768 pSMB->MaxParameterCount = cpu_to_le16(2);
4769 /* BB find exact max SMB PDU from sess structure BB */
4770 pSMB->MaxDataCount = cpu_to_le16(100);
4771 pSMB->MaxSetupCount = 0;
4772 pSMB->Reserved = 0;
4773 pSMB->Flags = 0;
4774 pSMB->Timeout = 0;
4775 pSMB->Reserved2 = 0;
4776 byte_count = params + 1 /* pad */ ;
4777 pSMB->ParameterCount = cpu_to_le16(params);
4778 pSMB->TotalParameterCount = pSMB->ParameterCount;
4779 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4780 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4781 pSMB->SetupCount = 1;
4782 pSMB->Reserved3 = 0;
4783 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4784 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4785 inc_rfc1001_len(pSMB, byte_count);
4786 pSMB->ByteCount = cpu_to_le16(byte_count);
4788 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4789 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4790 if (rc) {
4791 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
4792 } else { /* decode response */
4793 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4795 if (rc || get_bcc(&pSMBr->hdr) < 13) {
4796 rc = -EIO; /* bad smb */
4797 } else {
4798 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4799 response_data =
4800 (FILE_SYSTEM_POSIX_INFO
4801 *) (((char *) &pSMBr->hdr.Protocol) +
4802 data_offset);
4803 FSData->f_bsize =
4804 le32_to_cpu(response_data->BlockSize);
4805 FSData->f_blocks =
4806 le64_to_cpu(response_data->TotalBlocks);
4807 FSData->f_bfree =
4808 le64_to_cpu(response_data->BlocksAvail);
4809 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4810 FSData->f_bavail = FSData->f_bfree;
4811 } else {
4812 FSData->f_bavail =
4813 le64_to_cpu(response_data->UserBlocksAvail);
4815 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4816 FSData->f_files =
4817 le64_to_cpu(response_data->TotalFileNodes);
4818 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4819 FSData->f_ffree =
4820 le64_to_cpu(response_data->FreeFileNodes);
4823 cifs_buf_release(pSMB);
4825 if (rc == -EAGAIN)
4826 goto QFSPosixRetry;
4828 return rc;
4832 /* We can not use write of zero bytes trick to
4833 set file size due to need for large file support. Also note that
4834 this SetPathInfo is preferred to SetFileInfo based method in next
4835 routine which is only needed to work around a sharing violation bug
4836 in Samba which this routine can run into */
4839 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4840 __u64 size, bool SetAllocation,
4841 const struct nls_table *nls_codepage, int remap)
4843 struct smb_com_transaction2_spi_req *pSMB = NULL;
4844 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4845 struct file_end_of_file_info *parm_data;
4846 int name_len;
4847 int rc = 0;
4848 int bytes_returned = 0;
4849 __u16 params, byte_count, data_count, param_offset, offset;
4851 cFYI(1, "In SetEOF");
4852 SetEOFRetry:
4853 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4854 (void **) &pSMBr);
4855 if (rc)
4856 return rc;
4858 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4859 name_len =
4860 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4861 PATH_MAX, nls_codepage, remap);
4862 name_len++; /* trailing null */
4863 name_len *= 2;
4864 } else { /* BB improve the check for buffer overruns BB */
4865 name_len = strnlen(fileName, PATH_MAX);
4866 name_len++; /* trailing null */
4867 strncpy(pSMB->FileName, fileName, name_len);
4869 params = 6 + name_len;
4870 data_count = sizeof(struct file_end_of_file_info);
4871 pSMB->MaxParameterCount = cpu_to_le16(2);
4872 pSMB->MaxDataCount = cpu_to_le16(4100);
4873 pSMB->MaxSetupCount = 0;
4874 pSMB->Reserved = 0;
4875 pSMB->Flags = 0;
4876 pSMB->Timeout = 0;
4877 pSMB->Reserved2 = 0;
4878 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4879 InformationLevel) - 4;
4880 offset = param_offset + params;
4881 if (SetAllocation) {
4882 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4883 pSMB->InformationLevel =
4884 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4885 else
4886 pSMB->InformationLevel =
4887 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4888 } else /* Set File Size */ {
4889 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4890 pSMB->InformationLevel =
4891 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4892 else
4893 pSMB->InformationLevel =
4894 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4897 parm_data =
4898 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4899 offset);
4900 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4901 pSMB->DataOffset = cpu_to_le16(offset);
4902 pSMB->SetupCount = 1;
4903 pSMB->Reserved3 = 0;
4904 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4905 byte_count = 3 /* pad */ + params + data_count;
4906 pSMB->DataCount = cpu_to_le16(data_count);
4907 pSMB->TotalDataCount = pSMB->DataCount;
4908 pSMB->ParameterCount = cpu_to_le16(params);
4909 pSMB->TotalParameterCount = pSMB->ParameterCount;
4910 pSMB->Reserved4 = 0;
4911 inc_rfc1001_len(pSMB, byte_count);
4912 parm_data->FileSize = cpu_to_le64(size);
4913 pSMB->ByteCount = cpu_to_le16(byte_count);
4914 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4915 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4916 if (rc)
4917 cFYI(1, "SetPathInfo (file size) returned %d", rc);
4919 cifs_buf_release(pSMB);
4921 if (rc == -EAGAIN)
4922 goto SetEOFRetry;
4924 return rc;
4928 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4929 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4931 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4932 struct file_end_of_file_info *parm_data;
4933 int rc = 0;
4934 __u16 params, param_offset, offset, byte_count, count;
4936 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4937 (long long)size);
4938 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4940 if (rc)
4941 return rc;
4943 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4944 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4946 params = 6;
4947 pSMB->MaxSetupCount = 0;
4948 pSMB->Reserved = 0;
4949 pSMB->Flags = 0;
4950 pSMB->Timeout = 0;
4951 pSMB->Reserved2 = 0;
4952 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4953 offset = param_offset + params;
4955 count = sizeof(struct file_end_of_file_info);
4956 pSMB->MaxParameterCount = cpu_to_le16(2);
4957 /* BB find exact max SMB PDU from sess structure BB */
4958 pSMB->MaxDataCount = cpu_to_le16(1000);
4959 pSMB->SetupCount = 1;
4960 pSMB->Reserved3 = 0;
4961 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4962 byte_count = 3 /* pad */ + params + count;
4963 pSMB->DataCount = cpu_to_le16(count);
4964 pSMB->ParameterCount = cpu_to_le16(params);
4965 pSMB->TotalDataCount = pSMB->DataCount;
4966 pSMB->TotalParameterCount = pSMB->ParameterCount;
4967 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4968 parm_data =
4969 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4970 + offset);
4971 pSMB->DataOffset = cpu_to_le16(offset);
4972 parm_data->FileSize = cpu_to_le64(size);
4973 pSMB->Fid = fid;
4974 if (SetAllocation) {
4975 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4976 pSMB->InformationLevel =
4977 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4978 else
4979 pSMB->InformationLevel =
4980 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4981 } else /* Set File Size */ {
4982 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4983 pSMB->InformationLevel =
4984 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4985 else
4986 pSMB->InformationLevel =
4987 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4989 pSMB->Reserved4 = 0;
4990 inc_rfc1001_len(pSMB, byte_count);
4991 pSMB->ByteCount = cpu_to_le16(byte_count);
4992 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4993 if (rc) {
4994 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
4997 /* Note: On -EAGAIN error only caller can retry on handle based calls
4998 since file handle passed in no longer valid */
5000 return rc;
5003 /* Some legacy servers such as NT4 require that the file times be set on
5004 an open handle, rather than by pathname - this is awkward due to
5005 potential access conflicts on the open, but it is unavoidable for these
5006 old servers since the only other choice is to go from 100 nanosecond DCE
5007 time and resort to the original setpathinfo level which takes the ancient
5008 DOS time format with 2 second granularity */
5010 CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5011 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
5013 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5014 char *data_offset;
5015 int rc = 0;
5016 __u16 params, param_offset, offset, byte_count, count;
5018 cFYI(1, "Set Times (via SetFileInfo)");
5019 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5021 if (rc)
5022 return rc;
5024 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5025 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5027 params = 6;
5028 pSMB->MaxSetupCount = 0;
5029 pSMB->Reserved = 0;
5030 pSMB->Flags = 0;
5031 pSMB->Timeout = 0;
5032 pSMB->Reserved2 = 0;
5033 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5034 offset = param_offset + params;
5036 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5038 count = sizeof(FILE_BASIC_INFO);
5039 pSMB->MaxParameterCount = cpu_to_le16(2);
5040 /* BB find max SMB PDU from sess */
5041 pSMB->MaxDataCount = cpu_to_le16(1000);
5042 pSMB->SetupCount = 1;
5043 pSMB->Reserved3 = 0;
5044 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5045 byte_count = 3 /* pad */ + params + count;
5046 pSMB->DataCount = cpu_to_le16(count);
5047 pSMB->ParameterCount = cpu_to_le16(params);
5048 pSMB->TotalDataCount = pSMB->DataCount;
5049 pSMB->TotalParameterCount = pSMB->ParameterCount;
5050 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5051 pSMB->DataOffset = cpu_to_le16(offset);
5052 pSMB->Fid = fid;
5053 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5054 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5055 else
5056 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5057 pSMB->Reserved4 = 0;
5058 inc_rfc1001_len(pSMB, byte_count);
5059 pSMB->ByteCount = cpu_to_le16(byte_count);
5060 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5061 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5062 if (rc)
5063 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
5065 /* Note: On -EAGAIN error only caller can retry on handle based calls
5066 since file handle passed in no longer valid */
5068 return rc;
5072 CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5073 bool delete_file, __u16 fid, __u32 pid_of_opener)
5075 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5076 char *data_offset;
5077 int rc = 0;
5078 __u16 params, param_offset, offset, byte_count, count;
5080 cFYI(1, "Set File Disposition (via SetFileInfo)");
5081 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5083 if (rc)
5084 return rc;
5086 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5087 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5089 params = 6;
5090 pSMB->MaxSetupCount = 0;
5091 pSMB->Reserved = 0;
5092 pSMB->Flags = 0;
5093 pSMB->Timeout = 0;
5094 pSMB->Reserved2 = 0;
5095 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5096 offset = param_offset + params;
5098 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5100 count = 1;
5101 pSMB->MaxParameterCount = cpu_to_le16(2);
5102 /* BB find max SMB PDU from sess */
5103 pSMB->MaxDataCount = cpu_to_le16(1000);
5104 pSMB->SetupCount = 1;
5105 pSMB->Reserved3 = 0;
5106 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5107 byte_count = 3 /* pad */ + params + count;
5108 pSMB->DataCount = cpu_to_le16(count);
5109 pSMB->ParameterCount = cpu_to_le16(params);
5110 pSMB->TotalDataCount = pSMB->DataCount;
5111 pSMB->TotalParameterCount = pSMB->ParameterCount;
5112 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5113 pSMB->DataOffset = cpu_to_le16(offset);
5114 pSMB->Fid = fid;
5115 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5116 pSMB->Reserved4 = 0;
5117 inc_rfc1001_len(pSMB, byte_count);
5118 pSMB->ByteCount = cpu_to_le16(byte_count);
5119 *data_offset = delete_file ? 1 : 0;
5120 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5121 if (rc)
5122 cFYI(1, "Send error in SetFileDisposition = %d", rc);
5124 return rc;
5128 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5129 const char *fileName, const FILE_BASIC_INFO *data,
5130 const struct nls_table *nls_codepage, int remap)
5132 TRANSACTION2_SPI_REQ *pSMB = NULL;
5133 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5134 int name_len;
5135 int rc = 0;
5136 int bytes_returned = 0;
5137 char *data_offset;
5138 __u16 params, param_offset, offset, byte_count, count;
5140 cFYI(1, "In SetTimes");
5142 SetTimesRetry:
5143 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5144 (void **) &pSMBr);
5145 if (rc)
5146 return rc;
5148 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5149 name_len =
5150 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5151 PATH_MAX, nls_codepage, remap);
5152 name_len++; /* trailing null */
5153 name_len *= 2;
5154 } else { /* BB improve the check for buffer overruns BB */
5155 name_len = strnlen(fileName, PATH_MAX);
5156 name_len++; /* trailing null */
5157 strncpy(pSMB->FileName, fileName, name_len);
5160 params = 6 + name_len;
5161 count = sizeof(FILE_BASIC_INFO);
5162 pSMB->MaxParameterCount = cpu_to_le16(2);
5163 /* BB find max SMB PDU from sess structure BB */
5164 pSMB->MaxDataCount = cpu_to_le16(1000);
5165 pSMB->MaxSetupCount = 0;
5166 pSMB->Reserved = 0;
5167 pSMB->Flags = 0;
5168 pSMB->Timeout = 0;
5169 pSMB->Reserved2 = 0;
5170 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5171 InformationLevel) - 4;
5172 offset = param_offset + params;
5173 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5174 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5175 pSMB->DataOffset = cpu_to_le16(offset);
5176 pSMB->SetupCount = 1;
5177 pSMB->Reserved3 = 0;
5178 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5179 byte_count = 3 /* pad */ + params + count;
5181 pSMB->DataCount = cpu_to_le16(count);
5182 pSMB->ParameterCount = cpu_to_le16(params);
5183 pSMB->TotalDataCount = pSMB->DataCount;
5184 pSMB->TotalParameterCount = pSMB->ParameterCount;
5185 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5186 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5187 else
5188 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5189 pSMB->Reserved4 = 0;
5190 inc_rfc1001_len(pSMB, byte_count);
5191 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5192 pSMB->ByteCount = cpu_to_le16(byte_count);
5193 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5194 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5195 if (rc)
5196 cFYI(1, "SetPathInfo (times) returned %d", rc);
5198 cifs_buf_release(pSMB);
5200 if (rc == -EAGAIN)
5201 goto SetTimesRetry;
5203 return rc;
5206 /* Can not be used to set time stamps yet (due to old DOS time format) */
5207 /* Can be used to set attributes */
5208 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5209 handling it anyway and NT4 was what we thought it would be needed for
5210 Do not delete it until we prove whether needed for Win9x though */
5212 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5213 __u16 dos_attrs, const struct nls_table *nls_codepage)
5215 SETATTR_REQ *pSMB = NULL;
5216 SETATTR_RSP *pSMBr = NULL;
5217 int rc = 0;
5218 int bytes_returned;
5219 int name_len;
5221 cFYI(1, "In SetAttrLegacy");
5223 SetAttrLgcyRetry:
5224 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5225 (void **) &pSMBr);
5226 if (rc)
5227 return rc;
5229 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5230 name_len =
5231 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
5232 PATH_MAX, nls_codepage);
5233 name_len++; /* trailing null */
5234 name_len *= 2;
5235 } else { /* BB improve the check for buffer overruns BB */
5236 name_len = strnlen(fileName, PATH_MAX);
5237 name_len++; /* trailing null */
5238 strncpy(pSMB->fileName, fileName, name_len);
5240 pSMB->attr = cpu_to_le16(dos_attrs);
5241 pSMB->BufferFormat = 0x04;
5242 inc_rfc1001_len(pSMB, name_len + 1);
5243 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5244 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5245 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5246 if (rc)
5247 cFYI(1, "Error in LegacySetAttr = %d", rc);
5249 cifs_buf_release(pSMB);
5251 if (rc == -EAGAIN)
5252 goto SetAttrLgcyRetry;
5254 return rc;
5256 #endif /* temporarily unneeded SetAttr legacy function */
5258 static void
5259 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5260 const struct cifs_unix_set_info_args *args)
5262 u64 mode = args->mode;
5265 * Samba server ignores set of file size to zero due to bugs in some
5266 * older clients, but we should be precise - we use SetFileSize to
5267 * set file size and do not want to truncate file size to zero
5268 * accidentally as happened on one Samba server beta by putting
5269 * zero instead of -1 here
5271 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5272 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5273 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5274 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5275 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5276 data_offset->Uid = cpu_to_le64(args->uid);
5277 data_offset->Gid = cpu_to_le64(args->gid);
5278 /* better to leave device as zero when it is */
5279 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5280 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5281 data_offset->Permissions = cpu_to_le64(mode);
5283 if (S_ISREG(mode))
5284 data_offset->Type = cpu_to_le32(UNIX_FILE);
5285 else if (S_ISDIR(mode))
5286 data_offset->Type = cpu_to_le32(UNIX_DIR);
5287 else if (S_ISLNK(mode))
5288 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5289 else if (S_ISCHR(mode))
5290 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5291 else if (S_ISBLK(mode))
5292 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5293 else if (S_ISFIFO(mode))
5294 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5295 else if (S_ISSOCK(mode))
5296 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5300 CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5301 const struct cifs_unix_set_info_args *args,
5302 u16 fid, u32 pid_of_opener)
5304 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5305 FILE_UNIX_BASIC_INFO *data_offset;
5306 int rc = 0;
5307 u16 params, param_offset, offset, byte_count, count;
5309 cFYI(1, "Set Unix Info (via SetFileInfo)");
5310 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5312 if (rc)
5313 return rc;
5315 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5316 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5318 params = 6;
5319 pSMB->MaxSetupCount = 0;
5320 pSMB->Reserved = 0;
5321 pSMB->Flags = 0;
5322 pSMB->Timeout = 0;
5323 pSMB->Reserved2 = 0;
5324 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5325 offset = param_offset + params;
5327 data_offset = (FILE_UNIX_BASIC_INFO *)
5328 ((char *)(&pSMB->hdr.Protocol) + offset);
5329 count = sizeof(FILE_UNIX_BASIC_INFO);
5331 pSMB->MaxParameterCount = cpu_to_le16(2);
5332 /* BB find max SMB PDU from sess */
5333 pSMB->MaxDataCount = cpu_to_le16(1000);
5334 pSMB->SetupCount = 1;
5335 pSMB->Reserved3 = 0;
5336 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5337 byte_count = 3 /* pad */ + params + count;
5338 pSMB->DataCount = cpu_to_le16(count);
5339 pSMB->ParameterCount = cpu_to_le16(params);
5340 pSMB->TotalDataCount = pSMB->DataCount;
5341 pSMB->TotalParameterCount = pSMB->ParameterCount;
5342 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5343 pSMB->DataOffset = cpu_to_le16(offset);
5344 pSMB->Fid = fid;
5345 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5346 pSMB->Reserved4 = 0;
5347 inc_rfc1001_len(pSMB, byte_count);
5348 pSMB->ByteCount = cpu_to_le16(byte_count);
5350 cifs_fill_unix_set_info(data_offset, args);
5352 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5353 if (rc)
5354 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
5356 /* Note: On -EAGAIN error only caller can retry on handle based calls
5357 since file handle passed in no longer valid */
5359 return rc;
5363 CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5364 const struct cifs_unix_set_info_args *args,
5365 const struct nls_table *nls_codepage, int remap)
5367 TRANSACTION2_SPI_REQ *pSMB = NULL;
5368 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5369 int name_len;
5370 int rc = 0;
5371 int bytes_returned = 0;
5372 FILE_UNIX_BASIC_INFO *data_offset;
5373 __u16 params, param_offset, offset, count, byte_count;
5375 cFYI(1, "In SetUID/GID/Mode");
5376 setPermsRetry:
5377 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5378 (void **) &pSMBr);
5379 if (rc)
5380 return rc;
5382 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5383 name_len =
5384 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5385 PATH_MAX, nls_codepage, remap);
5386 name_len++; /* trailing null */
5387 name_len *= 2;
5388 } else { /* BB improve the check for buffer overruns BB */
5389 name_len = strnlen(fileName, PATH_MAX);
5390 name_len++; /* trailing null */
5391 strncpy(pSMB->FileName, fileName, name_len);
5394 params = 6 + name_len;
5395 count = sizeof(FILE_UNIX_BASIC_INFO);
5396 pSMB->MaxParameterCount = cpu_to_le16(2);
5397 /* BB find max SMB PDU from sess structure BB */
5398 pSMB->MaxDataCount = cpu_to_le16(1000);
5399 pSMB->MaxSetupCount = 0;
5400 pSMB->Reserved = 0;
5401 pSMB->Flags = 0;
5402 pSMB->Timeout = 0;
5403 pSMB->Reserved2 = 0;
5404 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5405 InformationLevel) - 4;
5406 offset = param_offset + params;
5407 data_offset =
5408 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5409 offset);
5410 memset(data_offset, 0, count);
5411 pSMB->DataOffset = cpu_to_le16(offset);
5412 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5413 pSMB->SetupCount = 1;
5414 pSMB->Reserved3 = 0;
5415 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5416 byte_count = 3 /* pad */ + params + count;
5417 pSMB->ParameterCount = cpu_to_le16(params);
5418 pSMB->DataCount = cpu_to_le16(count);
5419 pSMB->TotalParameterCount = pSMB->ParameterCount;
5420 pSMB->TotalDataCount = pSMB->DataCount;
5421 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5422 pSMB->Reserved4 = 0;
5423 inc_rfc1001_len(pSMB, byte_count);
5425 cifs_fill_unix_set_info(data_offset, args);
5427 pSMB->ByteCount = cpu_to_le16(byte_count);
5428 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5429 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5430 if (rc)
5431 cFYI(1, "SetPathInfo (perms) returned %d", rc);
5433 cifs_buf_release(pSMB);
5434 if (rc == -EAGAIN)
5435 goto setPermsRetry;
5436 return rc;
5439 #ifdef CONFIG_CIFS_XATTR
5441 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5442 * function used by listxattr and getxattr type calls. When ea_name is set,
5443 * it looks for that attribute name and stuffs that value into the EAData
5444 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5445 * buffer. In both cases, the return value is either the length of the
5446 * resulting data or a negative error code. If EAData is a NULL pointer then
5447 * the data isn't copied to it, but the length is returned.
5449 ssize_t
5450 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5451 const unsigned char *searchName, const unsigned char *ea_name,
5452 char *EAData, size_t buf_size,
5453 const struct nls_table *nls_codepage, int remap)
5455 /* BB assumes one setup word */
5456 TRANSACTION2_QPI_REQ *pSMB = NULL;
5457 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5458 int rc = 0;
5459 int bytes_returned;
5460 int list_len;
5461 struct fealist *ea_response_data;
5462 struct fea *temp_fea;
5463 char *temp_ptr;
5464 char *end_of_smb;
5465 __u16 params, byte_count, data_offset;
5467 cFYI(1, "In Query All EAs path %s", searchName);
5468 QAllEAsRetry:
5469 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5470 (void **) &pSMBr);
5471 if (rc)
5472 return rc;
5474 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5475 list_len =
5476 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5477 PATH_MAX, nls_codepage, remap);
5478 list_len++; /* trailing null */
5479 list_len *= 2;
5480 } else { /* BB improve the check for buffer overruns BB */
5481 list_len = strnlen(searchName, PATH_MAX);
5482 list_len++; /* trailing null */
5483 strncpy(pSMB->FileName, searchName, list_len);
5486 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
5487 pSMB->TotalDataCount = 0;
5488 pSMB->MaxParameterCount = cpu_to_le16(2);
5489 /* BB find exact max SMB PDU from sess structure BB */
5490 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
5491 pSMB->MaxSetupCount = 0;
5492 pSMB->Reserved = 0;
5493 pSMB->Flags = 0;
5494 pSMB->Timeout = 0;
5495 pSMB->Reserved2 = 0;
5496 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5497 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5498 pSMB->DataCount = 0;
5499 pSMB->DataOffset = 0;
5500 pSMB->SetupCount = 1;
5501 pSMB->Reserved3 = 0;
5502 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5503 byte_count = params + 1 /* pad */ ;
5504 pSMB->TotalParameterCount = cpu_to_le16(params);
5505 pSMB->ParameterCount = pSMB->TotalParameterCount;
5506 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5507 pSMB->Reserved4 = 0;
5508 inc_rfc1001_len(pSMB, byte_count);
5509 pSMB->ByteCount = cpu_to_le16(byte_count);
5511 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5512 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5513 if (rc) {
5514 cFYI(1, "Send error in QueryAllEAs = %d", rc);
5515 goto QAllEAsOut;
5519 /* BB also check enough total bytes returned */
5520 /* BB we need to improve the validity checking
5521 of these trans2 responses */
5523 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5524 if (rc || get_bcc(&pSMBr->hdr) < 4) {
5525 rc = -EIO; /* bad smb */
5526 goto QAllEAsOut;
5529 /* check that length of list is not more than bcc */
5530 /* check that each entry does not go beyond length
5531 of list */
5532 /* check that each element of each entry does not
5533 go beyond end of list */
5534 /* validate_trans2_offsets() */
5535 /* BB check if start of smb + data_offset > &bcc+ bcc */
5537 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5538 ea_response_data = (struct fealist *)
5539 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5541 list_len = le32_to_cpu(ea_response_data->list_len);
5542 cFYI(1, "ea length %d", list_len);
5543 if (list_len <= 8) {
5544 cFYI(1, "empty EA list returned from server");
5545 goto QAllEAsOut;
5548 /* make sure list_len doesn't go past end of SMB */
5549 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
5550 if ((char *)ea_response_data + list_len > end_of_smb) {
5551 cFYI(1, "EA list appears to go beyond SMB");
5552 rc = -EIO;
5553 goto QAllEAsOut;
5556 /* account for ea list len */
5557 list_len -= 4;
5558 temp_fea = ea_response_data->list;
5559 temp_ptr = (char *)temp_fea;
5560 while (list_len > 0) {
5561 unsigned int name_len;
5562 __u16 value_len;
5564 list_len -= 4;
5565 temp_ptr += 4;
5566 /* make sure we can read name_len and value_len */
5567 if (list_len < 0) {
5568 cFYI(1, "EA entry goes beyond length of list");
5569 rc = -EIO;
5570 goto QAllEAsOut;
5573 name_len = temp_fea->name_len;
5574 value_len = le16_to_cpu(temp_fea->value_len);
5575 list_len -= name_len + 1 + value_len;
5576 if (list_len < 0) {
5577 cFYI(1, "EA entry goes beyond length of list");
5578 rc = -EIO;
5579 goto QAllEAsOut;
5582 if (ea_name) {
5583 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5584 temp_ptr += name_len + 1;
5585 rc = value_len;
5586 if (buf_size == 0)
5587 goto QAllEAsOut;
5588 if ((size_t)value_len > buf_size) {
5589 rc = -ERANGE;
5590 goto QAllEAsOut;
5592 memcpy(EAData, temp_ptr, value_len);
5593 goto QAllEAsOut;
5595 } else {
5596 /* account for prefix user. and trailing null */
5597 rc += (5 + 1 + name_len);
5598 if (rc < (int) buf_size) {
5599 memcpy(EAData, "user.", 5);
5600 EAData += 5;
5601 memcpy(EAData, temp_ptr, name_len);
5602 EAData += name_len;
5603 /* null terminate name */
5604 *EAData = 0;
5605 ++EAData;
5606 } else if (buf_size == 0) {
5607 /* skip copy - calc size only */
5608 } else {
5609 /* stop before overrun buffer */
5610 rc = -ERANGE;
5611 break;
5614 temp_ptr += name_len + 1 + value_len;
5615 temp_fea = (struct fea *)temp_ptr;
5618 /* didn't find the named attribute */
5619 if (ea_name)
5620 rc = -ENODATA;
5622 QAllEAsOut:
5623 cifs_buf_release(pSMB);
5624 if (rc == -EAGAIN)
5625 goto QAllEAsRetry;
5627 return (ssize_t)rc;
5631 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5632 const char *ea_name, const void *ea_value,
5633 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5634 int remap)
5636 struct smb_com_transaction2_spi_req *pSMB = NULL;
5637 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5638 struct fealist *parm_data;
5639 int name_len;
5640 int rc = 0;
5641 int bytes_returned = 0;
5642 __u16 params, param_offset, byte_count, offset, count;
5644 cFYI(1, "In SetEA");
5645 SetEARetry:
5646 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5647 (void **) &pSMBr);
5648 if (rc)
5649 return rc;
5651 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5652 name_len =
5653 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5654 PATH_MAX, nls_codepage, remap);
5655 name_len++; /* trailing null */
5656 name_len *= 2;
5657 } else { /* BB improve the check for buffer overruns BB */
5658 name_len = strnlen(fileName, PATH_MAX);
5659 name_len++; /* trailing null */
5660 strncpy(pSMB->FileName, fileName, name_len);
5663 params = 6 + name_len;
5665 /* done calculating parms using name_len of file name,
5666 now use name_len to calculate length of ea name
5667 we are going to create in the inode xattrs */
5668 if (ea_name == NULL)
5669 name_len = 0;
5670 else
5671 name_len = strnlen(ea_name, 255);
5673 count = sizeof(*parm_data) + ea_value_len + name_len;
5674 pSMB->MaxParameterCount = cpu_to_le16(2);
5675 /* BB find max SMB PDU from sess */
5676 pSMB->MaxDataCount = cpu_to_le16(1000);
5677 pSMB->MaxSetupCount = 0;
5678 pSMB->Reserved = 0;
5679 pSMB->Flags = 0;
5680 pSMB->Timeout = 0;
5681 pSMB->Reserved2 = 0;
5682 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5683 InformationLevel) - 4;
5684 offset = param_offset + params;
5685 pSMB->InformationLevel =
5686 cpu_to_le16(SMB_SET_FILE_EA);
5688 parm_data =
5689 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5690 offset);
5691 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5692 pSMB->DataOffset = cpu_to_le16(offset);
5693 pSMB->SetupCount = 1;
5694 pSMB->Reserved3 = 0;
5695 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5696 byte_count = 3 /* pad */ + params + count;
5697 pSMB->DataCount = cpu_to_le16(count);
5698 parm_data->list_len = cpu_to_le32(count);
5699 parm_data->list[0].EA_flags = 0;
5700 /* we checked above that name len is less than 255 */
5701 parm_data->list[0].name_len = (__u8)name_len;
5702 /* EA names are always ASCII */
5703 if (ea_name)
5704 strncpy(parm_data->list[0].name, ea_name, name_len);
5705 parm_data->list[0].name[name_len] = 0;
5706 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5707 /* caller ensures that ea_value_len is less than 64K but
5708 we need to ensure that it fits within the smb */
5710 /*BB add length check to see if it would fit in
5711 negotiated SMB buffer size BB */
5712 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5713 if (ea_value_len)
5714 memcpy(parm_data->list[0].name+name_len+1,
5715 ea_value, ea_value_len);
5717 pSMB->TotalDataCount = pSMB->DataCount;
5718 pSMB->ParameterCount = cpu_to_le16(params);
5719 pSMB->TotalParameterCount = pSMB->ParameterCount;
5720 pSMB->Reserved4 = 0;
5721 inc_rfc1001_len(pSMB, byte_count);
5722 pSMB->ByteCount = cpu_to_le16(byte_count);
5723 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5724 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5725 if (rc)
5726 cFYI(1, "SetPathInfo (EA) returned %d", rc);
5728 cifs_buf_release(pSMB);
5730 if (rc == -EAGAIN)
5731 goto SetEARetry;
5733 return rc;
5735 #endif
5737 #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
5739 * Years ago the kernel added a "dnotify" function for Samba server,
5740 * to allow network clients (such as Windows) to display updated
5741 * lists of files in directory listings automatically when
5742 * files are added by one user when another user has the
5743 * same directory open on their desktop. The Linux cifs kernel
5744 * client hooked into the kernel side of this interface for
5745 * the same reason, but ironically when the VFS moved from
5746 * "dnotify" to "inotify" it became harder to plug in Linux
5747 * network file system clients (the most obvious use case
5748 * for notify interfaces is when multiple users can update
5749 * the contents of the same directory - exactly what network
5750 * file systems can do) although the server (Samba) could
5751 * still use it. For the short term we leave the worker
5752 * function ifdeffed out (below) until inotify is fixed
5753 * in the VFS to make it easier to plug in network file
5754 * system clients. If inotify turns out to be permanently
5755 * incompatible for network fs clients, we could instead simply
5756 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
5758 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5759 const int notify_subdirs, const __u16 netfid,
5760 __u32 filter, struct file *pfile, int multishot,
5761 const struct nls_table *nls_codepage)
5763 int rc = 0;
5764 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5765 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5766 struct dir_notify_req *dnotify_req;
5767 int bytes_returned;
5769 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
5770 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5771 (void **) &pSMBr);
5772 if (rc)
5773 return rc;
5775 pSMB->TotalParameterCount = 0 ;
5776 pSMB->TotalDataCount = 0;
5777 pSMB->MaxParameterCount = cpu_to_le32(2);
5778 /* BB find exact data count max from sess structure BB */
5779 pSMB->MaxDataCount = 0; /* same in little endian or be */
5780 /* BB VERIFY verify which is correct for above BB */
5781 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5782 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5784 pSMB->MaxSetupCount = 4;
5785 pSMB->Reserved = 0;
5786 pSMB->ParameterOffset = 0;
5787 pSMB->DataCount = 0;
5788 pSMB->DataOffset = 0;
5789 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5790 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5791 pSMB->ParameterCount = pSMB->TotalParameterCount;
5792 if (notify_subdirs)
5793 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5794 pSMB->Reserved2 = 0;
5795 pSMB->CompletionFilter = cpu_to_le32(filter);
5796 pSMB->Fid = netfid; /* file handle always le */
5797 pSMB->ByteCount = 0;
5799 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5800 (struct smb_hdr *)pSMBr, &bytes_returned,
5801 CIFS_ASYNC_OP);
5802 if (rc) {
5803 cFYI(1, "Error in Notify = %d", rc);
5804 } else {
5805 /* Add file to outstanding requests */
5806 /* BB change to kmem cache alloc */
5807 dnotify_req = kmalloc(
5808 sizeof(struct dir_notify_req),
5809 GFP_KERNEL);
5810 if (dnotify_req) {
5811 dnotify_req->Pid = pSMB->hdr.Pid;
5812 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5813 dnotify_req->Mid = pSMB->hdr.Mid;
5814 dnotify_req->Tid = pSMB->hdr.Tid;
5815 dnotify_req->Uid = pSMB->hdr.Uid;
5816 dnotify_req->netfid = netfid;
5817 dnotify_req->pfile = pfile;
5818 dnotify_req->filter = filter;
5819 dnotify_req->multishot = multishot;
5820 spin_lock(&GlobalMid_Lock);
5821 list_add_tail(&dnotify_req->lhead,
5822 &GlobalDnotifyReqList);
5823 spin_unlock(&GlobalMid_Lock);
5824 } else
5825 rc = -ENOMEM;
5827 cifs_buf_release(pSMB);
5828 return rc;
5830 #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */