[CIFS] pSesInfo->sesSem is used as mutex. Rename it to session_mutex and
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / cifs / cifssmb.c
blob9d17df3e076860924d072605e13f4a97cbb438cf
1 /*
2 * fs/cifs/cifssmb.c
4 * Copyright (C) International Business Machines Corp., 2002,2009
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/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsacl.h"
38 #include "cifsproto.h"
39 #include "cifs_unicode.h"
40 #include "cifs_debug.h"
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44 int index;
45 char *name;
46 } protocols[] = {
47 #ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
49 {LANMAN2_PROT, "\2LANMAN2.1"},
50 #endif /* weak password hashing for legacy clients */
51 {CIFS_PROT, "\2NT LM 0.12"},
52 {POSIX_PROT, "\2POSIX 2"},
53 {BAD_PROT, "\2"}
55 #else
56 static struct {
57 int index;
58 char *name;
59 } protocols[] = {
60 #ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
62 {LANMAN2_PROT, "\2LANMAN2.1"},
63 #endif /* weak password hashing for legacy clients */
64 {CIFS_PROT, "\2NT LM 0.12"},
65 {BAD_PROT, "\2"}
67 #endif
69 /* define the number of elements in the cifs dialect array */
70 #ifdef CONFIG_CIFS_POSIX
71 #ifdef CONFIG_CIFS_WEAK_PW_HASH
72 #define CIFS_NUM_PROT 4
73 #else
74 #define CIFS_NUM_PROT 2
75 #endif /* CIFS_WEAK_PW_HASH */
76 #else /* not posix */
77 #ifdef CONFIG_CIFS_WEAK_PW_HASH
78 #define CIFS_NUM_PROT 3
79 #else
80 #define CIFS_NUM_PROT 1
81 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
82 #endif /* CIFS_POSIX */
84 /* Mark as invalid, all open files on tree connections since they
85 were closed when session to server was lost */
86 static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
88 struct cifsFileInfo *open_file = NULL;
89 struct list_head *tmp;
90 struct list_head *tmp1;
92 /* list all files open on tree connection and mark them invalid */
93 write_lock(&GlobalSMBSeslock);
94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
95 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
96 open_file->invalidHandle = true;
97 open_file->oplock_break_cancelled = true;
99 write_unlock(&GlobalSMBSeslock);
100 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
101 to this tcon */
104 /* reconnect the socket, tcon, and smb session if needed */
105 static int
106 cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
108 int rc = 0;
109 struct cifsSesInfo *ses;
110 struct TCP_Server_Info *server;
111 struct nls_table *nls_codepage;
114 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
115 * tcp and smb session status done differently for those three - in the
116 * calling routine
118 if (!tcon)
119 return 0;
121 ses = tcon->ses;
122 server = ses->server;
125 * only tree disconnect, open, and write, (and ulogoff which does not
126 * have tcon) are allowed as we start force umount
128 if (tcon->tidStatus == CifsExiting) {
129 if (smb_command != SMB_COM_WRITE_ANDX &&
130 smb_command != SMB_COM_OPEN_ANDX &&
131 smb_command != SMB_COM_TREE_DISCONNECT) {
132 cFYI(1, ("can not send cmd %d while umounting",
133 smb_command));
134 return -ENODEV;
138 if (ses->status == CifsExiting)
139 return -EIO;
142 * Give demultiplex thread up to 10 seconds to reconnect, should be
143 * greater than cifs socket timeout which is 7 seconds
145 while (server->tcpStatus == CifsNeedReconnect) {
146 wait_event_interruptible_timeout(server->response_q,
147 (server->tcpStatus == CifsGood), 10 * HZ);
149 /* is TCP session is reestablished now ?*/
150 if (server->tcpStatus != CifsNeedReconnect)
151 break;
154 * on "soft" mounts we wait once. Hard mounts keep
155 * retrying until process is killed or server comes
156 * back on-line
158 if (!tcon->retry || ses->status == CifsExiting) {
159 cFYI(1, ("gave up waiting on reconnect in smb_init"));
160 return -EHOSTDOWN;
164 if (!ses->need_reconnect && !tcon->need_reconnect)
165 return 0;
167 nls_codepage = load_nls_default();
170 * need to prevent multiple threads trying to simultaneously
171 * reconnect the same SMB session
173 mutex_lock(&ses->session_mutex);
174 if (ses->need_reconnect)
175 rc = cifs_setup_session(0, ses, nls_codepage);
177 /* do we need to reconnect tcon? */
178 if (rc || !tcon->need_reconnect) {
179 mutex_unlock(&ses->session_mutex);
180 goto out;
183 mark_open_files_invalid(tcon);
184 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
185 mutex_unlock(&ses->session_mutex);
186 cFYI(1, ("reconnect tcon rc = %d", rc));
188 if (rc)
189 goto out;
192 * FIXME: check if wsize needs updated due to negotiated smb buffer
193 * size shrinking
195 atomic_inc(&tconInfoReconnectCount);
197 /* tell server Unix caps we support */
198 if (ses->capabilities & CAP_UNIX)
199 reset_cifs_unix_caps(0, tcon, NULL, NULL);
202 * Removed call to reopen open files here. It is safer (and faster) to
203 * reopen files one at a time as needed in read and write.
205 * FIXME: what about file locks? don't we need to reclaim them ASAP?
208 out:
210 * Check if handle based operation so we know whether we can continue
211 * or not without returning to caller to reset file handle
213 switch (smb_command) {
214 case SMB_COM_READ_ANDX:
215 case SMB_COM_WRITE_ANDX:
216 case SMB_COM_CLOSE:
217 case SMB_COM_FIND_CLOSE2:
218 case SMB_COM_LOCKING_ANDX:
219 rc = -EAGAIN;
222 unload_nls(nls_codepage);
223 return rc;
226 /* Allocate and return pointer to an SMB request buffer, and set basic
227 SMB information in the SMB header. If the return code is zero, this
228 function must have filled in request_buf pointer */
229 static int
230 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
231 void **request_buf)
233 int rc = 0;
235 rc = cifs_reconnect_tcon(tcon, smb_command);
236 if (rc)
237 return rc;
239 *request_buf = cifs_small_buf_get();
240 if (*request_buf == NULL) {
241 /* BB should we add a retry in here if not a writepage? */
242 return -ENOMEM;
245 header_assemble((struct smb_hdr *) *request_buf, smb_command,
246 tcon, wct);
248 if (tcon != NULL)
249 cifs_stats_inc(&tcon->num_smbs_sent);
251 return rc;
255 small_smb_init_no_tc(const int smb_command, const int wct,
256 struct cifsSesInfo *ses, void **request_buf)
258 int rc;
259 struct smb_hdr *buffer;
261 rc = small_smb_init(smb_command, wct, NULL, request_buf);
262 if (rc)
263 return rc;
265 buffer = (struct smb_hdr *)*request_buf;
266 buffer->Mid = GetNextMid(ses->server);
267 if (ses->capabilities & CAP_UNICODE)
268 buffer->Flags2 |= SMBFLG2_UNICODE;
269 if (ses->capabilities & CAP_STATUS32)
270 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
272 /* uid, tid can stay at zero as set in header assemble */
274 /* BB add support for turning on the signing when
275 this function is used after 1st of session setup requests */
277 return rc;
280 /* If the return code is zero, this function must fill in request_buf pointer */
281 static int
282 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
283 void **request_buf /* returned */ ,
284 void **response_buf /* returned */ )
286 int rc = 0;
288 rc = cifs_reconnect_tcon(tcon, smb_command);
289 if (rc)
290 return rc;
292 *request_buf = cifs_buf_get();
293 if (*request_buf == NULL) {
294 /* BB should we add a retry in here if not a writepage? */
295 return -ENOMEM;
297 /* Although the original thought was we needed the response buf for */
298 /* potential retries of smb operations it turns out we can determine */
299 /* from the mid flags when the request buffer can be resent without */
300 /* having to use a second distinct buffer for the response */
301 if (response_buf)
302 *response_buf = *request_buf;
304 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
305 wct);
307 if (tcon != NULL)
308 cifs_stats_inc(&tcon->num_smbs_sent);
310 return rc;
313 static int validate_t2(struct smb_t2_rsp *pSMB)
315 int rc = -EINVAL;
316 int total_size;
317 char *pBCC;
319 /* check for plausible wct, bcc and t2 data and parm sizes */
320 /* check for parm and data offset going beyond end of smb */
321 if (pSMB->hdr.WordCount >= 10) {
322 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
323 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
324 /* check that bcc is at least as big as parms + data */
325 /* check that bcc is less than negotiated smb buffer */
326 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
327 if (total_size < 512) {
328 total_size +=
329 le16_to_cpu(pSMB->t2_rsp.DataCount);
330 /* BCC le converted in SendReceive */
331 pBCC = (pSMB->hdr.WordCount * 2) +
332 sizeof(struct smb_hdr) +
333 (char *)pSMB;
334 if ((total_size <= (*(u16 *)pBCC)) &&
335 (total_size <
336 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
337 return 0;
342 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
343 sizeof(struct smb_t2_rsp) + 16);
344 return rc;
347 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
349 NEGOTIATE_REQ *pSMB;
350 NEGOTIATE_RSP *pSMBr;
351 int rc = 0;
352 int bytes_returned;
353 int i;
354 struct TCP_Server_Info *server;
355 u16 count;
356 unsigned int secFlags;
357 u16 dialect;
359 if (ses->server)
360 server = ses->server;
361 else {
362 rc = -EIO;
363 return rc;
365 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
366 (void **) &pSMB, (void **) &pSMBr);
367 if (rc)
368 return rc;
370 /* if any of auth flags (ie not sign or seal) are overriden use them */
371 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
372 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
373 else /* if override flags set only sign/seal OR them with global auth */
374 secFlags = extended_security | ses->overrideSecFlg;
376 cFYI(1, ("secFlags 0x%x", secFlags));
378 pSMB->hdr.Mid = GetNextMid(server);
379 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
381 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
382 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
383 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
384 cFYI(1, ("Kerberos only mechanism, enable extended security"));
385 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
387 #ifdef CONFIG_CIFS_EXPERIMENTAL
388 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
389 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
390 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
391 cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
392 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
394 #endif
396 count = 0;
397 for (i = 0; i < CIFS_NUM_PROT; i++) {
398 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
399 count += strlen(protocols[i].name) + 1;
400 /* null at end of source and target buffers anyway */
402 pSMB->hdr.smb_buf_length += count;
403 pSMB->ByteCount = cpu_to_le16(count);
405 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
406 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
407 if (rc != 0)
408 goto neg_err_exit;
410 dialect = le16_to_cpu(pSMBr->DialectIndex);
411 cFYI(1, ("Dialect: %d", dialect));
412 /* Check wct = 1 error case */
413 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
414 /* core returns wct = 1, but we do not ask for core - otherwise
415 small wct just comes when dialect index is -1 indicating we
416 could not negotiate a common dialect */
417 rc = -EOPNOTSUPP;
418 goto neg_err_exit;
419 #ifdef CONFIG_CIFS_WEAK_PW_HASH
420 } else if ((pSMBr->hdr.WordCount == 13)
421 && ((dialect == LANMAN_PROT)
422 || (dialect == LANMAN2_PROT))) {
423 __s16 tmp;
424 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
426 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
427 (secFlags & CIFSSEC_MAY_PLNTXT))
428 server->secType = LANMAN;
429 else {
430 cERROR(1, ("mount failed weak security disabled"
431 " in /proc/fs/cifs/SecurityFlags"));
432 rc = -EOPNOTSUPP;
433 goto neg_err_exit;
435 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
436 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
437 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
438 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
439 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
440 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
441 /* even though we do not use raw we might as well set this
442 accurately, in case we ever find a need for it */
443 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
444 server->max_rw = 0xFF00;
445 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
446 } else {
447 server->max_rw = 0;/* do not need to use raw anyway */
448 server->capabilities = CAP_MPX_MODE;
450 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
451 if (tmp == -1) {
452 /* OS/2 often does not set timezone therefore
453 * we must use server time to calc time zone.
454 * Could deviate slightly from the right zone.
455 * Smallest defined timezone difference is 15 minutes
456 * (i.e. Nepal). Rounding up/down is done to match
457 * this requirement.
459 int val, seconds, remain, result;
460 struct timespec ts, utc;
461 utc = CURRENT_TIME;
462 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
463 rsp->SrvTime.Time, 0);
464 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
465 (int)ts.tv_sec, (int)utc.tv_sec,
466 (int)(utc.tv_sec - ts.tv_sec)));
467 val = (int)(utc.tv_sec - ts.tv_sec);
468 seconds = abs(val);
469 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
470 remain = seconds % MIN_TZ_ADJ;
471 if (remain >= (MIN_TZ_ADJ / 2))
472 result += MIN_TZ_ADJ;
473 if (val < 0)
474 result = -result;
475 server->timeAdj = result;
476 } else {
477 server->timeAdj = (int)tmp;
478 server->timeAdj *= 60; /* also in seconds */
480 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
483 /* BB get server time for time conversions and add
484 code to use it and timezone since this is not UTC */
486 if (rsp->EncryptionKeyLength ==
487 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
488 memcpy(server->cryptKey, rsp->EncryptionKey,
489 CIFS_CRYPTO_KEY_SIZE);
490 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
491 rc = -EIO; /* need cryptkey unless plain text */
492 goto neg_err_exit;
495 cFYI(1, ("LANMAN negotiated"));
496 /* we will not end up setting signing flags - as no signing
497 was in LANMAN and server did not return the flags on */
498 goto signing_check;
499 #else /* weak security disabled */
500 } else if (pSMBr->hdr.WordCount == 13) {
501 cERROR(1, ("mount failed, cifs module not built "
502 "with CIFS_WEAK_PW_HASH support"));
503 rc = -EOPNOTSUPP;
504 #endif /* WEAK_PW_HASH */
505 goto neg_err_exit;
506 } else if (pSMBr->hdr.WordCount != 17) {
507 /* unknown wct */
508 rc = -EOPNOTSUPP;
509 goto neg_err_exit;
511 /* else wct == 17 NTLM */
512 server->secMode = pSMBr->SecurityMode;
513 if ((server->secMode & SECMODE_USER) == 0)
514 cFYI(1, ("share mode security"));
516 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
517 #ifdef CONFIG_CIFS_WEAK_PW_HASH
518 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
519 #endif /* CIFS_WEAK_PW_HASH */
520 cERROR(1, ("Server requests plain text password"
521 " but client support disabled"));
523 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
524 server->secType = NTLMv2;
525 else if (secFlags & CIFSSEC_MAY_NTLM)
526 server->secType = NTLM;
527 else if (secFlags & CIFSSEC_MAY_NTLMV2)
528 server->secType = NTLMv2;
529 else if (secFlags & CIFSSEC_MAY_KRB5)
530 server->secType = Kerberos;
531 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
532 server->secType = RawNTLMSSP;
533 else if (secFlags & CIFSSEC_MAY_LANMAN)
534 server->secType = LANMAN;
535 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
536 else if (secFlags & CIFSSEC_MAY_PLNTXT)
537 server->secType = ??
538 #endif */
539 else {
540 rc = -EOPNOTSUPP;
541 cERROR(1, ("Invalid security type"));
542 goto neg_err_exit;
544 /* else ... any others ...? */
546 /* one byte, so no need to convert this or EncryptionKeyLen from
547 little endian */
548 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
549 /* probably no need to store and check maxvcs */
550 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
551 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
552 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
553 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
554 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
555 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
556 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
557 server->timeAdj *= 60;
558 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
559 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
560 CIFS_CRYPTO_KEY_SIZE);
561 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
562 && (pSMBr->EncryptionKeyLength == 0)) {
563 /* decode security blob */
564 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
565 rc = -EIO; /* no crypt key only if plain text pwd */
566 goto neg_err_exit;
569 /* BB might be helpful to save off the domain of server here */
571 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
572 (server->capabilities & CAP_EXTENDED_SECURITY)) {
573 count = pSMBr->ByteCount;
574 if (count < 16) {
575 rc = -EIO;
576 goto neg_err_exit;
578 read_lock(&cifs_tcp_ses_lock);
579 if (server->srv_count > 1) {
580 read_unlock(&cifs_tcp_ses_lock);
581 if (memcmp(server->server_GUID,
582 pSMBr->u.extended_response.
583 GUID, 16) != 0) {
584 cFYI(1, ("server UID changed"));
585 memcpy(server->server_GUID,
586 pSMBr->u.extended_response.GUID,
587 16);
589 } else {
590 read_unlock(&cifs_tcp_ses_lock);
591 memcpy(server->server_GUID,
592 pSMBr->u.extended_response.GUID, 16);
595 if (count == 16) {
596 server->secType = RawNTLMSSP;
597 } else {
598 rc = decode_negTokenInit(pSMBr->u.extended_response.
599 SecurityBlob,
600 count - 16,
601 &server->secType);
602 if (rc == 1)
603 rc = 0;
604 else
605 rc = -EINVAL;
607 } else
608 server->capabilities &= ~CAP_EXTENDED_SECURITY;
610 #ifdef CONFIG_CIFS_WEAK_PW_HASH
611 signing_check:
612 #endif
613 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
614 /* MUST_SIGN already includes the MAY_SIGN FLAG
615 so if this is zero it means that signing is disabled */
616 cFYI(1, ("Signing disabled"));
617 if (server->secMode & SECMODE_SIGN_REQUIRED) {
618 cERROR(1, ("Server requires "
619 "packet signing to be enabled in "
620 "/proc/fs/cifs/SecurityFlags."));
621 rc = -EOPNOTSUPP;
623 server->secMode &=
624 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
625 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
626 /* signing required */
627 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
628 if ((server->secMode &
629 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
630 cERROR(1,
631 ("signing required but server lacks support"));
632 rc = -EOPNOTSUPP;
633 } else
634 server->secMode |= SECMODE_SIGN_REQUIRED;
635 } else {
636 /* signing optional ie CIFSSEC_MAY_SIGN */
637 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
638 server->secMode &=
639 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
642 neg_err_exit:
643 cifs_buf_release(pSMB);
645 cFYI(1, ("negprot rc %d", rc));
646 return rc;
650 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
652 struct smb_hdr *smb_buffer;
653 int rc = 0;
655 cFYI(1, ("In tree disconnect"));
657 /* BB: do we need to check this? These should never be NULL. */
658 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
659 return -EIO;
662 * No need to return error on this operation if tid invalidated and
663 * closed on server already e.g. due to tcp session crashing. Also,
664 * the tcon is no longer on the list, so no need to take lock before
665 * checking this.
667 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
668 return 0;
670 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
671 (void **)&smb_buffer);
672 if (rc)
673 return rc;
675 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
676 if (rc)
677 cFYI(1, ("Tree disconnect failed %d", rc));
679 /* No need to return error on this operation if tid invalidated and
680 closed on server already e.g. due to tcp session crashing */
681 if (rc == -EAGAIN)
682 rc = 0;
684 return rc;
688 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
690 LOGOFF_ANDX_REQ *pSMB;
691 int rc = 0;
693 cFYI(1, ("In SMBLogoff for session disconnect"));
696 * BB: do we need to check validity of ses and server? They should
697 * always be valid since we have an active reference. If not, that
698 * should probably be a BUG()
700 if (!ses || !ses->server)
701 return -EIO;
703 mutex_lock(&ses->session_mutex);
704 if (ses->need_reconnect)
705 goto session_already_dead; /* no need to send SMBlogoff if uid
706 already closed due to reconnect */
707 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
708 if (rc) {
709 mutex_unlock(&ses->session_mutex);
710 return rc;
713 pSMB->hdr.Mid = GetNextMid(ses->server);
715 if (ses->server->secMode &
716 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
717 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
719 pSMB->hdr.Uid = ses->Suid;
721 pSMB->AndXCommand = 0xFF;
722 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
723 session_already_dead:
724 mutex_unlock(&ses->session_mutex);
726 /* if session dead then we do not need to do ulogoff,
727 since server closed smb session, no sense reporting
728 error */
729 if (rc == -EAGAIN)
730 rc = 0;
731 return rc;
735 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
736 __u16 type, const struct nls_table *nls_codepage, int remap)
738 TRANSACTION2_SPI_REQ *pSMB = NULL;
739 TRANSACTION2_SPI_RSP *pSMBr = NULL;
740 struct unlink_psx_rq *pRqD;
741 int name_len;
742 int rc = 0;
743 int bytes_returned = 0;
744 __u16 params, param_offset, offset, byte_count;
746 cFYI(1, ("In POSIX delete"));
747 PsxDelete:
748 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
749 (void **) &pSMBr);
750 if (rc)
751 return rc;
753 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
754 name_len =
755 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
756 PATH_MAX, nls_codepage, remap);
757 name_len++; /* trailing null */
758 name_len *= 2;
759 } else { /* BB add path length overrun check */
760 name_len = strnlen(fileName, PATH_MAX);
761 name_len++; /* trailing null */
762 strncpy(pSMB->FileName, fileName, name_len);
765 params = 6 + name_len;
766 pSMB->MaxParameterCount = cpu_to_le16(2);
767 pSMB->MaxDataCount = 0; /* BB double check this with jra */
768 pSMB->MaxSetupCount = 0;
769 pSMB->Reserved = 0;
770 pSMB->Flags = 0;
771 pSMB->Timeout = 0;
772 pSMB->Reserved2 = 0;
773 param_offset = offsetof(struct smb_com_transaction2_spi_req,
774 InformationLevel) - 4;
775 offset = param_offset + params;
777 /* Setup pointer to Request Data (inode type) */
778 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
779 pRqD->type = cpu_to_le16(type);
780 pSMB->ParameterOffset = cpu_to_le16(param_offset);
781 pSMB->DataOffset = cpu_to_le16(offset);
782 pSMB->SetupCount = 1;
783 pSMB->Reserved3 = 0;
784 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
785 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
787 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
788 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
789 pSMB->ParameterCount = cpu_to_le16(params);
790 pSMB->TotalParameterCount = pSMB->ParameterCount;
791 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
792 pSMB->Reserved4 = 0;
793 pSMB->hdr.smb_buf_length += byte_count;
794 pSMB->ByteCount = cpu_to_le16(byte_count);
795 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
796 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
797 if (rc)
798 cFYI(1, ("Posix delete returned %d", rc));
799 cifs_buf_release(pSMB);
801 cifs_stats_inc(&tcon->num_deletes);
803 if (rc == -EAGAIN)
804 goto PsxDelete;
806 return rc;
810 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
811 const struct nls_table *nls_codepage, int remap)
813 DELETE_FILE_REQ *pSMB = NULL;
814 DELETE_FILE_RSP *pSMBr = NULL;
815 int rc = 0;
816 int bytes_returned;
817 int name_len;
819 DelFileRetry:
820 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
821 (void **) &pSMBr);
822 if (rc)
823 return rc;
825 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
826 name_len =
827 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
828 PATH_MAX, nls_codepage, remap);
829 name_len++; /* trailing null */
830 name_len *= 2;
831 } else { /* BB improve check for buffer overruns BB */
832 name_len = strnlen(fileName, PATH_MAX);
833 name_len++; /* trailing null */
834 strncpy(pSMB->fileName, fileName, name_len);
836 pSMB->SearchAttributes =
837 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
838 pSMB->BufferFormat = 0x04;
839 pSMB->hdr.smb_buf_length += name_len + 1;
840 pSMB->ByteCount = cpu_to_le16(name_len + 1);
841 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
842 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
843 cifs_stats_inc(&tcon->num_deletes);
844 if (rc)
845 cFYI(1, ("Error in RMFile = %d", rc));
847 cifs_buf_release(pSMB);
848 if (rc == -EAGAIN)
849 goto DelFileRetry;
851 return rc;
855 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
856 const struct nls_table *nls_codepage, int remap)
858 DELETE_DIRECTORY_REQ *pSMB = NULL;
859 DELETE_DIRECTORY_RSP *pSMBr = NULL;
860 int rc = 0;
861 int bytes_returned;
862 int name_len;
864 cFYI(1, ("In CIFSSMBRmDir"));
865 RmDirRetry:
866 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
867 (void **) &pSMBr);
868 if (rc)
869 return rc;
871 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
872 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
873 PATH_MAX, nls_codepage, remap);
874 name_len++; /* trailing null */
875 name_len *= 2;
876 } else { /* BB improve check for buffer overruns BB */
877 name_len = strnlen(dirName, PATH_MAX);
878 name_len++; /* trailing null */
879 strncpy(pSMB->DirName, dirName, name_len);
882 pSMB->BufferFormat = 0x04;
883 pSMB->hdr.smb_buf_length += name_len + 1;
884 pSMB->ByteCount = cpu_to_le16(name_len + 1);
885 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
886 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
887 cifs_stats_inc(&tcon->num_rmdirs);
888 if (rc)
889 cFYI(1, ("Error in RMDir = %d", rc));
891 cifs_buf_release(pSMB);
892 if (rc == -EAGAIN)
893 goto RmDirRetry;
894 return rc;
898 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
899 const char *name, const struct nls_table *nls_codepage, int remap)
901 int rc = 0;
902 CREATE_DIRECTORY_REQ *pSMB = NULL;
903 CREATE_DIRECTORY_RSP *pSMBr = NULL;
904 int bytes_returned;
905 int name_len;
907 cFYI(1, ("In CIFSSMBMkDir"));
908 MkDirRetry:
909 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
910 (void **) &pSMBr);
911 if (rc)
912 return rc;
914 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
915 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
916 PATH_MAX, nls_codepage, remap);
917 name_len++; /* trailing null */
918 name_len *= 2;
919 } else { /* BB improve check for buffer overruns BB */
920 name_len = strnlen(name, PATH_MAX);
921 name_len++; /* trailing null */
922 strncpy(pSMB->DirName, name, name_len);
925 pSMB->BufferFormat = 0x04;
926 pSMB->hdr.smb_buf_length += name_len + 1;
927 pSMB->ByteCount = cpu_to_le16(name_len + 1);
928 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
929 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
930 cifs_stats_inc(&tcon->num_mkdirs);
931 if (rc)
932 cFYI(1, ("Error in Mkdir = %d", rc));
934 cifs_buf_release(pSMB);
935 if (rc == -EAGAIN)
936 goto MkDirRetry;
937 return rc;
941 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
942 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
943 __u32 *pOplock, const char *name,
944 const struct nls_table *nls_codepage, int remap)
946 TRANSACTION2_SPI_REQ *pSMB = NULL;
947 TRANSACTION2_SPI_RSP *pSMBr = NULL;
948 int name_len;
949 int rc = 0;
950 int bytes_returned = 0;
951 __u16 params, param_offset, offset, byte_count, count;
952 OPEN_PSX_REQ *pdata;
953 OPEN_PSX_RSP *psx_rsp;
955 cFYI(1, ("In POSIX Create"));
956 PsxCreat:
957 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
958 (void **) &pSMBr);
959 if (rc)
960 return rc;
962 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
963 name_len =
964 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
965 PATH_MAX, nls_codepage, remap);
966 name_len++; /* trailing null */
967 name_len *= 2;
968 } else { /* BB improve the check for buffer overruns BB */
969 name_len = strnlen(name, PATH_MAX);
970 name_len++; /* trailing null */
971 strncpy(pSMB->FileName, name, name_len);
974 params = 6 + name_len;
975 count = sizeof(OPEN_PSX_REQ);
976 pSMB->MaxParameterCount = cpu_to_le16(2);
977 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
978 pSMB->MaxSetupCount = 0;
979 pSMB->Reserved = 0;
980 pSMB->Flags = 0;
981 pSMB->Timeout = 0;
982 pSMB->Reserved2 = 0;
983 param_offset = offsetof(struct smb_com_transaction2_spi_req,
984 InformationLevel) - 4;
985 offset = param_offset + params;
986 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
987 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
988 pdata->Permissions = cpu_to_le64(mode);
989 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
990 pdata->OpenFlags = cpu_to_le32(*pOplock);
991 pSMB->ParameterOffset = cpu_to_le16(param_offset);
992 pSMB->DataOffset = cpu_to_le16(offset);
993 pSMB->SetupCount = 1;
994 pSMB->Reserved3 = 0;
995 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
996 byte_count = 3 /* pad */ + params + count;
998 pSMB->DataCount = cpu_to_le16(count);
999 pSMB->ParameterCount = cpu_to_le16(params);
1000 pSMB->TotalDataCount = pSMB->DataCount;
1001 pSMB->TotalParameterCount = pSMB->ParameterCount;
1002 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1003 pSMB->Reserved4 = 0;
1004 pSMB->hdr.smb_buf_length += byte_count;
1005 pSMB->ByteCount = cpu_to_le16(byte_count);
1006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1008 if (rc) {
1009 cFYI(1, ("Posix create returned %d", rc));
1010 goto psx_create_err;
1013 cFYI(1, ("copying inode info"));
1014 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1016 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1017 rc = -EIO; /* bad smb */
1018 goto psx_create_err;
1021 /* copy return information to pRetData */
1022 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1023 + le16_to_cpu(pSMBr->t2.DataOffset));
1025 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1026 if (netfid)
1027 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1028 /* Let caller know file was created so we can set the mode. */
1029 /* Do we care about the CreateAction in any other cases? */
1030 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1031 *pOplock |= CIFS_CREATE_ACTION;
1032 /* check to make sure response data is there */
1033 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1034 pRetData->Type = cpu_to_le32(-1); /* unknown */
1035 cFYI(DBG2, ("unknown type"));
1036 } else {
1037 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1038 + sizeof(FILE_UNIX_BASIC_INFO)) {
1039 cERROR(1, ("Open response data too small"));
1040 pRetData->Type = cpu_to_le32(-1);
1041 goto psx_create_err;
1043 memcpy((char *) pRetData,
1044 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1045 sizeof(FILE_UNIX_BASIC_INFO));
1048 psx_create_err:
1049 cifs_buf_release(pSMB);
1051 if (posix_flags & SMB_O_DIRECTORY)
1052 cifs_stats_inc(&tcon->num_posixmkdirs);
1053 else
1054 cifs_stats_inc(&tcon->num_posixopens);
1056 if (rc == -EAGAIN)
1057 goto PsxCreat;
1059 return rc;
1062 static __u16 convert_disposition(int disposition)
1064 __u16 ofun = 0;
1066 switch (disposition) {
1067 case FILE_SUPERSEDE:
1068 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1069 break;
1070 case FILE_OPEN:
1071 ofun = SMBOPEN_OAPPEND;
1072 break;
1073 case FILE_CREATE:
1074 ofun = SMBOPEN_OCREATE;
1075 break;
1076 case FILE_OPEN_IF:
1077 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1078 break;
1079 case FILE_OVERWRITE:
1080 ofun = SMBOPEN_OTRUNC;
1081 break;
1082 case FILE_OVERWRITE_IF:
1083 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1084 break;
1085 default:
1086 cFYI(1, ("unknown disposition %d", disposition));
1087 ofun = SMBOPEN_OAPPEND; /* regular open */
1089 return ofun;
1092 static int
1093 access_flags_to_smbopen_mode(const int access_flags)
1095 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1097 if (masked_flags == GENERIC_READ)
1098 return SMBOPEN_READ;
1099 else if (masked_flags == GENERIC_WRITE)
1100 return SMBOPEN_WRITE;
1102 /* just go for read/write */
1103 return SMBOPEN_READWRITE;
1107 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1108 const char *fileName, const int openDisposition,
1109 const int access_flags, const int create_options, __u16 *netfid,
1110 int *pOplock, FILE_ALL_INFO *pfile_info,
1111 const struct nls_table *nls_codepage, int remap)
1113 int rc = -EACCES;
1114 OPENX_REQ *pSMB = NULL;
1115 OPENX_RSP *pSMBr = NULL;
1116 int bytes_returned;
1117 int name_len;
1118 __u16 count;
1120 OldOpenRetry:
1121 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1122 (void **) &pSMBr);
1123 if (rc)
1124 return rc;
1126 pSMB->AndXCommand = 0xFF; /* none */
1128 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1129 count = 1; /* account for one byte pad to word boundary */
1130 name_len =
1131 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1132 fileName, PATH_MAX, nls_codepage, remap);
1133 name_len++; /* trailing null */
1134 name_len *= 2;
1135 } else { /* BB improve check for buffer overruns BB */
1136 count = 0; /* no pad */
1137 name_len = strnlen(fileName, PATH_MAX);
1138 name_len++; /* trailing null */
1139 strncpy(pSMB->fileName, fileName, name_len);
1141 if (*pOplock & REQ_OPLOCK)
1142 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1143 else if (*pOplock & REQ_BATCHOPLOCK)
1144 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1146 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1147 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1148 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1149 /* set file as system file if special file such
1150 as fifo and server expecting SFU style and
1151 no Unix extensions */
1153 if (create_options & CREATE_OPTION_SPECIAL)
1154 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1155 else /* BB FIXME BB */
1156 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1158 if (create_options & CREATE_OPTION_READONLY)
1159 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1161 /* BB FIXME BB */
1162 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1163 CREATE_OPTIONS_MASK); */
1164 /* BB FIXME END BB */
1166 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1167 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1168 count += name_len;
1169 pSMB->hdr.smb_buf_length += count;
1171 pSMB->ByteCount = cpu_to_le16(count);
1172 /* long_op set to 1 to allow for oplock break timeouts */
1173 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1174 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1175 cifs_stats_inc(&tcon->num_opens);
1176 if (rc) {
1177 cFYI(1, ("Error in Open = %d", rc));
1178 } else {
1179 /* BB verify if wct == 15 */
1181 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1183 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1184 /* Let caller know file was created so we can set the mode. */
1185 /* Do we care about the CreateAction in any other cases? */
1186 /* BB FIXME BB */
1187 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1188 *pOplock |= CIFS_CREATE_ACTION; */
1189 /* BB FIXME END */
1191 if (pfile_info) {
1192 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1193 pfile_info->LastAccessTime = 0; /* BB fixme */
1194 pfile_info->LastWriteTime = 0; /* BB fixme */
1195 pfile_info->ChangeTime = 0; /* BB fixme */
1196 pfile_info->Attributes =
1197 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1198 /* the file_info buf is endian converted by caller */
1199 pfile_info->AllocationSize =
1200 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1201 pfile_info->EndOfFile = pfile_info->AllocationSize;
1202 pfile_info->NumberOfLinks = cpu_to_le32(1);
1203 pfile_info->DeletePending = 0;
1207 cifs_buf_release(pSMB);
1208 if (rc == -EAGAIN)
1209 goto OldOpenRetry;
1210 return rc;
1214 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1215 const char *fileName, const int openDisposition,
1216 const int access_flags, const int create_options, __u16 *netfid,
1217 int *pOplock, FILE_ALL_INFO *pfile_info,
1218 const struct nls_table *nls_codepage, int remap)
1220 int rc = -EACCES;
1221 OPEN_REQ *pSMB = NULL;
1222 OPEN_RSP *pSMBr = NULL;
1223 int bytes_returned;
1224 int name_len;
1225 __u16 count;
1227 openRetry:
1228 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1229 (void **) &pSMBr);
1230 if (rc)
1231 return rc;
1233 pSMB->AndXCommand = 0xFF; /* none */
1235 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1236 count = 1; /* account for one byte pad to word boundary */
1237 name_len =
1238 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1239 fileName, PATH_MAX, nls_codepage, remap);
1240 name_len++; /* trailing null */
1241 name_len *= 2;
1242 pSMB->NameLength = cpu_to_le16(name_len);
1243 } else { /* BB improve check for buffer overruns BB */
1244 count = 0; /* no pad */
1245 name_len = strnlen(fileName, PATH_MAX);
1246 name_len++; /* trailing null */
1247 pSMB->NameLength = cpu_to_le16(name_len);
1248 strncpy(pSMB->fileName, fileName, name_len);
1250 if (*pOplock & REQ_OPLOCK)
1251 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1252 else if (*pOplock & REQ_BATCHOPLOCK)
1253 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1254 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1255 pSMB->AllocationSize = 0;
1256 /* set file as system file if special file such
1257 as fifo and server expecting SFU style and
1258 no Unix extensions */
1259 if (create_options & CREATE_OPTION_SPECIAL)
1260 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1261 else
1262 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1264 /* XP does not handle ATTR_POSIX_SEMANTICS */
1265 /* but it helps speed up case sensitive checks for other
1266 servers such as Samba */
1267 if (tcon->ses->capabilities & CAP_UNIX)
1268 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1270 if (create_options & CREATE_OPTION_READONLY)
1271 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1273 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1274 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1275 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1276 /* BB Expirement with various impersonation levels and verify */
1277 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1278 pSMB->SecurityFlags =
1279 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1281 count += name_len;
1282 pSMB->hdr.smb_buf_length += count;
1284 pSMB->ByteCount = cpu_to_le16(count);
1285 /* long_op set to 1 to allow for oplock break timeouts */
1286 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1287 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1288 cifs_stats_inc(&tcon->num_opens);
1289 if (rc) {
1290 cFYI(1, ("Error in Open = %d", rc));
1291 } else {
1292 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1293 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1294 /* Let caller know file was created so we can set the mode. */
1295 /* Do we care about the CreateAction in any other cases? */
1296 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1297 *pOplock |= CIFS_CREATE_ACTION;
1298 if (pfile_info) {
1299 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1300 36 /* CreationTime to Attributes */);
1301 /* the file_info buf is endian converted by caller */
1302 pfile_info->AllocationSize = pSMBr->AllocationSize;
1303 pfile_info->EndOfFile = pSMBr->EndOfFile;
1304 pfile_info->NumberOfLinks = cpu_to_le32(1);
1305 pfile_info->DeletePending = 0;
1309 cifs_buf_release(pSMB);
1310 if (rc == -EAGAIN)
1311 goto openRetry;
1312 return rc;
1316 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1317 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1318 char **buf, int *pbuf_type)
1320 int rc = -EACCES;
1321 READ_REQ *pSMB = NULL;
1322 READ_RSP *pSMBr = NULL;
1323 char *pReadData = NULL;
1324 int wct;
1325 int resp_buf_type = 0;
1326 struct kvec iov[1];
1328 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1329 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1330 wct = 12;
1331 else {
1332 wct = 10; /* old style read */
1333 if ((lseek >> 32) > 0) {
1334 /* can not handle this big offset for old */
1335 return -EIO;
1339 *nbytes = 0;
1340 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1341 if (rc)
1342 return rc;
1344 /* tcon and ses pointer are checked in smb_init */
1345 if (tcon->ses->server == NULL)
1346 return -ECONNABORTED;
1348 pSMB->AndXCommand = 0xFF; /* none */
1349 pSMB->Fid = netfid;
1350 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1351 if (wct == 12)
1352 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1354 pSMB->Remaining = 0;
1355 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1356 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1357 if (wct == 12)
1358 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1359 else {
1360 /* old style read */
1361 struct smb_com_readx_req *pSMBW =
1362 (struct smb_com_readx_req *)pSMB;
1363 pSMBW->ByteCount = 0;
1366 iov[0].iov_base = (char *)pSMB;
1367 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1368 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1369 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1370 cifs_stats_inc(&tcon->num_reads);
1371 pSMBr = (READ_RSP *)iov[0].iov_base;
1372 if (rc) {
1373 cERROR(1, ("Send error in read = %d", rc));
1374 } else {
1375 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1376 data_length = data_length << 16;
1377 data_length += le16_to_cpu(pSMBr->DataLength);
1378 *nbytes = data_length;
1380 /*check that DataLength would not go beyond end of SMB */
1381 if ((data_length > CIFSMaxBufSize)
1382 || (data_length > count)) {
1383 cFYI(1, ("bad length %d for count %d",
1384 data_length, count));
1385 rc = -EIO;
1386 *nbytes = 0;
1387 } else {
1388 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1389 le16_to_cpu(pSMBr->DataOffset);
1390 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1391 cERROR(1,("Faulting on read rc = %d",rc));
1392 rc = -EFAULT;
1393 }*/ /* can not use copy_to_user when using page cache*/
1394 if (*buf)
1395 memcpy(*buf, pReadData, data_length);
1399 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1400 if (*buf) {
1401 if (resp_buf_type == CIFS_SMALL_BUFFER)
1402 cifs_small_buf_release(iov[0].iov_base);
1403 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1404 cifs_buf_release(iov[0].iov_base);
1405 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1406 /* return buffer to caller to free */
1407 *buf = iov[0].iov_base;
1408 if (resp_buf_type == CIFS_SMALL_BUFFER)
1409 *pbuf_type = CIFS_SMALL_BUFFER;
1410 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1411 *pbuf_type = CIFS_LARGE_BUFFER;
1412 } /* else no valid buffer on return - leave as null */
1414 /* Note: On -EAGAIN error only caller can retry on handle based calls
1415 since file handle passed in no longer valid */
1416 return rc;
1421 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1422 const int netfid, const unsigned int count,
1423 const __u64 offset, unsigned int *nbytes, const char *buf,
1424 const char __user *ubuf, const int long_op)
1426 int rc = -EACCES;
1427 WRITE_REQ *pSMB = NULL;
1428 WRITE_RSP *pSMBr = NULL;
1429 int bytes_returned, wct;
1430 __u32 bytes_sent;
1431 __u16 byte_count;
1433 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
1434 if (tcon->ses == NULL)
1435 return -ECONNABORTED;
1437 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1438 wct = 14;
1439 else {
1440 wct = 12;
1441 if ((offset >> 32) > 0) {
1442 /* can not handle big offset for old srv */
1443 return -EIO;
1447 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1448 (void **) &pSMBr);
1449 if (rc)
1450 return rc;
1451 /* tcon and ses pointer are checked in smb_init */
1452 if (tcon->ses->server == NULL)
1453 return -ECONNABORTED;
1455 pSMB->AndXCommand = 0xFF; /* none */
1456 pSMB->Fid = netfid;
1457 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1458 if (wct == 14)
1459 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1461 pSMB->Reserved = 0xFFFFFFFF;
1462 pSMB->WriteMode = 0;
1463 pSMB->Remaining = 0;
1465 /* Can increase buffer size if buffer is big enough in some cases ie we
1466 can send more if LARGE_WRITE_X capability returned by the server and if
1467 our buffer is big enough or if we convert to iovecs on socket writes
1468 and eliminate the copy to the CIFS buffer */
1469 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1470 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1471 } else {
1472 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1473 & ~0xFF;
1476 if (bytes_sent > count)
1477 bytes_sent = count;
1478 pSMB->DataOffset =
1479 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1480 if (buf)
1481 memcpy(pSMB->Data, buf, bytes_sent);
1482 else if (ubuf) {
1483 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1484 cifs_buf_release(pSMB);
1485 return -EFAULT;
1487 } else if (count != 0) {
1488 /* No buffer */
1489 cifs_buf_release(pSMB);
1490 return -EINVAL;
1491 } /* else setting file size with write of zero bytes */
1492 if (wct == 14)
1493 byte_count = bytes_sent + 1; /* pad */
1494 else /* wct == 12 */
1495 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1497 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1498 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1499 pSMB->hdr.smb_buf_length += byte_count;
1501 if (wct == 14)
1502 pSMB->ByteCount = cpu_to_le16(byte_count);
1503 else { /* old style write has byte count 4 bytes earlier
1504 so 4 bytes pad */
1505 struct smb_com_writex_req *pSMBW =
1506 (struct smb_com_writex_req *)pSMB;
1507 pSMBW->ByteCount = cpu_to_le16(byte_count);
1510 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1511 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1512 cifs_stats_inc(&tcon->num_writes);
1513 if (rc) {
1514 cFYI(1, ("Send error in write = %d", rc));
1515 *nbytes = 0;
1516 } else {
1517 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1518 *nbytes = (*nbytes) << 16;
1519 *nbytes += le16_to_cpu(pSMBr->Count);
1522 cifs_buf_release(pSMB);
1524 /* Note: On -EAGAIN error only caller can retry on handle based calls
1525 since file handle passed in no longer valid */
1527 return rc;
1531 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1532 const int netfid, const unsigned int count,
1533 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1534 int n_vec, const int long_op)
1536 int rc = -EACCES;
1537 WRITE_REQ *pSMB = NULL;
1538 int wct;
1539 int smb_hdr_len;
1540 int resp_buf_type = 0;
1542 *nbytes = 0;
1544 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1546 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1547 wct = 14;
1548 } else {
1549 wct = 12;
1550 if ((offset >> 32) > 0) {
1551 /* can not handle big offset for old srv */
1552 return -EIO;
1555 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1556 if (rc)
1557 return rc;
1558 /* tcon and ses pointer are checked in smb_init */
1559 if (tcon->ses->server == NULL)
1560 return -ECONNABORTED;
1562 pSMB->AndXCommand = 0xFF; /* none */
1563 pSMB->Fid = netfid;
1564 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1565 if (wct == 14)
1566 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1567 pSMB->Reserved = 0xFFFFFFFF;
1568 pSMB->WriteMode = 0;
1569 pSMB->Remaining = 0;
1571 pSMB->DataOffset =
1572 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1574 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1575 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1576 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1577 if (wct == 14)
1578 pSMB->hdr.smb_buf_length += count+1;
1579 else /* wct == 12 */
1580 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1581 if (wct == 14)
1582 pSMB->ByteCount = cpu_to_le16(count + 1);
1583 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1584 struct smb_com_writex_req *pSMBW =
1585 (struct smb_com_writex_req *)pSMB;
1586 pSMBW->ByteCount = cpu_to_le16(count + 5);
1588 iov[0].iov_base = pSMB;
1589 if (wct == 14)
1590 iov[0].iov_len = smb_hdr_len + 4;
1591 else /* wct == 12 pad bigger by four bytes */
1592 iov[0].iov_len = smb_hdr_len + 8;
1595 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1596 long_op);
1597 cifs_stats_inc(&tcon->num_writes);
1598 if (rc) {
1599 cFYI(1, ("Send error Write2 = %d", rc));
1600 } else if (resp_buf_type == 0) {
1601 /* presumably this can not happen, but best to be safe */
1602 rc = -EIO;
1603 } else {
1604 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1605 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1606 *nbytes = (*nbytes) << 16;
1607 *nbytes += le16_to_cpu(pSMBr->Count);
1610 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1611 if (resp_buf_type == CIFS_SMALL_BUFFER)
1612 cifs_small_buf_release(iov[0].iov_base);
1613 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1614 cifs_buf_release(iov[0].iov_base);
1616 /* Note: On -EAGAIN error only caller can retry on handle based calls
1617 since file handle passed in no longer valid */
1619 return rc;
1624 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1625 const __u16 smb_file_id, const __u64 len,
1626 const __u64 offset, const __u32 numUnlock,
1627 const __u32 numLock, const __u8 lockType, const bool waitFlag)
1629 int rc = 0;
1630 LOCK_REQ *pSMB = NULL;
1631 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1632 int bytes_returned;
1633 int timeout = 0;
1634 __u16 count;
1636 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1637 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1639 if (rc)
1640 return rc;
1642 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1643 timeout = CIFS_ASYNC_OP; /* no response expected */
1644 pSMB->Timeout = 0;
1645 } else if (waitFlag) {
1646 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1647 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1648 } else {
1649 pSMB->Timeout = 0;
1652 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1653 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1654 pSMB->LockType = lockType;
1655 pSMB->AndXCommand = 0xFF; /* none */
1656 pSMB->Fid = smb_file_id; /* netfid stays le */
1658 if ((numLock != 0) || (numUnlock != 0)) {
1659 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1660 /* BB where to store pid high? */
1661 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1662 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1663 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1664 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1665 count = sizeof(LOCKING_ANDX_RANGE);
1666 } else {
1667 /* oplock break */
1668 count = 0;
1670 pSMB->hdr.smb_buf_length += count;
1671 pSMB->ByteCount = cpu_to_le16(count);
1673 if (waitFlag) {
1674 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1675 (struct smb_hdr *) pSMB, &bytes_returned);
1676 cifs_small_buf_release(pSMB);
1677 } else {
1678 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1679 timeout);
1680 /* SMB buffer freed by function above */
1682 cifs_stats_inc(&tcon->num_locks);
1683 if (rc)
1684 cFYI(1, ("Send error in Lock = %d", rc));
1686 /* Note: On -EAGAIN error only caller can retry on handle based calls
1687 since file handle passed in no longer valid */
1688 return rc;
1692 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1693 const __u16 smb_file_id, const int get_flag, const __u64 len,
1694 struct file_lock *pLockData, const __u16 lock_type,
1695 const bool waitFlag)
1697 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1698 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1699 struct cifs_posix_lock *parm_data;
1700 int rc = 0;
1701 int timeout = 0;
1702 int bytes_returned = 0;
1703 int resp_buf_type = 0;
1704 __u16 params, param_offset, offset, byte_count, count;
1705 struct kvec iov[1];
1707 cFYI(1, ("Posix Lock"));
1709 if (pLockData == NULL)
1710 return -EINVAL;
1712 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1714 if (rc)
1715 return rc;
1717 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1719 params = 6;
1720 pSMB->MaxSetupCount = 0;
1721 pSMB->Reserved = 0;
1722 pSMB->Flags = 0;
1723 pSMB->Reserved2 = 0;
1724 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1725 offset = param_offset + params;
1727 count = sizeof(struct cifs_posix_lock);
1728 pSMB->MaxParameterCount = cpu_to_le16(2);
1729 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1730 pSMB->SetupCount = 1;
1731 pSMB->Reserved3 = 0;
1732 if (get_flag)
1733 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1734 else
1735 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1736 byte_count = 3 /* pad */ + params + count;
1737 pSMB->DataCount = cpu_to_le16(count);
1738 pSMB->ParameterCount = cpu_to_le16(params);
1739 pSMB->TotalDataCount = pSMB->DataCount;
1740 pSMB->TotalParameterCount = pSMB->ParameterCount;
1741 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1742 parm_data = (struct cifs_posix_lock *)
1743 (((char *) &pSMB->hdr.Protocol) + offset);
1745 parm_data->lock_type = cpu_to_le16(lock_type);
1746 if (waitFlag) {
1747 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1748 parm_data->lock_flags = cpu_to_le16(1);
1749 pSMB->Timeout = cpu_to_le32(-1);
1750 } else
1751 pSMB->Timeout = 0;
1753 parm_data->pid = cpu_to_le32(current->tgid);
1754 parm_data->start = cpu_to_le64(pLockData->fl_start);
1755 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1757 pSMB->DataOffset = cpu_to_le16(offset);
1758 pSMB->Fid = smb_file_id;
1759 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1760 pSMB->Reserved4 = 0;
1761 pSMB->hdr.smb_buf_length += byte_count;
1762 pSMB->ByteCount = cpu_to_le16(byte_count);
1763 if (waitFlag) {
1764 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1765 (struct smb_hdr *) pSMBr, &bytes_returned);
1766 } else {
1767 iov[0].iov_base = (char *)pSMB;
1768 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1769 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1770 &resp_buf_type, timeout);
1771 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1772 not try to free it twice below on exit */
1773 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1776 if (rc) {
1777 cFYI(1, ("Send error in Posix Lock = %d", rc));
1778 } else if (get_flag) {
1779 /* lock structure can be returned on get */
1780 __u16 data_offset;
1781 __u16 data_count;
1782 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1784 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1785 rc = -EIO; /* bad smb */
1786 goto plk_err_exit;
1788 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1789 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1790 if (data_count < sizeof(struct cifs_posix_lock)) {
1791 rc = -EIO;
1792 goto plk_err_exit;
1794 parm_data = (struct cifs_posix_lock *)
1795 ((char *)&pSMBr->hdr.Protocol + data_offset);
1796 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1797 pLockData->fl_type = F_UNLCK;
1800 plk_err_exit:
1801 if (pSMB)
1802 cifs_small_buf_release(pSMB);
1804 if (resp_buf_type == CIFS_SMALL_BUFFER)
1805 cifs_small_buf_release(iov[0].iov_base);
1806 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1807 cifs_buf_release(iov[0].iov_base);
1809 /* Note: On -EAGAIN error only caller can retry on handle based calls
1810 since file handle passed in no longer valid */
1812 return rc;
1817 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1819 int rc = 0;
1820 CLOSE_REQ *pSMB = NULL;
1821 cFYI(1, ("In CIFSSMBClose"));
1823 /* do not retry on dead session on close */
1824 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1825 if (rc == -EAGAIN)
1826 return 0;
1827 if (rc)
1828 return rc;
1830 pSMB->FileID = (__u16) smb_file_id;
1831 pSMB->LastWriteTime = 0xFFFFFFFF;
1832 pSMB->ByteCount = 0;
1833 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1834 cifs_stats_inc(&tcon->num_closes);
1835 if (rc) {
1836 if (rc != -EINTR) {
1837 /* EINTR is expected when user ctl-c to kill app */
1838 cERROR(1, ("Send error in Close = %d", rc));
1842 /* Since session is dead, file will be closed on server already */
1843 if (rc == -EAGAIN)
1844 rc = 0;
1846 return rc;
1850 CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1852 int rc = 0;
1853 FLUSH_REQ *pSMB = NULL;
1854 cFYI(1, ("In CIFSSMBFlush"));
1856 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1857 if (rc)
1858 return rc;
1860 pSMB->FileID = (__u16) smb_file_id;
1861 pSMB->ByteCount = 0;
1862 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1863 cifs_stats_inc(&tcon->num_flushes);
1864 if (rc)
1865 cERROR(1, ("Send error in Flush = %d", rc));
1867 return rc;
1871 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1872 const char *fromName, const char *toName,
1873 const struct nls_table *nls_codepage, int remap)
1875 int rc = 0;
1876 RENAME_REQ *pSMB = NULL;
1877 RENAME_RSP *pSMBr = NULL;
1878 int bytes_returned;
1879 int name_len, name_len2;
1880 __u16 count;
1882 cFYI(1, ("In CIFSSMBRename"));
1883 renameRetry:
1884 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1885 (void **) &pSMBr);
1886 if (rc)
1887 return rc;
1889 pSMB->BufferFormat = 0x04;
1890 pSMB->SearchAttributes =
1891 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1892 ATTR_DIRECTORY);
1894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1895 name_len =
1896 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1897 PATH_MAX, nls_codepage, remap);
1898 name_len++; /* trailing null */
1899 name_len *= 2;
1900 pSMB->OldFileName[name_len] = 0x04; /* pad */
1901 /* protocol requires ASCII signature byte on Unicode string */
1902 pSMB->OldFileName[name_len + 1] = 0x00;
1903 name_len2 =
1904 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1905 toName, PATH_MAX, nls_codepage, remap);
1906 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1907 name_len2 *= 2; /* convert to bytes */
1908 } else { /* BB improve the check for buffer overruns BB */
1909 name_len = strnlen(fromName, PATH_MAX);
1910 name_len++; /* trailing null */
1911 strncpy(pSMB->OldFileName, fromName, name_len);
1912 name_len2 = strnlen(toName, PATH_MAX);
1913 name_len2++; /* trailing null */
1914 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1915 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1916 name_len2++; /* trailing null */
1917 name_len2++; /* signature byte */
1920 count = 1 /* 1st signature byte */ + name_len + name_len2;
1921 pSMB->hdr.smb_buf_length += count;
1922 pSMB->ByteCount = cpu_to_le16(count);
1924 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1925 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1926 cifs_stats_inc(&tcon->num_renames);
1927 if (rc)
1928 cFYI(1, ("Send error in rename = %d", rc));
1930 cifs_buf_release(pSMB);
1932 if (rc == -EAGAIN)
1933 goto renameRetry;
1935 return rc;
1938 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1939 int netfid, const char *target_name,
1940 const struct nls_table *nls_codepage, int remap)
1942 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1943 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1944 struct set_file_rename *rename_info;
1945 char *data_offset;
1946 char dummy_string[30];
1947 int rc = 0;
1948 int bytes_returned = 0;
1949 int len_of_str;
1950 __u16 params, param_offset, offset, count, byte_count;
1952 cFYI(1, ("Rename to File by handle"));
1953 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1954 (void **) &pSMBr);
1955 if (rc)
1956 return rc;
1958 params = 6;
1959 pSMB->MaxSetupCount = 0;
1960 pSMB->Reserved = 0;
1961 pSMB->Flags = 0;
1962 pSMB->Timeout = 0;
1963 pSMB->Reserved2 = 0;
1964 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1965 offset = param_offset + params;
1967 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1968 rename_info = (struct set_file_rename *) data_offset;
1969 pSMB->MaxParameterCount = cpu_to_le16(2);
1970 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1971 pSMB->SetupCount = 1;
1972 pSMB->Reserved3 = 0;
1973 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1974 byte_count = 3 /* pad */ + params;
1975 pSMB->ParameterCount = cpu_to_le16(params);
1976 pSMB->TotalParameterCount = pSMB->ParameterCount;
1977 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1978 pSMB->DataOffset = cpu_to_le16(offset);
1979 /* construct random name ".cifs_tmp<inodenum><mid>" */
1980 rename_info->overwrite = cpu_to_le32(1);
1981 rename_info->root_fid = 0;
1982 /* unicode only call */
1983 if (target_name == NULL) {
1984 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
1985 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1986 dummy_string, 24, nls_codepage, remap);
1987 } else {
1988 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1989 target_name, PATH_MAX, nls_codepage,
1990 remap);
1992 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1993 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
1994 byte_count += count;
1995 pSMB->DataCount = cpu_to_le16(count);
1996 pSMB->TotalDataCount = pSMB->DataCount;
1997 pSMB->Fid = netfid;
1998 pSMB->InformationLevel =
1999 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2000 pSMB->Reserved4 = 0;
2001 pSMB->hdr.smb_buf_length += byte_count;
2002 pSMB->ByteCount = cpu_to_le16(byte_count);
2003 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2004 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2005 cifs_stats_inc(&pTcon->num_t2renames);
2006 if (rc)
2007 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2009 cifs_buf_release(pSMB);
2011 /* Note: On -EAGAIN error only caller can retry on handle based calls
2012 since file handle passed in no longer valid */
2014 return rc;
2018 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2019 const __u16 target_tid, const char *toName, const int flags,
2020 const struct nls_table *nls_codepage, int remap)
2022 int rc = 0;
2023 COPY_REQ *pSMB = NULL;
2024 COPY_RSP *pSMBr = NULL;
2025 int bytes_returned;
2026 int name_len, name_len2;
2027 __u16 count;
2029 cFYI(1, ("In CIFSSMBCopy"));
2030 copyRetry:
2031 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2032 (void **) &pSMBr);
2033 if (rc)
2034 return rc;
2036 pSMB->BufferFormat = 0x04;
2037 pSMB->Tid2 = target_tid;
2039 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2041 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2042 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2043 fromName, PATH_MAX, nls_codepage,
2044 remap);
2045 name_len++; /* trailing null */
2046 name_len *= 2;
2047 pSMB->OldFileName[name_len] = 0x04; /* pad */
2048 /* protocol requires ASCII signature byte on Unicode string */
2049 pSMB->OldFileName[name_len + 1] = 0x00;
2050 name_len2 =
2051 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2052 toName, PATH_MAX, nls_codepage, remap);
2053 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2054 name_len2 *= 2; /* convert to bytes */
2055 } else { /* BB improve the check for buffer overruns BB */
2056 name_len = strnlen(fromName, PATH_MAX);
2057 name_len++; /* trailing null */
2058 strncpy(pSMB->OldFileName, fromName, name_len);
2059 name_len2 = strnlen(toName, PATH_MAX);
2060 name_len2++; /* trailing null */
2061 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2062 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2063 name_len2++; /* trailing null */
2064 name_len2++; /* signature byte */
2067 count = 1 /* 1st signature byte */ + name_len + name_len2;
2068 pSMB->hdr.smb_buf_length += count;
2069 pSMB->ByteCount = cpu_to_le16(count);
2071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2073 if (rc) {
2074 cFYI(1, ("Send error in copy = %d with %d files copied",
2075 rc, le16_to_cpu(pSMBr->CopyCount)));
2077 cifs_buf_release(pSMB);
2079 if (rc == -EAGAIN)
2080 goto copyRetry;
2082 return rc;
2086 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2087 const char *fromName, const char *toName,
2088 const struct nls_table *nls_codepage)
2090 TRANSACTION2_SPI_REQ *pSMB = NULL;
2091 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2092 char *data_offset;
2093 int name_len;
2094 int name_len_target;
2095 int rc = 0;
2096 int bytes_returned = 0;
2097 __u16 params, param_offset, offset, byte_count;
2099 cFYI(1, ("In Symlink Unix style"));
2100 createSymLinkRetry:
2101 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2102 (void **) &pSMBr);
2103 if (rc)
2104 return rc;
2106 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2107 name_len =
2108 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2109 /* find define for this maxpathcomponent */
2110 , nls_codepage);
2111 name_len++; /* trailing null */
2112 name_len *= 2;
2114 } else { /* BB improve the check for buffer overruns BB */
2115 name_len = strnlen(fromName, PATH_MAX);
2116 name_len++; /* trailing null */
2117 strncpy(pSMB->FileName, fromName, name_len);
2119 params = 6 + name_len;
2120 pSMB->MaxSetupCount = 0;
2121 pSMB->Reserved = 0;
2122 pSMB->Flags = 0;
2123 pSMB->Timeout = 0;
2124 pSMB->Reserved2 = 0;
2125 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2126 InformationLevel) - 4;
2127 offset = param_offset + params;
2129 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2130 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2131 name_len_target =
2132 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2133 /* find define for this maxpathcomponent */
2134 , nls_codepage);
2135 name_len_target++; /* trailing null */
2136 name_len_target *= 2;
2137 } else { /* BB improve the check for buffer overruns BB */
2138 name_len_target = strnlen(toName, PATH_MAX);
2139 name_len_target++; /* trailing null */
2140 strncpy(data_offset, toName, name_len_target);
2143 pSMB->MaxParameterCount = cpu_to_le16(2);
2144 /* BB find exact max on data count below from sess */
2145 pSMB->MaxDataCount = cpu_to_le16(1000);
2146 pSMB->SetupCount = 1;
2147 pSMB->Reserved3 = 0;
2148 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2149 byte_count = 3 /* pad */ + params + name_len_target;
2150 pSMB->DataCount = cpu_to_le16(name_len_target);
2151 pSMB->ParameterCount = cpu_to_le16(params);
2152 pSMB->TotalDataCount = pSMB->DataCount;
2153 pSMB->TotalParameterCount = pSMB->ParameterCount;
2154 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2155 pSMB->DataOffset = cpu_to_le16(offset);
2156 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2157 pSMB->Reserved4 = 0;
2158 pSMB->hdr.smb_buf_length += byte_count;
2159 pSMB->ByteCount = cpu_to_le16(byte_count);
2160 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2161 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2162 cifs_stats_inc(&tcon->num_symlinks);
2163 if (rc)
2164 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2166 cifs_buf_release(pSMB);
2168 if (rc == -EAGAIN)
2169 goto createSymLinkRetry;
2171 return rc;
2175 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2176 const char *fromName, const char *toName,
2177 const struct nls_table *nls_codepage, int remap)
2179 TRANSACTION2_SPI_REQ *pSMB = NULL;
2180 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2181 char *data_offset;
2182 int name_len;
2183 int name_len_target;
2184 int rc = 0;
2185 int bytes_returned = 0;
2186 __u16 params, param_offset, offset, byte_count;
2188 cFYI(1, ("In Create Hard link Unix style"));
2189 createHardLinkRetry:
2190 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2191 (void **) &pSMBr);
2192 if (rc)
2193 return rc;
2195 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2196 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2197 PATH_MAX, nls_codepage, remap);
2198 name_len++; /* trailing null */
2199 name_len *= 2;
2201 } else { /* BB improve the check for buffer overruns BB */
2202 name_len = strnlen(toName, PATH_MAX);
2203 name_len++; /* trailing null */
2204 strncpy(pSMB->FileName, toName, name_len);
2206 params = 6 + name_len;
2207 pSMB->MaxSetupCount = 0;
2208 pSMB->Reserved = 0;
2209 pSMB->Flags = 0;
2210 pSMB->Timeout = 0;
2211 pSMB->Reserved2 = 0;
2212 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2213 InformationLevel) - 4;
2214 offset = param_offset + params;
2216 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2217 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2218 name_len_target =
2219 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2220 nls_codepage, remap);
2221 name_len_target++; /* trailing null */
2222 name_len_target *= 2;
2223 } else { /* BB improve the check for buffer overruns BB */
2224 name_len_target = strnlen(fromName, PATH_MAX);
2225 name_len_target++; /* trailing null */
2226 strncpy(data_offset, fromName, name_len_target);
2229 pSMB->MaxParameterCount = cpu_to_le16(2);
2230 /* BB find exact max on data count below from sess*/
2231 pSMB->MaxDataCount = cpu_to_le16(1000);
2232 pSMB->SetupCount = 1;
2233 pSMB->Reserved3 = 0;
2234 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2235 byte_count = 3 /* pad */ + params + name_len_target;
2236 pSMB->ParameterCount = cpu_to_le16(params);
2237 pSMB->TotalParameterCount = pSMB->ParameterCount;
2238 pSMB->DataCount = cpu_to_le16(name_len_target);
2239 pSMB->TotalDataCount = pSMB->DataCount;
2240 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2241 pSMB->DataOffset = cpu_to_le16(offset);
2242 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2243 pSMB->Reserved4 = 0;
2244 pSMB->hdr.smb_buf_length += byte_count;
2245 pSMB->ByteCount = cpu_to_le16(byte_count);
2246 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2247 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2248 cifs_stats_inc(&tcon->num_hardlinks);
2249 if (rc)
2250 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2252 cifs_buf_release(pSMB);
2253 if (rc == -EAGAIN)
2254 goto createHardLinkRetry;
2256 return rc;
2260 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2261 const char *fromName, const char *toName,
2262 const struct nls_table *nls_codepage, int remap)
2264 int rc = 0;
2265 NT_RENAME_REQ *pSMB = NULL;
2266 RENAME_RSP *pSMBr = NULL;
2267 int bytes_returned;
2268 int name_len, name_len2;
2269 __u16 count;
2271 cFYI(1, ("In CIFSCreateHardLink"));
2272 winCreateHardLinkRetry:
2274 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2275 (void **) &pSMBr);
2276 if (rc)
2277 return rc;
2279 pSMB->SearchAttributes =
2280 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2281 ATTR_DIRECTORY);
2282 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2283 pSMB->ClusterCount = 0;
2285 pSMB->BufferFormat = 0x04;
2287 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2288 name_len =
2289 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2290 PATH_MAX, nls_codepage, remap);
2291 name_len++; /* trailing null */
2292 name_len *= 2;
2294 /* protocol specifies ASCII buffer format (0x04) for unicode */
2295 pSMB->OldFileName[name_len] = 0x04;
2296 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2297 name_len2 =
2298 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2299 toName, PATH_MAX, nls_codepage, remap);
2300 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2301 name_len2 *= 2; /* convert to bytes */
2302 } else { /* BB improve the check for buffer overruns BB */
2303 name_len = strnlen(fromName, PATH_MAX);
2304 name_len++; /* trailing null */
2305 strncpy(pSMB->OldFileName, fromName, name_len);
2306 name_len2 = strnlen(toName, PATH_MAX);
2307 name_len2++; /* trailing null */
2308 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2309 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2310 name_len2++; /* trailing null */
2311 name_len2++; /* signature byte */
2314 count = 1 /* string type byte */ + name_len + name_len2;
2315 pSMB->hdr.smb_buf_length += count;
2316 pSMB->ByteCount = cpu_to_le16(count);
2318 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2319 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2320 cifs_stats_inc(&tcon->num_hardlinks);
2321 if (rc)
2322 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2324 cifs_buf_release(pSMB);
2325 if (rc == -EAGAIN)
2326 goto winCreateHardLinkRetry;
2328 return rc;
2332 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2333 const unsigned char *searchName, char **symlinkinfo,
2334 const struct nls_table *nls_codepage)
2336 /* SMB_QUERY_FILE_UNIX_LINK */
2337 TRANSACTION2_QPI_REQ *pSMB = NULL;
2338 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2339 int rc = 0;
2340 int bytes_returned;
2341 int name_len;
2342 __u16 params, byte_count;
2343 char *data_start;
2345 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2347 querySymLinkRetry:
2348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2349 (void **) &pSMBr);
2350 if (rc)
2351 return rc;
2353 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2354 name_len =
2355 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2356 PATH_MAX, nls_codepage);
2357 name_len++; /* trailing null */
2358 name_len *= 2;
2359 } else { /* BB improve the check for buffer overruns BB */
2360 name_len = strnlen(searchName, PATH_MAX);
2361 name_len++; /* trailing null */
2362 strncpy(pSMB->FileName, searchName, name_len);
2365 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2366 pSMB->TotalDataCount = 0;
2367 pSMB->MaxParameterCount = cpu_to_le16(2);
2368 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
2369 pSMB->MaxSetupCount = 0;
2370 pSMB->Reserved = 0;
2371 pSMB->Flags = 0;
2372 pSMB->Timeout = 0;
2373 pSMB->Reserved2 = 0;
2374 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2375 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2376 pSMB->DataCount = 0;
2377 pSMB->DataOffset = 0;
2378 pSMB->SetupCount = 1;
2379 pSMB->Reserved3 = 0;
2380 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2381 byte_count = params + 1 /* pad */ ;
2382 pSMB->TotalParameterCount = cpu_to_le16(params);
2383 pSMB->ParameterCount = pSMB->TotalParameterCount;
2384 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2385 pSMB->Reserved4 = 0;
2386 pSMB->hdr.smb_buf_length += byte_count;
2387 pSMB->ByteCount = cpu_to_le16(byte_count);
2389 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2390 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2391 if (rc) {
2392 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2393 } else {
2394 /* decode response */
2396 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2397 /* BB also check enough total bytes returned */
2398 if (rc || (pSMBr->ByteCount < 2))
2399 rc = -EIO;
2400 else {
2401 bool is_unicode;
2402 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2404 data_start = ((char *) &pSMBr->hdr.Protocol) +
2405 le16_to_cpu(pSMBr->t2.DataOffset);
2407 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2408 is_unicode = true;
2409 else
2410 is_unicode = false;
2412 /* BB FIXME investigate remapping reserved chars here */
2413 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
2414 is_unicode, nls_codepage);
2415 if (!*symlinkinfo)
2416 rc = -ENOMEM;
2419 cifs_buf_release(pSMB);
2420 if (rc == -EAGAIN)
2421 goto querySymLinkRetry;
2422 return rc;
2425 #ifdef CONFIG_CIFS_EXPERIMENTAL
2426 /* Initialize NT TRANSACT SMB into small smb request buffer.
2427 This assumes that all NT TRANSACTS that we init here have
2428 total parm and data under about 400 bytes (to fit in small cifs
2429 buffer size), which is the case so far, it easily fits. NB:
2430 Setup words themselves and ByteCount
2431 MaxSetupCount (size of returned setup area) and
2432 MaxParameterCount (returned parms size) must be set by caller */
2433 static int
2434 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2435 const int parm_len, struct cifsTconInfo *tcon,
2436 void **ret_buf)
2438 int rc;
2439 __u32 temp_offset;
2440 struct smb_com_ntransact_req *pSMB;
2442 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2443 (void **)&pSMB);
2444 if (rc)
2445 return rc;
2446 *ret_buf = (void *)pSMB;
2447 pSMB->Reserved = 0;
2448 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2449 pSMB->TotalDataCount = 0;
2450 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2451 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2452 pSMB->ParameterCount = pSMB->TotalParameterCount;
2453 pSMB->DataCount = pSMB->TotalDataCount;
2454 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2455 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2456 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2457 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2458 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2459 pSMB->SubCommand = cpu_to_le16(sub_command);
2460 return 0;
2463 static int
2464 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2465 __u32 *pparmlen, __u32 *pdatalen)
2467 char *end_of_smb;
2468 __u32 data_count, data_offset, parm_count, parm_offset;
2469 struct smb_com_ntransact_rsp *pSMBr;
2471 *pdatalen = 0;
2472 *pparmlen = 0;
2474 if (buf == NULL)
2475 return -EINVAL;
2477 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2479 /* ByteCount was converted from little endian in SendReceive */
2480 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2481 (char *)&pSMBr->ByteCount;
2483 data_offset = le32_to_cpu(pSMBr->DataOffset);
2484 data_count = le32_to_cpu(pSMBr->DataCount);
2485 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2486 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2488 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2489 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2491 /* should we also check that parm and data areas do not overlap? */
2492 if (*ppparm > end_of_smb) {
2493 cFYI(1, ("parms start after end of smb"));
2494 return -EINVAL;
2495 } else if (parm_count + *ppparm > end_of_smb) {
2496 cFYI(1, ("parm end after end of smb"));
2497 return -EINVAL;
2498 } else if (*ppdata > end_of_smb) {
2499 cFYI(1, ("data starts after end of smb"));
2500 return -EINVAL;
2501 } else if (data_count + *ppdata > end_of_smb) {
2502 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2503 *ppdata, data_count, (data_count + *ppdata),
2504 end_of_smb, pSMBr));
2505 return -EINVAL;
2506 } else if (parm_count + data_count > pSMBr->ByteCount) {
2507 cFYI(1, ("parm count and data count larger than SMB"));
2508 return -EINVAL;
2510 *pdatalen = data_count;
2511 *pparmlen = parm_count;
2512 return 0;
2516 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2517 const unsigned char *searchName,
2518 char *symlinkinfo, const int buflen, __u16 fid,
2519 const struct nls_table *nls_codepage)
2521 int rc = 0;
2522 int bytes_returned;
2523 struct smb_com_transaction_ioctl_req *pSMB;
2524 struct smb_com_transaction_ioctl_rsp *pSMBr;
2526 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2527 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2528 (void **) &pSMBr);
2529 if (rc)
2530 return rc;
2532 pSMB->TotalParameterCount = 0 ;
2533 pSMB->TotalDataCount = 0;
2534 pSMB->MaxParameterCount = cpu_to_le32(2);
2535 /* BB find exact data count max from sess structure BB */
2536 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2537 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2538 pSMB->MaxSetupCount = 4;
2539 pSMB->Reserved = 0;
2540 pSMB->ParameterOffset = 0;
2541 pSMB->DataCount = 0;
2542 pSMB->DataOffset = 0;
2543 pSMB->SetupCount = 4;
2544 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2545 pSMB->ParameterCount = pSMB->TotalParameterCount;
2546 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2547 pSMB->IsFsctl = 1; /* FSCTL */
2548 pSMB->IsRootFlag = 0;
2549 pSMB->Fid = fid; /* file handle always le */
2550 pSMB->ByteCount = 0;
2552 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2553 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2554 if (rc) {
2555 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2556 } else { /* decode response */
2557 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2558 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2559 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
2560 /* BB also check enough total bytes returned */
2561 rc = -EIO; /* bad smb */
2562 goto qreparse_out;
2564 if (data_count && (data_count < 2048)) {
2565 char *end_of_smb = 2 /* sizeof byte count */ +
2566 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
2568 struct reparse_data *reparse_buf =
2569 (struct reparse_data *)
2570 ((char *)&pSMBr->hdr.Protocol
2571 + data_offset);
2572 if ((char *)reparse_buf >= end_of_smb) {
2573 rc = -EIO;
2574 goto qreparse_out;
2576 if ((reparse_buf->LinkNamesBuf +
2577 reparse_buf->TargetNameOffset +
2578 reparse_buf->TargetNameLen) > end_of_smb) {
2579 cFYI(1, ("reparse buf beyond SMB"));
2580 rc = -EIO;
2581 goto qreparse_out;
2584 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2585 cifs_from_ucs2(symlinkinfo, (__le16 *)
2586 (reparse_buf->LinkNamesBuf +
2587 reparse_buf->TargetNameOffset),
2588 buflen,
2589 reparse_buf->TargetNameLen,
2590 nls_codepage, 0);
2591 } else { /* ASCII names */
2592 strncpy(symlinkinfo,
2593 reparse_buf->LinkNamesBuf +
2594 reparse_buf->TargetNameOffset,
2595 min_t(const int, buflen,
2596 reparse_buf->TargetNameLen));
2598 } else {
2599 rc = -EIO;
2600 cFYI(1, ("Invalid return data count on "
2601 "get reparse info ioctl"));
2603 symlinkinfo[buflen] = 0; /* just in case so the caller
2604 does not go off the end of the buffer */
2605 cFYI(1, ("readlink result - %s", symlinkinfo));
2608 qreparse_out:
2609 cifs_buf_release(pSMB);
2611 /* Note: On -EAGAIN error only caller can retry on handle based calls
2612 since file handle passed in no longer valid */
2614 return rc;
2616 #endif /* CIFS_EXPERIMENTAL */
2618 #ifdef CONFIG_CIFS_POSIX
2620 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2621 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2622 struct cifs_posix_ace *cifs_ace)
2624 /* u8 cifs fields do not need le conversion */
2625 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2626 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2627 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2628 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2630 return;
2633 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2634 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2635 const int acl_type, const int size_of_data_area)
2637 int size = 0;
2638 int i;
2639 __u16 count;
2640 struct cifs_posix_ace *pACE;
2641 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2642 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2644 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2645 return -EOPNOTSUPP;
2647 if (acl_type & ACL_TYPE_ACCESS) {
2648 count = le16_to_cpu(cifs_acl->access_entry_count);
2649 pACE = &cifs_acl->ace_array[0];
2650 size = sizeof(struct cifs_posix_acl);
2651 size += sizeof(struct cifs_posix_ace) * count;
2652 /* check if we would go beyond end of SMB */
2653 if (size_of_data_area < size) {
2654 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2655 size_of_data_area, size));
2656 return -EINVAL;
2658 } else if (acl_type & ACL_TYPE_DEFAULT) {
2659 count = le16_to_cpu(cifs_acl->access_entry_count);
2660 size = sizeof(struct cifs_posix_acl);
2661 size += sizeof(struct cifs_posix_ace) * count;
2662 /* skip past access ACEs to get to default ACEs */
2663 pACE = &cifs_acl->ace_array[count];
2664 count = le16_to_cpu(cifs_acl->default_entry_count);
2665 size += sizeof(struct cifs_posix_ace) * count;
2666 /* check if we would go beyond end of SMB */
2667 if (size_of_data_area < size)
2668 return -EINVAL;
2669 } else {
2670 /* illegal type */
2671 return -EINVAL;
2674 size = posix_acl_xattr_size(count);
2675 if ((buflen == 0) || (local_acl == NULL)) {
2676 /* used to query ACL EA size */
2677 } else if (size > buflen) {
2678 return -ERANGE;
2679 } else /* buffer big enough */ {
2680 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2681 for (i = 0; i < count ; i++) {
2682 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2683 pACE++;
2686 return size;
2689 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2690 const posix_acl_xattr_entry *local_ace)
2692 __u16 rc = 0; /* 0 = ACL converted ok */
2694 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2695 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2696 /* BB is there a better way to handle the large uid? */
2697 if (local_ace->e_id == cpu_to_le32(-1)) {
2698 /* Probably no need to le convert -1 on any arch but can not hurt */
2699 cifs_ace->cifs_uid = cpu_to_le64(-1);
2700 } else
2701 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2702 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2703 return rc;
2706 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2707 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2708 const int buflen, const int acl_type)
2710 __u16 rc = 0;
2711 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2712 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2713 int count;
2714 int i;
2716 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2717 return 0;
2719 count = posix_acl_xattr_count((size_t)buflen);
2720 cFYI(1, ("setting acl with %d entries from buf of length %d and "
2721 "version of %d",
2722 count, buflen, le32_to_cpu(local_acl->a_version)));
2723 if (le32_to_cpu(local_acl->a_version) != 2) {
2724 cFYI(1, ("unknown POSIX ACL version %d",
2725 le32_to_cpu(local_acl->a_version)));
2726 return 0;
2728 cifs_acl->version = cpu_to_le16(1);
2729 if (acl_type == ACL_TYPE_ACCESS)
2730 cifs_acl->access_entry_count = cpu_to_le16(count);
2731 else if (acl_type == ACL_TYPE_DEFAULT)
2732 cifs_acl->default_entry_count = cpu_to_le16(count);
2733 else {
2734 cFYI(1, ("unknown ACL type %d", acl_type));
2735 return 0;
2737 for (i = 0; i < count; i++) {
2738 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2739 &local_acl->a_entries[i]);
2740 if (rc != 0) {
2741 /* ACE not converted */
2742 break;
2745 if (rc == 0) {
2746 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2747 rc += sizeof(struct cifs_posix_acl);
2748 /* BB add check to make sure ACL does not overflow SMB */
2750 return rc;
2754 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2755 const unsigned char *searchName,
2756 char *acl_inf, const int buflen, const int acl_type,
2757 const struct nls_table *nls_codepage, int remap)
2759 /* SMB_QUERY_POSIX_ACL */
2760 TRANSACTION2_QPI_REQ *pSMB = NULL;
2761 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2762 int rc = 0;
2763 int bytes_returned;
2764 int name_len;
2765 __u16 params, byte_count;
2767 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2769 queryAclRetry:
2770 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2771 (void **) &pSMBr);
2772 if (rc)
2773 return rc;
2775 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2776 name_len =
2777 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2778 PATH_MAX, nls_codepage, remap);
2779 name_len++; /* trailing null */
2780 name_len *= 2;
2781 pSMB->FileName[name_len] = 0;
2782 pSMB->FileName[name_len+1] = 0;
2783 } else { /* BB improve the check for buffer overruns BB */
2784 name_len = strnlen(searchName, PATH_MAX);
2785 name_len++; /* trailing null */
2786 strncpy(pSMB->FileName, searchName, name_len);
2789 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2790 pSMB->TotalDataCount = 0;
2791 pSMB->MaxParameterCount = cpu_to_le16(2);
2792 /* BB find exact max data count below from sess structure BB */
2793 pSMB->MaxDataCount = cpu_to_le16(4000);
2794 pSMB->MaxSetupCount = 0;
2795 pSMB->Reserved = 0;
2796 pSMB->Flags = 0;
2797 pSMB->Timeout = 0;
2798 pSMB->Reserved2 = 0;
2799 pSMB->ParameterOffset = cpu_to_le16(
2800 offsetof(struct smb_com_transaction2_qpi_req,
2801 InformationLevel) - 4);
2802 pSMB->DataCount = 0;
2803 pSMB->DataOffset = 0;
2804 pSMB->SetupCount = 1;
2805 pSMB->Reserved3 = 0;
2806 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2807 byte_count = params + 1 /* pad */ ;
2808 pSMB->TotalParameterCount = cpu_to_le16(params);
2809 pSMB->ParameterCount = pSMB->TotalParameterCount;
2810 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2811 pSMB->Reserved4 = 0;
2812 pSMB->hdr.smb_buf_length += byte_count;
2813 pSMB->ByteCount = cpu_to_le16(byte_count);
2815 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2816 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2817 cifs_stats_inc(&tcon->num_acl_get);
2818 if (rc) {
2819 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2820 } else {
2821 /* decode response */
2823 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2824 if (rc || (pSMBr->ByteCount < 2))
2825 /* BB also check enough total bytes returned */
2826 rc = -EIO; /* bad smb */
2827 else {
2828 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2829 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2830 rc = cifs_copy_posix_acl(acl_inf,
2831 (char *)&pSMBr->hdr.Protocol+data_offset,
2832 buflen, acl_type, count);
2835 cifs_buf_release(pSMB);
2836 if (rc == -EAGAIN)
2837 goto queryAclRetry;
2838 return rc;
2842 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2843 const unsigned char *fileName,
2844 const char *local_acl, const int buflen,
2845 const int acl_type,
2846 const struct nls_table *nls_codepage, int remap)
2848 struct smb_com_transaction2_spi_req *pSMB = NULL;
2849 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2850 char *parm_data;
2851 int name_len;
2852 int rc = 0;
2853 int bytes_returned = 0;
2854 __u16 params, byte_count, data_count, param_offset, offset;
2856 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2857 setAclRetry:
2858 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2859 (void **) &pSMBr);
2860 if (rc)
2861 return rc;
2862 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2863 name_len =
2864 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2865 PATH_MAX, nls_codepage, remap);
2866 name_len++; /* trailing null */
2867 name_len *= 2;
2868 } else { /* BB improve the check for buffer overruns BB */
2869 name_len = strnlen(fileName, PATH_MAX);
2870 name_len++; /* trailing null */
2871 strncpy(pSMB->FileName, fileName, name_len);
2873 params = 6 + name_len;
2874 pSMB->MaxParameterCount = cpu_to_le16(2);
2875 /* BB find max SMB size from sess */
2876 pSMB->MaxDataCount = cpu_to_le16(1000);
2877 pSMB->MaxSetupCount = 0;
2878 pSMB->Reserved = 0;
2879 pSMB->Flags = 0;
2880 pSMB->Timeout = 0;
2881 pSMB->Reserved2 = 0;
2882 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2883 InformationLevel) - 4;
2884 offset = param_offset + params;
2885 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2886 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2888 /* convert to on the wire format for POSIX ACL */
2889 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2891 if (data_count == 0) {
2892 rc = -EOPNOTSUPP;
2893 goto setACLerrorExit;
2895 pSMB->DataOffset = cpu_to_le16(offset);
2896 pSMB->SetupCount = 1;
2897 pSMB->Reserved3 = 0;
2898 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2899 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2900 byte_count = 3 /* pad */ + params + data_count;
2901 pSMB->DataCount = cpu_to_le16(data_count);
2902 pSMB->TotalDataCount = pSMB->DataCount;
2903 pSMB->ParameterCount = cpu_to_le16(params);
2904 pSMB->TotalParameterCount = pSMB->ParameterCount;
2905 pSMB->Reserved4 = 0;
2906 pSMB->hdr.smb_buf_length += byte_count;
2907 pSMB->ByteCount = cpu_to_le16(byte_count);
2908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2910 if (rc)
2911 cFYI(1, ("Set POSIX ACL returned %d", rc));
2913 setACLerrorExit:
2914 cifs_buf_release(pSMB);
2915 if (rc == -EAGAIN)
2916 goto setAclRetry;
2917 return rc;
2920 /* BB fix tabs in this function FIXME BB */
2922 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2923 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2925 int rc = 0;
2926 struct smb_t2_qfi_req *pSMB = NULL;
2927 struct smb_t2_qfi_rsp *pSMBr = NULL;
2928 int bytes_returned;
2929 __u16 params, byte_count;
2931 cFYI(1, ("In GetExtAttr"));
2932 if (tcon == NULL)
2933 return -ENODEV;
2935 GetExtAttrRetry:
2936 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2937 (void **) &pSMBr);
2938 if (rc)
2939 return rc;
2941 params = 2 /* level */ + 2 /* fid */;
2942 pSMB->t2.TotalDataCount = 0;
2943 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2944 /* BB find exact max data count below from sess structure BB */
2945 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2946 pSMB->t2.MaxSetupCount = 0;
2947 pSMB->t2.Reserved = 0;
2948 pSMB->t2.Flags = 0;
2949 pSMB->t2.Timeout = 0;
2950 pSMB->t2.Reserved2 = 0;
2951 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2952 Fid) - 4);
2953 pSMB->t2.DataCount = 0;
2954 pSMB->t2.DataOffset = 0;
2955 pSMB->t2.SetupCount = 1;
2956 pSMB->t2.Reserved3 = 0;
2957 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2958 byte_count = params + 1 /* pad */ ;
2959 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2960 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2961 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2962 pSMB->Pad = 0;
2963 pSMB->Fid = netfid;
2964 pSMB->hdr.smb_buf_length += byte_count;
2965 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2967 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2968 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2969 if (rc) {
2970 cFYI(1, ("error %d in GetExtAttr", rc));
2971 } else {
2972 /* decode response */
2973 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2974 if (rc || (pSMBr->ByteCount < 2))
2975 /* BB also check enough total bytes returned */
2976 /* If rc should we check for EOPNOSUPP and
2977 disable the srvino flag? or in caller? */
2978 rc = -EIO; /* bad smb */
2979 else {
2980 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2981 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2982 struct file_chattr_info *pfinfo;
2983 /* BB Do we need a cast or hash here ? */
2984 if (count != 16) {
2985 cFYI(1, ("Illegal size ret in GetExtAttr"));
2986 rc = -EIO;
2987 goto GetExtAttrOut;
2989 pfinfo = (struct file_chattr_info *)
2990 (data_offset + (char *) &pSMBr->hdr.Protocol);
2991 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2992 *pMask = le64_to_cpu(pfinfo->mask);
2995 GetExtAttrOut:
2996 cifs_buf_release(pSMB);
2997 if (rc == -EAGAIN)
2998 goto GetExtAttrRetry;
2999 return rc;
3002 #endif /* CONFIG_POSIX */
3004 #ifdef CONFIG_CIFS_EXPERIMENTAL
3005 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3007 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3008 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3010 int rc = 0;
3011 int buf_type = 0;
3012 QUERY_SEC_DESC_REQ *pSMB;
3013 struct kvec iov[1];
3015 cFYI(1, ("GetCifsACL"));
3017 *pbuflen = 0;
3018 *acl_inf = NULL;
3020 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3021 8 /* parm len */, tcon, (void **) &pSMB);
3022 if (rc)
3023 return rc;
3025 pSMB->MaxParameterCount = cpu_to_le32(4);
3026 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3027 pSMB->MaxSetupCount = 0;
3028 pSMB->Fid = fid; /* file handle always le */
3029 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3030 CIFS_ACL_DACL);
3031 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3032 pSMB->hdr.smb_buf_length += 11;
3033 iov[0].iov_base = (char *)pSMB;
3034 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3036 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3037 CIFS_STD_OP);
3038 cifs_stats_inc(&tcon->num_acl_get);
3039 if (rc) {
3040 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3041 } else { /* decode response */
3042 __le32 *parm;
3043 __u32 parm_len;
3044 __u32 acl_len;
3045 struct smb_com_ntransact_rsp *pSMBr;
3046 char *pdata;
3048 /* validate_nttransact */
3049 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3050 &pdata, &parm_len, pbuflen);
3051 if (rc)
3052 goto qsec_out;
3053 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3055 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3057 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3058 rc = -EIO; /* bad smb */
3059 *pbuflen = 0;
3060 goto qsec_out;
3063 /* BB check that data area is minimum length and as big as acl_len */
3065 acl_len = le32_to_cpu(*parm);
3066 if (acl_len != *pbuflen) {
3067 cERROR(1, ("acl length %d does not match %d",
3068 acl_len, *pbuflen));
3069 if (*pbuflen > acl_len)
3070 *pbuflen = acl_len;
3073 /* check if buffer is big enough for the acl
3074 header followed by the smallest SID */
3075 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3076 (*pbuflen >= 64 * 1024)) {
3077 cERROR(1, ("bad acl length %d", *pbuflen));
3078 rc = -EINVAL;
3079 *pbuflen = 0;
3080 } else {
3081 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3082 if (*acl_inf == NULL) {
3083 *pbuflen = 0;
3084 rc = -ENOMEM;
3086 memcpy(*acl_inf, pdata, *pbuflen);
3089 qsec_out:
3090 if (buf_type == CIFS_SMALL_BUFFER)
3091 cifs_small_buf_release(iov[0].iov_base);
3092 else if (buf_type == CIFS_LARGE_BUFFER)
3093 cifs_buf_release(iov[0].iov_base);
3094 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3095 return rc;
3099 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3100 struct cifs_ntsd *pntsd, __u32 acllen)
3102 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3103 int rc = 0;
3104 int bytes_returned = 0;
3105 SET_SEC_DESC_REQ *pSMB = NULL;
3106 NTRANSACT_RSP *pSMBr = NULL;
3108 setCifsAclRetry:
3109 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3110 (void **) &pSMBr);
3111 if (rc)
3112 return (rc);
3114 pSMB->MaxSetupCount = 0;
3115 pSMB->Reserved = 0;
3117 param_count = 8;
3118 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3119 data_count = acllen;
3120 data_offset = param_offset + param_count;
3121 byte_count = 3 /* pad */ + param_count;
3123 pSMB->DataCount = cpu_to_le32(data_count);
3124 pSMB->TotalDataCount = pSMB->DataCount;
3125 pSMB->MaxParameterCount = cpu_to_le32(4);
3126 pSMB->MaxDataCount = cpu_to_le32(16384);
3127 pSMB->ParameterCount = cpu_to_le32(param_count);
3128 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3129 pSMB->TotalParameterCount = pSMB->ParameterCount;
3130 pSMB->DataOffset = cpu_to_le32(data_offset);
3131 pSMB->SetupCount = 0;
3132 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3133 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3135 pSMB->Fid = fid; /* file handle always le */
3136 pSMB->Reserved2 = 0;
3137 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3139 if (pntsd && acllen) {
3140 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3141 (char *) pntsd,
3142 acllen);
3143 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3145 } else
3146 pSMB->hdr.smb_buf_length += byte_count;
3148 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3149 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3151 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3152 if (rc)
3153 cFYI(1, ("Set CIFS ACL returned %d", rc));
3154 cifs_buf_release(pSMB);
3156 if (rc == -EAGAIN)
3157 goto setCifsAclRetry;
3159 return (rc);
3162 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3164 /* Legacy Query Path Information call for lookup to old servers such
3165 as Win9x/WinME */
3166 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3167 const unsigned char *searchName,
3168 FILE_ALL_INFO *pFinfo,
3169 const struct nls_table *nls_codepage, int remap)
3171 QUERY_INFORMATION_REQ *pSMB;
3172 QUERY_INFORMATION_RSP *pSMBr;
3173 int rc = 0;
3174 int bytes_returned;
3175 int name_len;
3177 cFYI(1, ("In SMBQPath path %s", searchName));
3178 QInfRetry:
3179 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3180 (void **) &pSMBr);
3181 if (rc)
3182 return rc;
3184 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3185 name_len =
3186 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3187 PATH_MAX, nls_codepage, remap);
3188 name_len++; /* trailing null */
3189 name_len *= 2;
3190 } else {
3191 name_len = strnlen(searchName, PATH_MAX);
3192 name_len++; /* trailing null */
3193 strncpy(pSMB->FileName, searchName, name_len);
3195 pSMB->BufferFormat = 0x04;
3196 name_len++; /* account for buffer type byte */
3197 pSMB->hdr.smb_buf_length += (__u16) name_len;
3198 pSMB->ByteCount = cpu_to_le16(name_len);
3200 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3201 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3202 if (rc) {
3203 cFYI(1, ("Send error in QueryInfo = %d", rc));
3204 } else if (pFinfo) {
3205 struct timespec ts;
3206 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3208 /* decode response */
3209 /* BB FIXME - add time zone adjustment BB */
3210 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3211 ts.tv_nsec = 0;
3212 ts.tv_sec = time;
3213 /* decode time fields */
3214 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3215 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3216 pFinfo->LastAccessTime = 0;
3217 pFinfo->AllocationSize =
3218 cpu_to_le64(le32_to_cpu(pSMBr->size));
3219 pFinfo->EndOfFile = pFinfo->AllocationSize;
3220 pFinfo->Attributes =
3221 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3222 } else
3223 rc = -EIO; /* bad buffer passed in */
3225 cifs_buf_release(pSMB);
3227 if (rc == -EAGAIN)
3228 goto QInfRetry;
3230 return rc;
3237 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3238 const unsigned char *searchName,
3239 FILE_ALL_INFO *pFindData,
3240 int legacy /* old style infolevel */,
3241 const struct nls_table *nls_codepage, int remap)
3243 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3244 TRANSACTION2_QPI_REQ *pSMB = NULL;
3245 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3246 int rc = 0;
3247 int bytes_returned;
3248 int name_len;
3249 __u16 params, byte_count;
3251 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3252 QPathInfoRetry:
3253 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3254 (void **) &pSMBr);
3255 if (rc)
3256 return rc;
3258 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3259 name_len =
3260 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3261 PATH_MAX, nls_codepage, remap);
3262 name_len++; /* trailing null */
3263 name_len *= 2;
3264 } else { /* BB improve the check for buffer overruns BB */
3265 name_len = strnlen(searchName, PATH_MAX);
3266 name_len++; /* trailing null */
3267 strncpy(pSMB->FileName, searchName, name_len);
3270 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3271 pSMB->TotalDataCount = 0;
3272 pSMB->MaxParameterCount = cpu_to_le16(2);
3273 /* BB find exact max SMB PDU from sess structure BB */
3274 pSMB->MaxDataCount = cpu_to_le16(4000);
3275 pSMB->MaxSetupCount = 0;
3276 pSMB->Reserved = 0;
3277 pSMB->Flags = 0;
3278 pSMB->Timeout = 0;
3279 pSMB->Reserved2 = 0;
3280 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3281 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3282 pSMB->DataCount = 0;
3283 pSMB->DataOffset = 0;
3284 pSMB->SetupCount = 1;
3285 pSMB->Reserved3 = 0;
3286 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3287 byte_count = params + 1 /* pad */ ;
3288 pSMB->TotalParameterCount = cpu_to_le16(params);
3289 pSMB->ParameterCount = pSMB->TotalParameterCount;
3290 if (legacy)
3291 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3292 else
3293 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3294 pSMB->Reserved4 = 0;
3295 pSMB->hdr.smb_buf_length += byte_count;
3296 pSMB->ByteCount = cpu_to_le16(byte_count);
3298 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3299 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3300 if (rc) {
3301 cFYI(1, ("Send error in QPathInfo = %d", rc));
3302 } else { /* decode response */
3303 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3305 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3306 rc = -EIO;
3307 else if (!legacy && (pSMBr->ByteCount < 40))
3308 rc = -EIO; /* bad smb */
3309 else if (legacy && (pSMBr->ByteCount < 24))
3310 rc = -EIO; /* 24 or 26 expected but we do not read
3311 last field */
3312 else if (pFindData) {
3313 int size;
3314 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3316 /* On legacy responses we do not read the last field,
3317 EAsize, fortunately since it varies by subdialect and
3318 also note it differs on Set vs. Get, ie two bytes or 4
3319 bytes depending but we don't care here */
3320 if (legacy)
3321 size = sizeof(FILE_INFO_STANDARD);
3322 else
3323 size = sizeof(FILE_ALL_INFO);
3324 memcpy((char *) pFindData,
3325 (char *) &pSMBr->hdr.Protocol +
3326 data_offset, size);
3327 } else
3328 rc = -ENOMEM;
3330 cifs_buf_release(pSMB);
3331 if (rc == -EAGAIN)
3332 goto QPathInfoRetry;
3334 return rc;
3338 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3339 const unsigned char *searchName,
3340 FILE_UNIX_BASIC_INFO *pFindData,
3341 const struct nls_table *nls_codepage, int remap)
3343 /* SMB_QUERY_FILE_UNIX_BASIC */
3344 TRANSACTION2_QPI_REQ *pSMB = NULL;
3345 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3346 int rc = 0;
3347 int bytes_returned = 0;
3348 int name_len;
3349 __u16 params, byte_count;
3351 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3352 UnixQPathInfoRetry:
3353 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3354 (void **) &pSMBr);
3355 if (rc)
3356 return rc;
3358 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3359 name_len =
3360 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3361 PATH_MAX, nls_codepage, remap);
3362 name_len++; /* trailing null */
3363 name_len *= 2;
3364 } else { /* BB improve the check for buffer overruns BB */
3365 name_len = strnlen(searchName, PATH_MAX);
3366 name_len++; /* trailing null */
3367 strncpy(pSMB->FileName, searchName, name_len);
3370 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3371 pSMB->TotalDataCount = 0;
3372 pSMB->MaxParameterCount = cpu_to_le16(2);
3373 /* BB find exact max SMB PDU from sess structure BB */
3374 pSMB->MaxDataCount = cpu_to_le16(4000);
3375 pSMB->MaxSetupCount = 0;
3376 pSMB->Reserved = 0;
3377 pSMB->Flags = 0;
3378 pSMB->Timeout = 0;
3379 pSMB->Reserved2 = 0;
3380 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3381 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3382 pSMB->DataCount = 0;
3383 pSMB->DataOffset = 0;
3384 pSMB->SetupCount = 1;
3385 pSMB->Reserved3 = 0;
3386 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3387 byte_count = params + 1 /* pad */ ;
3388 pSMB->TotalParameterCount = cpu_to_le16(params);
3389 pSMB->ParameterCount = pSMB->TotalParameterCount;
3390 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3391 pSMB->Reserved4 = 0;
3392 pSMB->hdr.smb_buf_length += byte_count;
3393 pSMB->ByteCount = cpu_to_le16(byte_count);
3395 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3396 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3397 if (rc) {
3398 cFYI(1, ("Send error in QPathInfo = %d", rc));
3399 } else { /* decode response */
3400 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3402 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3403 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3404 "Unix Extensions can be disabled on mount "
3405 "by specifying the nosfu mount option."));
3406 rc = -EIO; /* bad smb */
3407 } else {
3408 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3409 memcpy((char *) pFindData,
3410 (char *) &pSMBr->hdr.Protocol +
3411 data_offset,
3412 sizeof(FILE_UNIX_BASIC_INFO));
3415 cifs_buf_release(pSMB);
3416 if (rc == -EAGAIN)
3417 goto UnixQPathInfoRetry;
3419 return rc;
3422 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3424 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3425 const char *searchName,
3426 const struct nls_table *nls_codepage,
3427 __u16 *pnetfid,
3428 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3430 /* level 257 SMB_ */
3431 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3432 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3433 T2_FFIRST_RSP_PARMS *parms;
3434 int rc = 0;
3435 int bytes_returned = 0;
3436 int name_len;
3437 __u16 params, byte_count;
3439 cFYI(1, ("In FindFirst for %s", searchName));
3441 findFirstRetry:
3442 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3443 (void **) &pSMBr);
3444 if (rc)
3445 return rc;
3447 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3448 name_len =
3449 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3450 PATH_MAX, nls_codepage, remap);
3451 /* We can not add the asterik earlier in case
3452 it got remapped to 0xF03A as if it were part of the
3453 directory name instead of a wildcard */
3454 name_len *= 2;
3455 pSMB->FileName[name_len] = dirsep;
3456 pSMB->FileName[name_len+1] = 0;
3457 pSMB->FileName[name_len+2] = '*';
3458 pSMB->FileName[name_len+3] = 0;
3459 name_len += 4; /* now the trailing null */
3460 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3461 pSMB->FileName[name_len+1] = 0;
3462 name_len += 2;
3463 } else { /* BB add check for overrun of SMB buf BB */
3464 name_len = strnlen(searchName, PATH_MAX);
3465 /* BB fix here and in unicode clause above ie
3466 if (name_len > buffersize-header)
3467 free buffer exit; BB */
3468 strncpy(pSMB->FileName, searchName, name_len);
3469 pSMB->FileName[name_len] = dirsep;
3470 pSMB->FileName[name_len+1] = '*';
3471 pSMB->FileName[name_len+2] = 0;
3472 name_len += 3;
3475 params = 12 + name_len /* includes null */ ;
3476 pSMB->TotalDataCount = 0; /* no EAs */
3477 pSMB->MaxParameterCount = cpu_to_le16(10);
3478 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3479 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3480 pSMB->MaxSetupCount = 0;
3481 pSMB->Reserved = 0;
3482 pSMB->Flags = 0;
3483 pSMB->Timeout = 0;
3484 pSMB->Reserved2 = 0;
3485 byte_count = params + 1 /* pad */ ;
3486 pSMB->TotalParameterCount = cpu_to_le16(params);
3487 pSMB->ParameterCount = pSMB->TotalParameterCount;
3488 pSMB->ParameterOffset = cpu_to_le16(
3489 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3490 - 4);
3491 pSMB->DataCount = 0;
3492 pSMB->DataOffset = 0;
3493 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3494 pSMB->Reserved3 = 0;
3495 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3496 pSMB->SearchAttributes =
3497 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3498 ATTR_DIRECTORY);
3499 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3500 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3501 CIFS_SEARCH_RETURN_RESUME);
3502 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3504 /* BB what should we set StorageType to? Does it matter? BB */
3505 pSMB->SearchStorageType = 0;
3506 pSMB->hdr.smb_buf_length += byte_count;
3507 pSMB->ByteCount = cpu_to_le16(byte_count);
3509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3510 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3511 cifs_stats_inc(&tcon->num_ffirst);
3513 if (rc) {/* BB add logic to retry regular search if Unix search
3514 rejected unexpectedly by server */
3515 /* BB Add code to handle unsupported level rc */
3516 cFYI(1, ("Error in FindFirst = %d", rc));
3518 cifs_buf_release(pSMB);
3520 /* BB eventually could optimize out free and realloc of buf */
3521 /* for this case */
3522 if (rc == -EAGAIN)
3523 goto findFirstRetry;
3524 } else { /* decode response */
3525 /* BB remember to free buffer if error BB */
3526 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3527 if (rc == 0) {
3528 unsigned int lnoff;
3530 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3531 psrch_inf->unicode = true;
3532 else
3533 psrch_inf->unicode = false;
3535 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3536 psrch_inf->smallBuf = 0;
3537 psrch_inf->srch_entries_start =
3538 (char *) &pSMBr->hdr.Protocol +
3539 le16_to_cpu(pSMBr->t2.DataOffset);
3540 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3541 le16_to_cpu(pSMBr->t2.ParameterOffset));
3543 if (parms->EndofSearch)
3544 psrch_inf->endOfSearch = true;
3545 else
3546 psrch_inf->endOfSearch = false;
3548 psrch_inf->entries_in_buffer =
3549 le16_to_cpu(parms->SearchCount);
3550 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3551 psrch_inf->entries_in_buffer;
3552 lnoff = le16_to_cpu(parms->LastNameOffset);
3553 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3554 lnoff) {
3555 cERROR(1, ("ignoring corrupt resume name"));
3556 psrch_inf->last_entry = NULL;
3557 return rc;
3560 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3561 lnoff;
3563 *pnetfid = parms->SearchHandle;
3564 } else {
3565 cifs_buf_release(pSMB);
3569 return rc;
3572 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3573 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3575 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3576 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3577 T2_FNEXT_RSP_PARMS *parms;
3578 char *response_data;
3579 int rc = 0;
3580 int bytes_returned, name_len;
3581 __u16 params, byte_count;
3583 cFYI(1, ("In FindNext"));
3585 if (psrch_inf->endOfSearch)
3586 return -ENOENT;
3588 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3589 (void **) &pSMBr);
3590 if (rc)
3591 return rc;
3593 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3594 byte_count = 0;
3595 pSMB->TotalDataCount = 0; /* no EAs */
3596 pSMB->MaxParameterCount = cpu_to_le16(8);
3597 pSMB->MaxDataCount =
3598 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3599 0xFFFFFF00);
3600 pSMB->MaxSetupCount = 0;
3601 pSMB->Reserved = 0;
3602 pSMB->Flags = 0;
3603 pSMB->Timeout = 0;
3604 pSMB->Reserved2 = 0;
3605 pSMB->ParameterOffset = cpu_to_le16(
3606 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3607 pSMB->DataCount = 0;
3608 pSMB->DataOffset = 0;
3609 pSMB->SetupCount = 1;
3610 pSMB->Reserved3 = 0;
3611 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3612 pSMB->SearchHandle = searchHandle; /* always kept as le */
3613 pSMB->SearchCount =
3614 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3615 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3616 pSMB->ResumeKey = psrch_inf->resume_key;
3617 pSMB->SearchFlags =
3618 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3620 name_len = psrch_inf->resume_name_len;
3621 params += name_len;
3622 if (name_len < PATH_MAX) {
3623 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3624 byte_count += name_len;
3625 /* 14 byte parm len above enough for 2 byte null terminator */
3626 pSMB->ResumeFileName[name_len] = 0;
3627 pSMB->ResumeFileName[name_len+1] = 0;
3628 } else {
3629 rc = -EINVAL;
3630 goto FNext2_err_exit;
3632 byte_count = params + 1 /* pad */ ;
3633 pSMB->TotalParameterCount = cpu_to_le16(params);
3634 pSMB->ParameterCount = pSMB->TotalParameterCount;
3635 pSMB->hdr.smb_buf_length += byte_count;
3636 pSMB->ByteCount = cpu_to_le16(byte_count);
3638 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3639 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3640 cifs_stats_inc(&tcon->num_fnext);
3641 if (rc) {
3642 if (rc == -EBADF) {
3643 psrch_inf->endOfSearch = true;
3644 cifs_buf_release(pSMB);
3645 rc = 0; /* search probably was closed at end of search*/
3646 } else
3647 cFYI(1, ("FindNext returned = %d", rc));
3648 } else { /* decode response */
3649 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3651 if (rc == 0) {
3652 unsigned int lnoff;
3654 /* BB fixme add lock for file (srch_info) struct here */
3655 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3656 psrch_inf->unicode = true;
3657 else
3658 psrch_inf->unicode = false;
3659 response_data = (char *) &pSMBr->hdr.Protocol +
3660 le16_to_cpu(pSMBr->t2.ParameterOffset);
3661 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3662 response_data = (char *)&pSMBr->hdr.Protocol +
3663 le16_to_cpu(pSMBr->t2.DataOffset);
3664 if (psrch_inf->smallBuf)
3665 cifs_small_buf_release(
3666 psrch_inf->ntwrk_buf_start);
3667 else
3668 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3669 psrch_inf->srch_entries_start = response_data;
3670 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3671 psrch_inf->smallBuf = 0;
3672 if (parms->EndofSearch)
3673 psrch_inf->endOfSearch = true;
3674 else
3675 psrch_inf->endOfSearch = false;
3676 psrch_inf->entries_in_buffer =
3677 le16_to_cpu(parms->SearchCount);
3678 psrch_inf->index_of_last_entry +=
3679 psrch_inf->entries_in_buffer;
3680 lnoff = le16_to_cpu(parms->LastNameOffset);
3681 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3682 lnoff) {
3683 cERROR(1, ("ignoring corrupt resume name"));
3684 psrch_inf->last_entry = NULL;
3685 return rc;
3686 } else
3687 psrch_inf->last_entry =
3688 psrch_inf->srch_entries_start + lnoff;
3690 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3691 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3693 /* BB fixme add unlock here */
3698 /* BB On error, should we leave previous search buf (and count and
3699 last entry fields) intact or free the previous one? */
3701 /* Note: On -EAGAIN error only caller can retry on handle based calls
3702 since file handle passed in no longer valid */
3703 FNext2_err_exit:
3704 if (rc != 0)
3705 cifs_buf_release(pSMB);
3706 return rc;
3710 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3711 const __u16 searchHandle)
3713 int rc = 0;
3714 FINDCLOSE_REQ *pSMB = NULL;
3716 cFYI(1, ("In CIFSSMBFindClose"));
3717 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3719 /* no sense returning error if session restarted
3720 as file handle has been closed */
3721 if (rc == -EAGAIN)
3722 return 0;
3723 if (rc)
3724 return rc;
3726 pSMB->FileID = searchHandle;
3727 pSMB->ByteCount = 0;
3728 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3729 if (rc)
3730 cERROR(1, ("Send error in FindClose = %d", rc));
3732 cifs_stats_inc(&tcon->num_fclose);
3734 /* Since session is dead, search handle closed on server already */
3735 if (rc == -EAGAIN)
3736 rc = 0;
3738 return rc;
3742 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3743 const unsigned char *searchName,
3744 __u64 *inode_number,
3745 const struct nls_table *nls_codepage, int remap)
3747 int rc = 0;
3748 TRANSACTION2_QPI_REQ *pSMB = NULL;
3749 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3750 int name_len, bytes_returned;
3751 __u16 params, byte_count;
3753 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3754 if (tcon == NULL)
3755 return -ENODEV;
3757 GetInodeNumberRetry:
3758 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3759 (void **) &pSMBr);
3760 if (rc)
3761 return rc;
3763 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3764 name_len =
3765 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3766 PATH_MAX, nls_codepage, remap);
3767 name_len++; /* trailing null */
3768 name_len *= 2;
3769 } else { /* BB improve the check for buffer overruns BB */
3770 name_len = strnlen(searchName, PATH_MAX);
3771 name_len++; /* trailing null */
3772 strncpy(pSMB->FileName, searchName, name_len);
3775 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3776 pSMB->TotalDataCount = 0;
3777 pSMB->MaxParameterCount = cpu_to_le16(2);
3778 /* BB find exact max data count below from sess structure BB */
3779 pSMB->MaxDataCount = cpu_to_le16(4000);
3780 pSMB->MaxSetupCount = 0;
3781 pSMB->Reserved = 0;
3782 pSMB->Flags = 0;
3783 pSMB->Timeout = 0;
3784 pSMB->Reserved2 = 0;
3785 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3786 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3787 pSMB->DataCount = 0;
3788 pSMB->DataOffset = 0;
3789 pSMB->SetupCount = 1;
3790 pSMB->Reserved3 = 0;
3791 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3792 byte_count = params + 1 /* pad */ ;
3793 pSMB->TotalParameterCount = cpu_to_le16(params);
3794 pSMB->ParameterCount = pSMB->TotalParameterCount;
3795 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3796 pSMB->Reserved4 = 0;
3797 pSMB->hdr.smb_buf_length += byte_count;
3798 pSMB->ByteCount = cpu_to_le16(byte_count);
3800 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3801 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3802 if (rc) {
3803 cFYI(1, ("error %d in QueryInternalInfo", rc));
3804 } else {
3805 /* decode response */
3806 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3807 if (rc || (pSMBr->ByteCount < 2))
3808 /* BB also check enough total bytes returned */
3809 /* If rc should we check for EOPNOSUPP and
3810 disable the srvino flag? or in caller? */
3811 rc = -EIO; /* bad smb */
3812 else {
3813 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3814 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3815 struct file_internal_info *pfinfo;
3816 /* BB Do we need a cast or hash here ? */
3817 if (count < 8) {
3818 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3819 rc = -EIO;
3820 goto GetInodeNumOut;
3822 pfinfo = (struct file_internal_info *)
3823 (data_offset + (char *) &pSMBr->hdr.Protocol);
3824 *inode_number = le64_to_cpu(pfinfo->UniqueId);
3827 GetInodeNumOut:
3828 cifs_buf_release(pSMB);
3829 if (rc == -EAGAIN)
3830 goto GetInodeNumberRetry;
3831 return rc;
3834 /* parses DFS refferal V3 structure
3835 * caller is responsible for freeing target_nodes
3836 * returns:
3837 * on success - 0
3838 * on failure - errno
3840 static int
3841 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
3842 unsigned int *num_of_nodes,
3843 struct dfs_info3_param **target_nodes,
3844 const struct nls_table *nls_codepage, int remap,
3845 const char *searchName)
3847 int i, rc = 0;
3848 char *data_end;
3849 bool is_unicode;
3850 struct dfs_referral_level_3 *ref;
3852 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3853 is_unicode = true;
3854 else
3855 is_unicode = false;
3856 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3858 if (*num_of_nodes < 1) {
3859 cERROR(1, ("num_referrals: must be at least > 0,"
3860 "but we get num_referrals = %d\n", *num_of_nodes));
3861 rc = -EINVAL;
3862 goto parse_DFS_referrals_exit;
3865 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
3866 if (ref->VersionNumber != cpu_to_le16(3)) {
3867 cERROR(1, ("Referrals of V%d version are not supported,"
3868 "should be V3", le16_to_cpu(ref->VersionNumber)));
3869 rc = -EINVAL;
3870 goto parse_DFS_referrals_exit;
3873 /* get the upper boundary of the resp buffer */
3874 data_end = (char *)(&(pSMBr->PathConsumed)) +
3875 le16_to_cpu(pSMBr->t2.DataCount);
3877 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3878 *num_of_nodes,
3879 le32_to_cpu(pSMBr->DFSFlags)));
3881 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3882 *num_of_nodes, GFP_KERNEL);
3883 if (*target_nodes == NULL) {
3884 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3885 rc = -ENOMEM;
3886 goto parse_DFS_referrals_exit;
3889 /* collect neccessary data from referrals */
3890 for (i = 0; i < *num_of_nodes; i++) {
3891 char *temp;
3892 int max_len;
3893 struct dfs_info3_param *node = (*target_nodes)+i;
3895 node->flags = le32_to_cpu(pSMBr->DFSFlags);
3896 if (is_unicode) {
3897 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3898 GFP_KERNEL);
3899 if (tmp == NULL) {
3900 rc = -ENOMEM;
3901 goto parse_DFS_referrals_exit;
3903 cifsConvertToUCS((__le16 *) tmp, searchName,
3904 PATH_MAX, nls_codepage, remap);
3905 node->path_consumed = cifs_ucs2_bytes(tmp,
3906 le16_to_cpu(pSMBr->PathConsumed),
3907 nls_codepage);
3908 kfree(tmp);
3909 } else
3910 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3912 node->server_type = le16_to_cpu(ref->ServerType);
3913 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3915 /* copy DfsPath */
3916 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3917 max_len = data_end - temp;
3918 node->path_name = cifs_strndup_from_ucs(temp, max_len,
3919 is_unicode, nls_codepage);
3920 if (!node->path_name) {
3921 rc = -ENOMEM;
3922 goto parse_DFS_referrals_exit;
3925 /* copy link target UNC */
3926 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3927 max_len = data_end - temp;
3928 node->node_name = cifs_strndup_from_ucs(temp, max_len,
3929 is_unicode, nls_codepage);
3930 if (!node->node_name)
3931 rc = -ENOMEM;
3934 parse_DFS_referrals_exit:
3935 if (rc) {
3936 free_dfs_info_array(*target_nodes, *num_of_nodes);
3937 *target_nodes = NULL;
3938 *num_of_nodes = 0;
3940 return rc;
3944 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3945 const unsigned char *searchName,
3946 struct dfs_info3_param **target_nodes,
3947 unsigned int *num_of_nodes,
3948 const struct nls_table *nls_codepage, int remap)
3950 /* TRANS2_GET_DFS_REFERRAL */
3951 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3952 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3953 int rc = 0;
3954 int bytes_returned;
3955 int name_len;
3956 __u16 params, byte_count;
3957 *num_of_nodes = 0;
3958 *target_nodes = NULL;
3960 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3961 if (ses == NULL)
3962 return -ENODEV;
3963 getDFSRetry:
3964 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3965 (void **) &pSMBr);
3966 if (rc)
3967 return rc;
3969 /* server pointer checked in called function,
3970 but should never be null here anyway */
3971 pSMB->hdr.Mid = GetNextMid(ses->server);
3972 pSMB->hdr.Tid = ses->ipc_tid;
3973 pSMB->hdr.Uid = ses->Suid;
3974 if (ses->capabilities & CAP_STATUS32)
3975 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3976 if (ses->capabilities & CAP_DFS)
3977 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3979 if (ses->capabilities & CAP_UNICODE) {
3980 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3981 name_len =
3982 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3983 searchName, PATH_MAX, nls_codepage, remap);
3984 name_len++; /* trailing null */
3985 name_len *= 2;
3986 } else { /* BB improve the check for buffer overruns BB */
3987 name_len = strnlen(searchName, PATH_MAX);
3988 name_len++; /* trailing null */
3989 strncpy(pSMB->RequestFileName, searchName, name_len);
3992 if (ses->server) {
3993 if (ses->server->secMode &
3994 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3995 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3998 pSMB->hdr.Uid = ses->Suid;
4000 params = 2 /* level */ + name_len /*includes null */ ;
4001 pSMB->TotalDataCount = 0;
4002 pSMB->DataCount = 0;
4003 pSMB->DataOffset = 0;
4004 pSMB->MaxParameterCount = 0;
4005 /* BB find exact max SMB PDU from sess structure BB */
4006 pSMB->MaxDataCount = cpu_to_le16(4000);
4007 pSMB->MaxSetupCount = 0;
4008 pSMB->Reserved = 0;
4009 pSMB->Flags = 0;
4010 pSMB->Timeout = 0;
4011 pSMB->Reserved2 = 0;
4012 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4013 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4014 pSMB->SetupCount = 1;
4015 pSMB->Reserved3 = 0;
4016 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4017 byte_count = params + 3 /* pad */ ;
4018 pSMB->ParameterCount = cpu_to_le16(params);
4019 pSMB->TotalParameterCount = pSMB->ParameterCount;
4020 pSMB->MaxReferralLevel = cpu_to_le16(3);
4021 pSMB->hdr.smb_buf_length += byte_count;
4022 pSMB->ByteCount = cpu_to_le16(byte_count);
4024 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4025 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4026 if (rc) {
4027 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
4028 goto GetDFSRefExit;
4030 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4032 /* BB Also check if enough total bytes returned? */
4033 if (rc || (pSMBr->ByteCount < 17)) {
4034 rc = -EIO; /* bad smb */
4035 goto GetDFSRefExit;
4038 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4039 pSMBr->ByteCount,
4040 le16_to_cpu(pSMBr->t2.DataOffset)));
4042 /* parse returned result into more usable form */
4043 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4044 target_nodes, nls_codepage, remap,
4045 searchName);
4047 GetDFSRefExit:
4048 cifs_buf_release(pSMB);
4050 if (rc == -EAGAIN)
4051 goto getDFSRetry;
4053 return rc;
4056 /* Query File System Info such as free space to old servers such as Win 9x */
4058 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4060 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4061 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4062 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4063 FILE_SYSTEM_ALLOC_INFO *response_data;
4064 int rc = 0;
4065 int bytes_returned = 0;
4066 __u16 params, byte_count;
4068 cFYI(1, ("OldQFSInfo"));
4069 oldQFSInfoRetry:
4070 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4071 (void **) &pSMBr);
4072 if (rc)
4073 return rc;
4075 params = 2; /* level */
4076 pSMB->TotalDataCount = 0;
4077 pSMB->MaxParameterCount = cpu_to_le16(2);
4078 pSMB->MaxDataCount = cpu_to_le16(1000);
4079 pSMB->MaxSetupCount = 0;
4080 pSMB->Reserved = 0;
4081 pSMB->Flags = 0;
4082 pSMB->Timeout = 0;
4083 pSMB->Reserved2 = 0;
4084 byte_count = params + 1 /* pad */ ;
4085 pSMB->TotalParameterCount = cpu_to_le16(params);
4086 pSMB->ParameterCount = pSMB->TotalParameterCount;
4087 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4088 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4089 pSMB->DataCount = 0;
4090 pSMB->DataOffset = 0;
4091 pSMB->SetupCount = 1;
4092 pSMB->Reserved3 = 0;
4093 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4094 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4095 pSMB->hdr.smb_buf_length += byte_count;
4096 pSMB->ByteCount = cpu_to_le16(byte_count);
4098 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4099 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4100 if (rc) {
4101 cFYI(1, ("Send error in QFSInfo = %d", rc));
4102 } else { /* decode response */
4103 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4105 if (rc || (pSMBr->ByteCount < 18))
4106 rc = -EIO; /* bad smb */
4107 else {
4108 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4109 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4110 pSMBr->ByteCount, data_offset));
4112 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4113 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4114 FSData->f_bsize =
4115 le16_to_cpu(response_data->BytesPerSector) *
4116 le32_to_cpu(response_data->
4117 SectorsPerAllocationUnit);
4118 FSData->f_blocks =
4119 le32_to_cpu(response_data->TotalAllocationUnits);
4120 FSData->f_bfree = FSData->f_bavail =
4121 le32_to_cpu(response_data->FreeAllocationUnits);
4122 cFYI(1,
4123 ("Blocks: %lld Free: %lld Block size %ld",
4124 (unsigned long long)FSData->f_blocks,
4125 (unsigned long long)FSData->f_bfree,
4126 FSData->f_bsize));
4129 cifs_buf_release(pSMB);
4131 if (rc == -EAGAIN)
4132 goto oldQFSInfoRetry;
4134 return rc;
4138 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4140 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4141 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4142 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4143 FILE_SYSTEM_INFO *response_data;
4144 int rc = 0;
4145 int bytes_returned = 0;
4146 __u16 params, byte_count;
4148 cFYI(1, ("In QFSInfo"));
4149 QFSInfoRetry:
4150 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4151 (void **) &pSMBr);
4152 if (rc)
4153 return rc;
4155 params = 2; /* level */
4156 pSMB->TotalDataCount = 0;
4157 pSMB->MaxParameterCount = cpu_to_le16(2);
4158 pSMB->MaxDataCount = cpu_to_le16(1000);
4159 pSMB->MaxSetupCount = 0;
4160 pSMB->Reserved = 0;
4161 pSMB->Flags = 0;
4162 pSMB->Timeout = 0;
4163 pSMB->Reserved2 = 0;
4164 byte_count = params + 1 /* pad */ ;
4165 pSMB->TotalParameterCount = cpu_to_le16(params);
4166 pSMB->ParameterCount = pSMB->TotalParameterCount;
4167 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4168 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4169 pSMB->DataCount = 0;
4170 pSMB->DataOffset = 0;
4171 pSMB->SetupCount = 1;
4172 pSMB->Reserved3 = 0;
4173 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4174 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4175 pSMB->hdr.smb_buf_length += byte_count;
4176 pSMB->ByteCount = cpu_to_le16(byte_count);
4178 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4179 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4180 if (rc) {
4181 cFYI(1, ("Send error in QFSInfo = %d", rc));
4182 } else { /* decode response */
4183 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4185 if (rc || (pSMBr->ByteCount < 24))
4186 rc = -EIO; /* bad smb */
4187 else {
4188 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4190 response_data =
4191 (FILE_SYSTEM_INFO
4192 *) (((char *) &pSMBr->hdr.Protocol) +
4193 data_offset);
4194 FSData->f_bsize =
4195 le32_to_cpu(response_data->BytesPerSector) *
4196 le32_to_cpu(response_data->
4197 SectorsPerAllocationUnit);
4198 FSData->f_blocks =
4199 le64_to_cpu(response_data->TotalAllocationUnits);
4200 FSData->f_bfree = FSData->f_bavail =
4201 le64_to_cpu(response_data->FreeAllocationUnits);
4202 cFYI(1,
4203 ("Blocks: %lld Free: %lld Block size %ld",
4204 (unsigned long long)FSData->f_blocks,
4205 (unsigned long long)FSData->f_bfree,
4206 FSData->f_bsize));
4209 cifs_buf_release(pSMB);
4211 if (rc == -EAGAIN)
4212 goto QFSInfoRetry;
4214 return rc;
4218 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4220 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4221 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4222 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4223 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4224 int rc = 0;
4225 int bytes_returned = 0;
4226 __u16 params, byte_count;
4228 cFYI(1, ("In QFSAttributeInfo"));
4229 QFSAttributeRetry:
4230 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4231 (void **) &pSMBr);
4232 if (rc)
4233 return rc;
4235 params = 2; /* level */
4236 pSMB->TotalDataCount = 0;
4237 pSMB->MaxParameterCount = cpu_to_le16(2);
4238 /* BB find exact max SMB PDU from sess structure BB */
4239 pSMB->MaxDataCount = cpu_to_le16(1000);
4240 pSMB->MaxSetupCount = 0;
4241 pSMB->Reserved = 0;
4242 pSMB->Flags = 0;
4243 pSMB->Timeout = 0;
4244 pSMB->Reserved2 = 0;
4245 byte_count = params + 1 /* pad */ ;
4246 pSMB->TotalParameterCount = cpu_to_le16(params);
4247 pSMB->ParameterCount = pSMB->TotalParameterCount;
4248 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4249 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4250 pSMB->DataCount = 0;
4251 pSMB->DataOffset = 0;
4252 pSMB->SetupCount = 1;
4253 pSMB->Reserved3 = 0;
4254 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4255 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4256 pSMB->hdr.smb_buf_length += byte_count;
4257 pSMB->ByteCount = cpu_to_le16(byte_count);
4259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4260 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4261 if (rc) {
4262 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4263 } else { /* decode response */
4264 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4266 if (rc || (pSMBr->ByteCount < 13)) {
4267 /* BB also check if enough bytes returned */
4268 rc = -EIO; /* bad smb */
4269 } else {
4270 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4271 response_data =
4272 (FILE_SYSTEM_ATTRIBUTE_INFO
4273 *) (((char *) &pSMBr->hdr.Protocol) +
4274 data_offset);
4275 memcpy(&tcon->fsAttrInfo, response_data,
4276 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4279 cifs_buf_release(pSMB);
4281 if (rc == -EAGAIN)
4282 goto QFSAttributeRetry;
4284 return rc;
4288 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4290 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4291 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4292 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4293 FILE_SYSTEM_DEVICE_INFO *response_data;
4294 int rc = 0;
4295 int bytes_returned = 0;
4296 __u16 params, byte_count;
4298 cFYI(1, ("In QFSDeviceInfo"));
4299 QFSDeviceRetry:
4300 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4301 (void **) &pSMBr);
4302 if (rc)
4303 return rc;
4305 params = 2; /* level */
4306 pSMB->TotalDataCount = 0;
4307 pSMB->MaxParameterCount = cpu_to_le16(2);
4308 /* BB find exact max SMB PDU from sess structure BB */
4309 pSMB->MaxDataCount = cpu_to_le16(1000);
4310 pSMB->MaxSetupCount = 0;
4311 pSMB->Reserved = 0;
4312 pSMB->Flags = 0;
4313 pSMB->Timeout = 0;
4314 pSMB->Reserved2 = 0;
4315 byte_count = params + 1 /* pad */ ;
4316 pSMB->TotalParameterCount = cpu_to_le16(params);
4317 pSMB->ParameterCount = pSMB->TotalParameterCount;
4318 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4319 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4321 pSMB->DataCount = 0;
4322 pSMB->DataOffset = 0;
4323 pSMB->SetupCount = 1;
4324 pSMB->Reserved3 = 0;
4325 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4326 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4327 pSMB->hdr.smb_buf_length += byte_count;
4328 pSMB->ByteCount = cpu_to_le16(byte_count);
4330 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4331 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4332 if (rc) {
4333 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4334 } else { /* decode response */
4335 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4337 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4338 rc = -EIO; /* bad smb */
4339 else {
4340 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4341 response_data =
4342 (FILE_SYSTEM_DEVICE_INFO *)
4343 (((char *) &pSMBr->hdr.Protocol) +
4344 data_offset);
4345 memcpy(&tcon->fsDevInfo, response_data,
4346 sizeof(FILE_SYSTEM_DEVICE_INFO));
4349 cifs_buf_release(pSMB);
4351 if (rc == -EAGAIN)
4352 goto QFSDeviceRetry;
4354 return rc;
4358 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4360 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4361 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4362 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4363 FILE_SYSTEM_UNIX_INFO *response_data;
4364 int rc = 0;
4365 int bytes_returned = 0;
4366 __u16 params, byte_count;
4368 cFYI(1, ("In QFSUnixInfo"));
4369 QFSUnixRetry:
4370 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4371 (void **) &pSMBr);
4372 if (rc)
4373 return rc;
4375 params = 2; /* level */
4376 pSMB->TotalDataCount = 0;
4377 pSMB->DataCount = 0;
4378 pSMB->DataOffset = 0;
4379 pSMB->MaxParameterCount = cpu_to_le16(2);
4380 /* BB find exact max SMB PDU from sess structure BB */
4381 pSMB->MaxDataCount = cpu_to_le16(100);
4382 pSMB->MaxSetupCount = 0;
4383 pSMB->Reserved = 0;
4384 pSMB->Flags = 0;
4385 pSMB->Timeout = 0;
4386 pSMB->Reserved2 = 0;
4387 byte_count = params + 1 /* pad */ ;
4388 pSMB->ParameterCount = cpu_to_le16(params);
4389 pSMB->TotalParameterCount = pSMB->ParameterCount;
4390 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4391 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4392 pSMB->SetupCount = 1;
4393 pSMB->Reserved3 = 0;
4394 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4395 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4396 pSMB->hdr.smb_buf_length += byte_count;
4397 pSMB->ByteCount = cpu_to_le16(byte_count);
4399 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4400 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4401 if (rc) {
4402 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4403 } else { /* decode response */
4404 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4406 if (rc || (pSMBr->ByteCount < 13)) {
4407 rc = -EIO; /* bad smb */
4408 } else {
4409 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4410 response_data =
4411 (FILE_SYSTEM_UNIX_INFO
4412 *) (((char *) &pSMBr->hdr.Protocol) +
4413 data_offset);
4414 memcpy(&tcon->fsUnixInfo, response_data,
4415 sizeof(FILE_SYSTEM_UNIX_INFO));
4418 cifs_buf_release(pSMB);
4420 if (rc == -EAGAIN)
4421 goto QFSUnixRetry;
4424 return rc;
4428 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4430 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4431 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4432 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4433 int rc = 0;
4434 int bytes_returned = 0;
4435 __u16 params, param_offset, offset, byte_count;
4437 cFYI(1, ("In SETFSUnixInfo"));
4438 SETFSUnixRetry:
4439 /* BB switch to small buf init to save memory */
4440 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4441 (void **) &pSMBr);
4442 if (rc)
4443 return rc;
4445 params = 4; /* 2 bytes zero followed by info level. */
4446 pSMB->MaxSetupCount = 0;
4447 pSMB->Reserved = 0;
4448 pSMB->Flags = 0;
4449 pSMB->Timeout = 0;
4450 pSMB->Reserved2 = 0;
4451 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4452 - 4;
4453 offset = param_offset + params;
4455 pSMB->MaxParameterCount = cpu_to_le16(4);
4456 /* BB find exact max SMB PDU from sess structure BB */
4457 pSMB->MaxDataCount = cpu_to_le16(100);
4458 pSMB->SetupCount = 1;
4459 pSMB->Reserved3 = 0;
4460 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4461 byte_count = 1 /* pad */ + params + 12;
4463 pSMB->DataCount = cpu_to_le16(12);
4464 pSMB->ParameterCount = cpu_to_le16(params);
4465 pSMB->TotalDataCount = pSMB->DataCount;
4466 pSMB->TotalParameterCount = pSMB->ParameterCount;
4467 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4468 pSMB->DataOffset = cpu_to_le16(offset);
4470 /* Params. */
4471 pSMB->FileNum = 0;
4472 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4474 /* Data. */
4475 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4476 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4477 pSMB->ClientUnixCap = cpu_to_le64(cap);
4479 pSMB->hdr.smb_buf_length += byte_count;
4480 pSMB->ByteCount = cpu_to_le16(byte_count);
4482 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4483 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4484 if (rc) {
4485 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4486 } else { /* decode response */
4487 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4488 if (rc)
4489 rc = -EIO; /* bad smb */
4491 cifs_buf_release(pSMB);
4493 if (rc == -EAGAIN)
4494 goto SETFSUnixRetry;
4496 return rc;
4502 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4503 struct kstatfs *FSData)
4505 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4506 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4507 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4508 FILE_SYSTEM_POSIX_INFO *response_data;
4509 int rc = 0;
4510 int bytes_returned = 0;
4511 __u16 params, byte_count;
4513 cFYI(1, ("In QFSPosixInfo"));
4514 QFSPosixRetry:
4515 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4516 (void **) &pSMBr);
4517 if (rc)
4518 return rc;
4520 params = 2; /* level */
4521 pSMB->TotalDataCount = 0;
4522 pSMB->DataCount = 0;
4523 pSMB->DataOffset = 0;
4524 pSMB->MaxParameterCount = cpu_to_le16(2);
4525 /* BB find exact max SMB PDU from sess structure BB */
4526 pSMB->MaxDataCount = cpu_to_le16(100);
4527 pSMB->MaxSetupCount = 0;
4528 pSMB->Reserved = 0;
4529 pSMB->Flags = 0;
4530 pSMB->Timeout = 0;
4531 pSMB->Reserved2 = 0;
4532 byte_count = params + 1 /* pad */ ;
4533 pSMB->ParameterCount = cpu_to_le16(params);
4534 pSMB->TotalParameterCount = pSMB->ParameterCount;
4535 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4536 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4537 pSMB->SetupCount = 1;
4538 pSMB->Reserved3 = 0;
4539 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4540 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4541 pSMB->hdr.smb_buf_length += byte_count;
4542 pSMB->ByteCount = cpu_to_le16(byte_count);
4544 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4545 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4546 if (rc) {
4547 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4548 } else { /* decode response */
4549 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4551 if (rc || (pSMBr->ByteCount < 13)) {
4552 rc = -EIO; /* bad smb */
4553 } else {
4554 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4555 response_data =
4556 (FILE_SYSTEM_POSIX_INFO
4557 *) (((char *) &pSMBr->hdr.Protocol) +
4558 data_offset);
4559 FSData->f_bsize =
4560 le32_to_cpu(response_data->BlockSize);
4561 FSData->f_blocks =
4562 le64_to_cpu(response_data->TotalBlocks);
4563 FSData->f_bfree =
4564 le64_to_cpu(response_data->BlocksAvail);
4565 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4566 FSData->f_bavail = FSData->f_bfree;
4567 } else {
4568 FSData->f_bavail =
4569 le64_to_cpu(response_data->UserBlocksAvail);
4571 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4572 FSData->f_files =
4573 le64_to_cpu(response_data->TotalFileNodes);
4574 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4575 FSData->f_ffree =
4576 le64_to_cpu(response_data->FreeFileNodes);
4579 cifs_buf_release(pSMB);
4581 if (rc == -EAGAIN)
4582 goto QFSPosixRetry;
4584 return rc;
4588 /* We can not use write of zero bytes trick to
4589 set file size due to need for large file support. Also note that
4590 this SetPathInfo is preferred to SetFileInfo based method in next
4591 routine which is only needed to work around a sharing violation bug
4592 in Samba which this routine can run into */
4595 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4596 __u64 size, bool SetAllocation,
4597 const struct nls_table *nls_codepage, int remap)
4599 struct smb_com_transaction2_spi_req *pSMB = NULL;
4600 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4601 struct file_end_of_file_info *parm_data;
4602 int name_len;
4603 int rc = 0;
4604 int bytes_returned = 0;
4605 __u16 params, byte_count, data_count, param_offset, offset;
4607 cFYI(1, ("In SetEOF"));
4608 SetEOFRetry:
4609 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4610 (void **) &pSMBr);
4611 if (rc)
4612 return rc;
4614 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4615 name_len =
4616 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4617 PATH_MAX, nls_codepage, remap);
4618 name_len++; /* trailing null */
4619 name_len *= 2;
4620 } else { /* BB improve the check for buffer overruns BB */
4621 name_len = strnlen(fileName, PATH_MAX);
4622 name_len++; /* trailing null */
4623 strncpy(pSMB->FileName, fileName, name_len);
4625 params = 6 + name_len;
4626 data_count = sizeof(struct file_end_of_file_info);
4627 pSMB->MaxParameterCount = cpu_to_le16(2);
4628 pSMB->MaxDataCount = cpu_to_le16(4100);
4629 pSMB->MaxSetupCount = 0;
4630 pSMB->Reserved = 0;
4631 pSMB->Flags = 0;
4632 pSMB->Timeout = 0;
4633 pSMB->Reserved2 = 0;
4634 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4635 InformationLevel) - 4;
4636 offset = param_offset + params;
4637 if (SetAllocation) {
4638 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4639 pSMB->InformationLevel =
4640 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4641 else
4642 pSMB->InformationLevel =
4643 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4644 } else /* Set File Size */ {
4645 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4646 pSMB->InformationLevel =
4647 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4648 else
4649 pSMB->InformationLevel =
4650 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4653 parm_data =
4654 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4655 offset);
4656 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4657 pSMB->DataOffset = cpu_to_le16(offset);
4658 pSMB->SetupCount = 1;
4659 pSMB->Reserved3 = 0;
4660 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4661 byte_count = 3 /* pad */ + params + data_count;
4662 pSMB->DataCount = cpu_to_le16(data_count);
4663 pSMB->TotalDataCount = pSMB->DataCount;
4664 pSMB->ParameterCount = cpu_to_le16(params);
4665 pSMB->TotalParameterCount = pSMB->ParameterCount;
4666 pSMB->Reserved4 = 0;
4667 pSMB->hdr.smb_buf_length += byte_count;
4668 parm_data->FileSize = cpu_to_le64(size);
4669 pSMB->ByteCount = cpu_to_le16(byte_count);
4670 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4671 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4672 if (rc)
4673 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4675 cifs_buf_release(pSMB);
4677 if (rc == -EAGAIN)
4678 goto SetEOFRetry;
4680 return rc;
4684 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4685 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4687 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4688 char *data_offset;
4689 struct file_end_of_file_info *parm_data;
4690 int rc = 0;
4691 __u16 params, param_offset, offset, byte_count, count;
4693 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4694 (long long)size));
4695 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4697 if (rc)
4698 return rc;
4700 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4701 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4703 params = 6;
4704 pSMB->MaxSetupCount = 0;
4705 pSMB->Reserved = 0;
4706 pSMB->Flags = 0;
4707 pSMB->Timeout = 0;
4708 pSMB->Reserved2 = 0;
4709 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4710 offset = param_offset + params;
4712 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4714 count = sizeof(struct file_end_of_file_info);
4715 pSMB->MaxParameterCount = cpu_to_le16(2);
4716 /* BB find exact max SMB PDU from sess structure BB */
4717 pSMB->MaxDataCount = cpu_to_le16(1000);
4718 pSMB->SetupCount = 1;
4719 pSMB->Reserved3 = 0;
4720 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4721 byte_count = 3 /* pad */ + params + count;
4722 pSMB->DataCount = cpu_to_le16(count);
4723 pSMB->ParameterCount = cpu_to_le16(params);
4724 pSMB->TotalDataCount = pSMB->DataCount;
4725 pSMB->TotalParameterCount = pSMB->ParameterCount;
4726 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4727 parm_data =
4728 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4729 + offset);
4730 pSMB->DataOffset = cpu_to_le16(offset);
4731 parm_data->FileSize = cpu_to_le64(size);
4732 pSMB->Fid = fid;
4733 if (SetAllocation) {
4734 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4735 pSMB->InformationLevel =
4736 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4737 else
4738 pSMB->InformationLevel =
4739 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4740 } else /* Set File Size */ {
4741 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4742 pSMB->InformationLevel =
4743 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4744 else
4745 pSMB->InformationLevel =
4746 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4748 pSMB->Reserved4 = 0;
4749 pSMB->hdr.smb_buf_length += byte_count;
4750 pSMB->ByteCount = cpu_to_le16(byte_count);
4751 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4752 if (rc) {
4753 cFYI(1,
4754 ("Send error in SetFileInfo (SetFileSize) = %d",
4755 rc));
4758 /* Note: On -EAGAIN error only caller can retry on handle based calls
4759 since file handle passed in no longer valid */
4761 return rc;
4764 /* Some legacy servers such as NT4 require that the file times be set on
4765 an open handle, rather than by pathname - this is awkward due to
4766 potential access conflicts on the open, but it is unavoidable for these
4767 old servers since the only other choice is to go from 100 nanosecond DCE
4768 time and resort to the original setpathinfo level which takes the ancient
4769 DOS time format with 2 second granularity */
4771 CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4772 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4774 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4775 char *data_offset;
4776 int rc = 0;
4777 __u16 params, param_offset, offset, byte_count, count;
4779 cFYI(1, ("Set Times (via SetFileInfo)"));
4780 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4782 if (rc)
4783 return rc;
4785 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4786 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4788 params = 6;
4789 pSMB->MaxSetupCount = 0;
4790 pSMB->Reserved = 0;
4791 pSMB->Flags = 0;
4792 pSMB->Timeout = 0;
4793 pSMB->Reserved2 = 0;
4794 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4795 offset = param_offset + params;
4797 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4799 count = sizeof(FILE_BASIC_INFO);
4800 pSMB->MaxParameterCount = cpu_to_le16(2);
4801 /* BB find max SMB PDU from sess */
4802 pSMB->MaxDataCount = cpu_to_le16(1000);
4803 pSMB->SetupCount = 1;
4804 pSMB->Reserved3 = 0;
4805 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4806 byte_count = 3 /* pad */ + params + count;
4807 pSMB->DataCount = cpu_to_le16(count);
4808 pSMB->ParameterCount = cpu_to_le16(params);
4809 pSMB->TotalDataCount = pSMB->DataCount;
4810 pSMB->TotalParameterCount = pSMB->ParameterCount;
4811 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4812 pSMB->DataOffset = cpu_to_le16(offset);
4813 pSMB->Fid = fid;
4814 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4815 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4816 else
4817 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4818 pSMB->Reserved4 = 0;
4819 pSMB->hdr.smb_buf_length += byte_count;
4820 pSMB->ByteCount = cpu_to_le16(byte_count);
4821 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4822 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4823 if (rc)
4824 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4826 /* Note: On -EAGAIN error only caller can retry on handle based calls
4827 since file handle passed in no longer valid */
4829 return rc;
4833 CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4834 bool delete_file, __u16 fid, __u32 pid_of_opener)
4836 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4837 char *data_offset;
4838 int rc = 0;
4839 __u16 params, param_offset, offset, byte_count, count;
4841 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4842 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4844 if (rc)
4845 return rc;
4847 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4848 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4850 params = 6;
4851 pSMB->MaxSetupCount = 0;
4852 pSMB->Reserved = 0;
4853 pSMB->Flags = 0;
4854 pSMB->Timeout = 0;
4855 pSMB->Reserved2 = 0;
4856 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4857 offset = param_offset + params;
4859 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4861 count = 1;
4862 pSMB->MaxParameterCount = cpu_to_le16(2);
4863 /* BB find max SMB PDU from sess */
4864 pSMB->MaxDataCount = cpu_to_le16(1000);
4865 pSMB->SetupCount = 1;
4866 pSMB->Reserved3 = 0;
4867 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4868 byte_count = 3 /* pad */ + params + count;
4869 pSMB->DataCount = cpu_to_le16(count);
4870 pSMB->ParameterCount = cpu_to_le16(params);
4871 pSMB->TotalDataCount = pSMB->DataCount;
4872 pSMB->TotalParameterCount = pSMB->ParameterCount;
4873 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4874 pSMB->DataOffset = cpu_to_le16(offset);
4875 pSMB->Fid = fid;
4876 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4877 pSMB->Reserved4 = 0;
4878 pSMB->hdr.smb_buf_length += byte_count;
4879 pSMB->ByteCount = cpu_to_le16(byte_count);
4880 *data_offset = delete_file ? 1 : 0;
4881 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4882 if (rc)
4883 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4885 return rc;
4889 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4890 const char *fileName, const FILE_BASIC_INFO *data,
4891 const struct nls_table *nls_codepage, int remap)
4893 TRANSACTION2_SPI_REQ *pSMB = NULL;
4894 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4895 int name_len;
4896 int rc = 0;
4897 int bytes_returned = 0;
4898 char *data_offset;
4899 __u16 params, param_offset, offset, byte_count, count;
4901 cFYI(1, ("In SetTimes"));
4903 SetTimesRetry:
4904 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4905 (void **) &pSMBr);
4906 if (rc)
4907 return rc;
4909 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4910 name_len =
4911 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4912 PATH_MAX, nls_codepage, remap);
4913 name_len++; /* trailing null */
4914 name_len *= 2;
4915 } else { /* BB improve the check for buffer overruns BB */
4916 name_len = strnlen(fileName, PATH_MAX);
4917 name_len++; /* trailing null */
4918 strncpy(pSMB->FileName, fileName, name_len);
4921 params = 6 + name_len;
4922 count = sizeof(FILE_BASIC_INFO);
4923 pSMB->MaxParameterCount = cpu_to_le16(2);
4924 /* BB find max SMB PDU from sess structure BB */
4925 pSMB->MaxDataCount = cpu_to_le16(1000);
4926 pSMB->MaxSetupCount = 0;
4927 pSMB->Reserved = 0;
4928 pSMB->Flags = 0;
4929 pSMB->Timeout = 0;
4930 pSMB->Reserved2 = 0;
4931 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4932 InformationLevel) - 4;
4933 offset = param_offset + params;
4934 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4935 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4936 pSMB->DataOffset = cpu_to_le16(offset);
4937 pSMB->SetupCount = 1;
4938 pSMB->Reserved3 = 0;
4939 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4940 byte_count = 3 /* pad */ + params + count;
4942 pSMB->DataCount = cpu_to_le16(count);
4943 pSMB->ParameterCount = cpu_to_le16(params);
4944 pSMB->TotalDataCount = pSMB->DataCount;
4945 pSMB->TotalParameterCount = pSMB->ParameterCount;
4946 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4947 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4948 else
4949 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4950 pSMB->Reserved4 = 0;
4951 pSMB->hdr.smb_buf_length += byte_count;
4952 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4953 pSMB->ByteCount = cpu_to_le16(byte_count);
4954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4956 if (rc)
4957 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4959 cifs_buf_release(pSMB);
4961 if (rc == -EAGAIN)
4962 goto SetTimesRetry;
4964 return rc;
4967 /* Can not be used to set time stamps yet (due to old DOS time format) */
4968 /* Can be used to set attributes */
4969 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4970 handling it anyway and NT4 was what we thought it would be needed for
4971 Do not delete it until we prove whether needed for Win9x though */
4973 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4974 __u16 dos_attrs, const struct nls_table *nls_codepage)
4976 SETATTR_REQ *pSMB = NULL;
4977 SETATTR_RSP *pSMBr = NULL;
4978 int rc = 0;
4979 int bytes_returned;
4980 int name_len;
4982 cFYI(1, ("In SetAttrLegacy"));
4984 SetAttrLgcyRetry:
4985 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4986 (void **) &pSMBr);
4987 if (rc)
4988 return rc;
4990 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4991 name_len =
4992 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4993 PATH_MAX, nls_codepage);
4994 name_len++; /* trailing null */
4995 name_len *= 2;
4996 } else { /* BB improve the check for buffer overruns BB */
4997 name_len = strnlen(fileName, PATH_MAX);
4998 name_len++; /* trailing null */
4999 strncpy(pSMB->fileName, fileName, name_len);
5001 pSMB->attr = cpu_to_le16(dos_attrs);
5002 pSMB->BufferFormat = 0x04;
5003 pSMB->hdr.smb_buf_length += name_len + 1;
5004 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5007 if (rc)
5008 cFYI(1, ("Error in LegacySetAttr = %d", rc));
5010 cifs_buf_release(pSMB);
5012 if (rc == -EAGAIN)
5013 goto SetAttrLgcyRetry;
5015 return rc;
5017 #endif /* temporarily unneeded SetAttr legacy function */
5019 static void
5020 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5021 const struct cifs_unix_set_info_args *args)
5023 u64 mode = args->mode;
5026 * Samba server ignores set of file size to zero due to bugs in some
5027 * older clients, but we should be precise - we use SetFileSize to
5028 * set file size and do not want to truncate file size to zero
5029 * accidently as happened on one Samba server beta by putting
5030 * zero instead of -1 here
5032 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5033 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5034 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5035 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5036 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5037 data_offset->Uid = cpu_to_le64(args->uid);
5038 data_offset->Gid = cpu_to_le64(args->gid);
5039 /* better to leave device as zero when it is */
5040 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5041 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5042 data_offset->Permissions = cpu_to_le64(mode);
5044 if (S_ISREG(mode))
5045 data_offset->Type = cpu_to_le32(UNIX_FILE);
5046 else if (S_ISDIR(mode))
5047 data_offset->Type = cpu_to_le32(UNIX_DIR);
5048 else if (S_ISLNK(mode))
5049 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5050 else if (S_ISCHR(mode))
5051 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5052 else if (S_ISBLK(mode))
5053 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5054 else if (S_ISFIFO(mode))
5055 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5056 else if (S_ISSOCK(mode))
5057 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5061 CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5062 const struct cifs_unix_set_info_args *args,
5063 u16 fid, u32 pid_of_opener)
5065 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5066 FILE_UNIX_BASIC_INFO *data_offset;
5067 int rc = 0;
5068 u16 params, param_offset, offset, byte_count, count;
5070 cFYI(1, ("Set Unix Info (via SetFileInfo)"));
5071 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5073 if (rc)
5074 return rc;
5076 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5077 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5079 params = 6;
5080 pSMB->MaxSetupCount = 0;
5081 pSMB->Reserved = 0;
5082 pSMB->Flags = 0;
5083 pSMB->Timeout = 0;
5084 pSMB->Reserved2 = 0;
5085 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5086 offset = param_offset + params;
5088 data_offset = (FILE_UNIX_BASIC_INFO *)
5089 ((char *)(&pSMB->hdr.Protocol) + offset);
5090 count = sizeof(FILE_UNIX_BASIC_INFO);
5092 pSMB->MaxParameterCount = cpu_to_le16(2);
5093 /* BB find max SMB PDU from sess */
5094 pSMB->MaxDataCount = cpu_to_le16(1000);
5095 pSMB->SetupCount = 1;
5096 pSMB->Reserved3 = 0;
5097 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5098 byte_count = 3 /* pad */ + params + count;
5099 pSMB->DataCount = cpu_to_le16(count);
5100 pSMB->ParameterCount = cpu_to_le16(params);
5101 pSMB->TotalDataCount = pSMB->DataCount;
5102 pSMB->TotalParameterCount = pSMB->ParameterCount;
5103 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5104 pSMB->DataOffset = cpu_to_le16(offset);
5105 pSMB->Fid = fid;
5106 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5107 pSMB->Reserved4 = 0;
5108 pSMB->hdr.smb_buf_length += byte_count;
5109 pSMB->ByteCount = cpu_to_le16(byte_count);
5111 cifs_fill_unix_set_info(data_offset, args);
5113 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5114 if (rc)
5115 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
5117 /* Note: On -EAGAIN error only caller can retry on handle based calls
5118 since file handle passed in no longer valid */
5120 return rc;
5124 CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5125 const struct cifs_unix_set_info_args *args,
5126 const struct nls_table *nls_codepage, int remap)
5128 TRANSACTION2_SPI_REQ *pSMB = NULL;
5129 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5130 int name_len;
5131 int rc = 0;
5132 int bytes_returned = 0;
5133 FILE_UNIX_BASIC_INFO *data_offset;
5134 __u16 params, param_offset, offset, count, byte_count;
5136 cFYI(1, ("In SetUID/GID/Mode"));
5137 setPermsRetry:
5138 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5139 (void **) &pSMBr);
5140 if (rc)
5141 return rc;
5143 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5144 name_len =
5145 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5146 PATH_MAX, nls_codepage, remap);
5147 name_len++; /* trailing null */
5148 name_len *= 2;
5149 } else { /* BB improve the check for buffer overruns BB */
5150 name_len = strnlen(fileName, PATH_MAX);
5151 name_len++; /* trailing null */
5152 strncpy(pSMB->FileName, fileName, name_len);
5155 params = 6 + name_len;
5156 count = sizeof(FILE_UNIX_BASIC_INFO);
5157 pSMB->MaxParameterCount = cpu_to_le16(2);
5158 /* BB find max SMB PDU from sess structure BB */
5159 pSMB->MaxDataCount = cpu_to_le16(1000);
5160 pSMB->MaxSetupCount = 0;
5161 pSMB->Reserved = 0;
5162 pSMB->Flags = 0;
5163 pSMB->Timeout = 0;
5164 pSMB->Reserved2 = 0;
5165 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5166 InformationLevel) - 4;
5167 offset = param_offset + params;
5168 data_offset =
5169 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5170 offset);
5171 memset(data_offset, 0, count);
5172 pSMB->DataOffset = cpu_to_le16(offset);
5173 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5174 pSMB->SetupCount = 1;
5175 pSMB->Reserved3 = 0;
5176 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5177 byte_count = 3 /* pad */ + params + count;
5178 pSMB->ParameterCount = cpu_to_le16(params);
5179 pSMB->DataCount = cpu_to_le16(count);
5180 pSMB->TotalParameterCount = pSMB->ParameterCount;
5181 pSMB->TotalDataCount = pSMB->DataCount;
5182 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5183 pSMB->Reserved4 = 0;
5184 pSMB->hdr.smb_buf_length += byte_count;
5186 cifs_fill_unix_set_info(data_offset, args);
5188 pSMB->ByteCount = cpu_to_le16(byte_count);
5189 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5190 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5191 if (rc)
5192 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5194 cifs_buf_release(pSMB);
5195 if (rc == -EAGAIN)
5196 goto setPermsRetry;
5197 return rc;
5200 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5201 const int notify_subdirs, const __u16 netfid,
5202 __u32 filter, struct file *pfile, int multishot,
5203 const struct nls_table *nls_codepage)
5205 int rc = 0;
5206 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5207 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5208 struct dir_notify_req *dnotify_req;
5209 int bytes_returned;
5211 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5212 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5213 (void **) &pSMBr);
5214 if (rc)
5215 return rc;
5217 pSMB->TotalParameterCount = 0 ;
5218 pSMB->TotalDataCount = 0;
5219 pSMB->MaxParameterCount = cpu_to_le32(2);
5220 /* BB find exact data count max from sess structure BB */
5221 pSMB->MaxDataCount = 0; /* same in little endian or be */
5222 /* BB VERIFY verify which is correct for above BB */
5223 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5224 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5226 pSMB->MaxSetupCount = 4;
5227 pSMB->Reserved = 0;
5228 pSMB->ParameterOffset = 0;
5229 pSMB->DataCount = 0;
5230 pSMB->DataOffset = 0;
5231 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5232 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5233 pSMB->ParameterCount = pSMB->TotalParameterCount;
5234 if (notify_subdirs)
5235 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5236 pSMB->Reserved2 = 0;
5237 pSMB->CompletionFilter = cpu_to_le32(filter);
5238 pSMB->Fid = netfid; /* file handle always le */
5239 pSMB->ByteCount = 0;
5241 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5242 (struct smb_hdr *)pSMBr, &bytes_returned,
5243 CIFS_ASYNC_OP);
5244 if (rc) {
5245 cFYI(1, ("Error in Notify = %d", rc));
5246 } else {
5247 /* Add file to outstanding requests */
5248 /* BB change to kmem cache alloc */
5249 dnotify_req = kmalloc(
5250 sizeof(struct dir_notify_req),
5251 GFP_KERNEL);
5252 if (dnotify_req) {
5253 dnotify_req->Pid = pSMB->hdr.Pid;
5254 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5255 dnotify_req->Mid = pSMB->hdr.Mid;
5256 dnotify_req->Tid = pSMB->hdr.Tid;
5257 dnotify_req->Uid = pSMB->hdr.Uid;
5258 dnotify_req->netfid = netfid;
5259 dnotify_req->pfile = pfile;
5260 dnotify_req->filter = filter;
5261 dnotify_req->multishot = multishot;
5262 spin_lock(&GlobalMid_Lock);
5263 list_add_tail(&dnotify_req->lhead,
5264 &GlobalDnotifyReqList);
5265 spin_unlock(&GlobalMid_Lock);
5266 } else
5267 rc = -ENOMEM;
5269 cifs_buf_release(pSMB);
5270 return rc;
5273 #ifdef CONFIG_CIFS_XATTR
5275 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5276 * function used by listxattr and getxattr type calls. When ea_name is set,
5277 * it looks for that attribute name and stuffs that value into the EAData
5278 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5279 * buffer. In both cases, the return value is either the length of the
5280 * resulting data or a negative error code. If EAData is a NULL pointer then
5281 * the data isn't copied to it, but the length is returned.
5283 ssize_t
5284 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5285 const unsigned char *searchName, const unsigned char *ea_name,
5286 char *EAData, size_t buf_size,
5287 const struct nls_table *nls_codepage, int remap)
5289 /* BB assumes one setup word */
5290 TRANSACTION2_QPI_REQ *pSMB = NULL;
5291 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5292 int rc = 0;
5293 int bytes_returned;
5294 int list_len;
5295 struct fealist *ea_response_data;
5296 struct fea *temp_fea;
5297 char *temp_ptr;
5298 char *end_of_smb;
5299 __u16 params, byte_count, data_offset;
5301 cFYI(1, ("In Query All EAs path %s", searchName));
5302 QAllEAsRetry:
5303 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5304 (void **) &pSMBr);
5305 if (rc)
5306 return rc;
5308 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5309 list_len =
5310 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5311 PATH_MAX, nls_codepage, remap);
5312 list_len++; /* trailing null */
5313 list_len *= 2;
5314 } else { /* BB improve the check for buffer overruns BB */
5315 list_len = strnlen(searchName, PATH_MAX);
5316 list_len++; /* trailing null */
5317 strncpy(pSMB->FileName, searchName, list_len);
5320 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
5321 pSMB->TotalDataCount = 0;
5322 pSMB->MaxParameterCount = cpu_to_le16(2);
5323 /* BB find exact max SMB PDU from sess structure BB */
5324 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
5325 pSMB->MaxSetupCount = 0;
5326 pSMB->Reserved = 0;
5327 pSMB->Flags = 0;
5328 pSMB->Timeout = 0;
5329 pSMB->Reserved2 = 0;
5330 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5331 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5332 pSMB->DataCount = 0;
5333 pSMB->DataOffset = 0;
5334 pSMB->SetupCount = 1;
5335 pSMB->Reserved3 = 0;
5336 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5337 byte_count = params + 1 /* pad */ ;
5338 pSMB->TotalParameterCount = cpu_to_le16(params);
5339 pSMB->ParameterCount = pSMB->TotalParameterCount;
5340 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5341 pSMB->Reserved4 = 0;
5342 pSMB->hdr.smb_buf_length += byte_count;
5343 pSMB->ByteCount = cpu_to_le16(byte_count);
5345 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5347 if (rc) {
5348 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5349 goto QAllEAsOut;
5353 /* BB also check enough total bytes returned */
5354 /* BB we need to improve the validity checking
5355 of these trans2 responses */
5357 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5358 if (rc || (pSMBr->ByteCount < 4)) {
5359 rc = -EIO; /* bad smb */
5360 goto QAllEAsOut;
5363 /* check that length of list is not more than bcc */
5364 /* check that each entry does not go beyond length
5365 of list */
5366 /* check that each element of each entry does not
5367 go beyond end of list */
5368 /* validate_trans2_offsets() */
5369 /* BB check if start of smb + data_offset > &bcc+ bcc */
5371 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5372 ea_response_data = (struct fealist *)
5373 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5375 list_len = le32_to_cpu(ea_response_data->list_len);
5376 cFYI(1, ("ea length %d", list_len));
5377 if (list_len <= 8) {
5378 cFYI(1, ("empty EA list returned from server"));
5379 goto QAllEAsOut;
5382 /* make sure list_len doesn't go past end of SMB */
5383 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5384 if ((char *)ea_response_data + list_len > end_of_smb) {
5385 cFYI(1, ("EA list appears to go beyond SMB"));
5386 rc = -EIO;
5387 goto QAllEAsOut;
5390 /* account for ea list len */
5391 list_len -= 4;
5392 temp_fea = ea_response_data->list;
5393 temp_ptr = (char *)temp_fea;
5394 while (list_len > 0) {
5395 unsigned int name_len;
5396 __u16 value_len;
5398 list_len -= 4;
5399 temp_ptr += 4;
5400 /* make sure we can read name_len and value_len */
5401 if (list_len < 0) {
5402 cFYI(1, ("EA entry goes beyond length of list"));
5403 rc = -EIO;
5404 goto QAllEAsOut;
5407 name_len = temp_fea->name_len;
5408 value_len = le16_to_cpu(temp_fea->value_len);
5409 list_len -= name_len + 1 + value_len;
5410 if (list_len < 0) {
5411 cFYI(1, ("EA entry goes beyond length of list"));
5412 rc = -EIO;
5413 goto QAllEAsOut;
5416 if (ea_name) {
5417 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5418 temp_ptr += name_len + 1;
5419 rc = value_len;
5420 if (buf_size == 0)
5421 goto QAllEAsOut;
5422 if ((size_t)value_len > buf_size) {
5423 rc = -ERANGE;
5424 goto QAllEAsOut;
5426 memcpy(EAData, temp_ptr, value_len);
5427 goto QAllEAsOut;
5429 } else {
5430 /* account for prefix user. and trailing null */
5431 rc += (5 + 1 + name_len);
5432 if (rc < (int) buf_size) {
5433 memcpy(EAData, "user.", 5);
5434 EAData += 5;
5435 memcpy(EAData, temp_ptr, name_len);
5436 EAData += name_len;
5437 /* null terminate name */
5438 *EAData = 0;
5439 ++EAData;
5440 } else if (buf_size == 0) {
5441 /* skip copy - calc size only */
5442 } else {
5443 /* stop before overrun buffer */
5444 rc = -ERANGE;
5445 break;
5448 temp_ptr += name_len + 1 + value_len;
5449 temp_fea = (struct fea *)temp_ptr;
5452 /* didn't find the named attribute */
5453 if (ea_name)
5454 rc = -ENODATA;
5456 QAllEAsOut:
5457 cifs_buf_release(pSMB);
5458 if (rc == -EAGAIN)
5459 goto QAllEAsRetry;
5461 return (ssize_t)rc;
5465 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5466 const char *ea_name, const void *ea_value,
5467 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5468 int remap)
5470 struct smb_com_transaction2_spi_req *pSMB = NULL;
5471 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5472 struct fealist *parm_data;
5473 int name_len;
5474 int rc = 0;
5475 int bytes_returned = 0;
5476 __u16 params, param_offset, byte_count, offset, count;
5478 cFYI(1, ("In SetEA"));
5479 SetEARetry:
5480 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5481 (void **) &pSMBr);
5482 if (rc)
5483 return rc;
5485 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5486 name_len =
5487 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5488 PATH_MAX, nls_codepage, remap);
5489 name_len++; /* trailing null */
5490 name_len *= 2;
5491 } else { /* BB improve the check for buffer overruns BB */
5492 name_len = strnlen(fileName, PATH_MAX);
5493 name_len++; /* trailing null */
5494 strncpy(pSMB->FileName, fileName, name_len);
5497 params = 6 + name_len;
5499 /* done calculating parms using name_len of file name,
5500 now use name_len to calculate length of ea name
5501 we are going to create in the inode xattrs */
5502 if (ea_name == NULL)
5503 name_len = 0;
5504 else
5505 name_len = strnlen(ea_name, 255);
5507 count = sizeof(*parm_data) + ea_value_len + name_len;
5508 pSMB->MaxParameterCount = cpu_to_le16(2);
5509 /* BB find max SMB PDU from sess */
5510 pSMB->MaxDataCount = cpu_to_le16(1000);
5511 pSMB->MaxSetupCount = 0;
5512 pSMB->Reserved = 0;
5513 pSMB->Flags = 0;
5514 pSMB->Timeout = 0;
5515 pSMB->Reserved2 = 0;
5516 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5517 InformationLevel) - 4;
5518 offset = param_offset + params;
5519 pSMB->InformationLevel =
5520 cpu_to_le16(SMB_SET_FILE_EA);
5522 parm_data =
5523 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5524 offset);
5525 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5526 pSMB->DataOffset = cpu_to_le16(offset);
5527 pSMB->SetupCount = 1;
5528 pSMB->Reserved3 = 0;
5529 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5530 byte_count = 3 /* pad */ + params + count;
5531 pSMB->DataCount = cpu_to_le16(count);
5532 parm_data->list_len = cpu_to_le32(count);
5533 parm_data->list[0].EA_flags = 0;
5534 /* we checked above that name len is less than 255 */
5535 parm_data->list[0].name_len = (__u8)name_len;
5536 /* EA names are always ASCII */
5537 if (ea_name)
5538 strncpy(parm_data->list[0].name, ea_name, name_len);
5539 parm_data->list[0].name[name_len] = 0;
5540 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5541 /* caller ensures that ea_value_len is less than 64K but
5542 we need to ensure that it fits within the smb */
5544 /*BB add length check to see if it would fit in
5545 negotiated SMB buffer size BB */
5546 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5547 if (ea_value_len)
5548 memcpy(parm_data->list[0].name+name_len+1,
5549 ea_value, ea_value_len);
5551 pSMB->TotalDataCount = pSMB->DataCount;
5552 pSMB->ParameterCount = cpu_to_le16(params);
5553 pSMB->TotalParameterCount = pSMB->ParameterCount;
5554 pSMB->Reserved4 = 0;
5555 pSMB->hdr.smb_buf_length += byte_count;
5556 pSMB->ByteCount = cpu_to_le16(byte_count);
5557 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5558 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5559 if (rc)
5560 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5562 cifs_buf_release(pSMB);
5564 if (rc == -EAGAIN)
5565 goto SetEARetry;
5567 return rc;
5570 #endif