Fix gcc 4.5.1 miscompiling drivers/char/i8k.c (again)
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / cifs / cifssmb.c
blob04b755ae1b38c2f8e43a6f8d1468522c7f56d38c
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 down(&ses->sesSem);
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 up(&ses->sesSem);
180 goto out;
183 mark_open_files_invalid(tcon);
184 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
185 up(&ses->sesSem);
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 down(&ses->sesSem);
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 up(&ses->sesSem);
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 up(&ses->sesSem);
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 *nbytes = 0;
1435 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
1436 if (tcon->ses == NULL)
1437 return -ECONNABORTED;
1439 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1440 wct = 14;
1441 else {
1442 wct = 12;
1443 if ((offset >> 32) > 0) {
1444 /* can not handle big offset for old srv */
1445 return -EIO;
1449 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1450 (void **) &pSMBr);
1451 if (rc)
1452 return rc;
1453 /* tcon and ses pointer are checked in smb_init */
1454 if (tcon->ses->server == NULL)
1455 return -ECONNABORTED;
1457 pSMB->AndXCommand = 0xFF; /* none */
1458 pSMB->Fid = netfid;
1459 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1460 if (wct == 14)
1461 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1463 pSMB->Reserved = 0xFFFFFFFF;
1464 pSMB->WriteMode = 0;
1465 pSMB->Remaining = 0;
1467 /* Can increase buffer size if buffer is big enough in some cases ie we
1468 can send more if LARGE_WRITE_X capability returned by the server and if
1469 our buffer is big enough or if we convert to iovecs on socket writes
1470 and eliminate the copy to the CIFS buffer */
1471 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1472 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1473 } else {
1474 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1475 & ~0xFF;
1478 if (bytes_sent > count)
1479 bytes_sent = count;
1480 pSMB->DataOffset =
1481 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1482 if (buf)
1483 memcpy(pSMB->Data, buf, bytes_sent);
1484 else if (ubuf) {
1485 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1486 cifs_buf_release(pSMB);
1487 return -EFAULT;
1489 } else if (count != 0) {
1490 /* No buffer */
1491 cifs_buf_release(pSMB);
1492 return -EINVAL;
1493 } /* else setting file size with write of zero bytes */
1494 if (wct == 14)
1495 byte_count = bytes_sent + 1; /* pad */
1496 else /* wct == 12 */
1497 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1499 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1500 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1501 pSMB->hdr.smb_buf_length += byte_count;
1503 if (wct == 14)
1504 pSMB->ByteCount = cpu_to_le16(byte_count);
1505 else { /* old style write has byte count 4 bytes earlier
1506 so 4 bytes pad */
1507 struct smb_com_writex_req *pSMBW =
1508 (struct smb_com_writex_req *)pSMB;
1509 pSMBW->ByteCount = cpu_to_le16(byte_count);
1512 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1513 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1514 cifs_stats_inc(&tcon->num_writes);
1515 if (rc) {
1516 cFYI(1, ("Send error in write = %d", rc));
1517 } else {
1518 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1519 *nbytes = (*nbytes) << 16;
1520 *nbytes += le16_to_cpu(pSMBr->Count);
1523 * Mask off high 16 bits when bytes written as returned by the
1524 * server is greater than bytes requested by the client. Some
1525 * OS/2 servers are known to set incorrect CountHigh values.
1527 if (*nbytes > count)
1528 *nbytes &= 0xFFFF;
1531 cifs_buf_release(pSMB);
1533 /* Note: On -EAGAIN error only caller can retry on handle based calls
1534 since file handle passed in no longer valid */
1536 return rc;
1540 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1541 const int netfid, const unsigned int count,
1542 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1543 int n_vec, const int long_op)
1545 int rc = -EACCES;
1546 WRITE_REQ *pSMB = NULL;
1547 int wct;
1548 int smb_hdr_len;
1549 int resp_buf_type = 0;
1551 *nbytes = 0;
1553 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1555 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1556 wct = 14;
1557 } else {
1558 wct = 12;
1559 if ((offset >> 32) > 0) {
1560 /* can not handle big offset for old srv */
1561 return -EIO;
1564 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1565 if (rc)
1566 return rc;
1567 /* tcon and ses pointer are checked in smb_init */
1568 if (tcon->ses->server == NULL)
1569 return -ECONNABORTED;
1571 pSMB->AndXCommand = 0xFF; /* none */
1572 pSMB->Fid = netfid;
1573 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1574 if (wct == 14)
1575 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1576 pSMB->Reserved = 0xFFFFFFFF;
1577 pSMB->WriteMode = 0;
1578 pSMB->Remaining = 0;
1580 pSMB->DataOffset =
1581 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1583 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1584 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1585 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1586 if (wct == 14)
1587 pSMB->hdr.smb_buf_length += count+1;
1588 else /* wct == 12 */
1589 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1590 if (wct == 14)
1591 pSMB->ByteCount = cpu_to_le16(count + 1);
1592 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1593 struct smb_com_writex_req *pSMBW =
1594 (struct smb_com_writex_req *)pSMB;
1595 pSMBW->ByteCount = cpu_to_le16(count + 5);
1597 iov[0].iov_base = pSMB;
1598 if (wct == 14)
1599 iov[0].iov_len = smb_hdr_len + 4;
1600 else /* wct == 12 pad bigger by four bytes */
1601 iov[0].iov_len = smb_hdr_len + 8;
1604 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1605 long_op);
1606 cifs_stats_inc(&tcon->num_writes);
1607 if (rc) {
1608 cFYI(1, ("Send error Write2 = %d", rc));
1609 } else if (resp_buf_type == 0) {
1610 /* presumably this can not happen, but best to be safe */
1611 rc = -EIO;
1612 } else {
1613 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1614 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1615 *nbytes = (*nbytes) << 16;
1616 *nbytes += le16_to_cpu(pSMBr->Count);
1619 * Mask off high 16 bits when bytes written as returned by the
1620 * server is greater than bytes requested by the client. OS/2
1621 * servers are known to set incorrect CountHigh values.
1623 if (*nbytes > count)
1624 *nbytes &= 0xFFFF;
1627 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1628 if (resp_buf_type == CIFS_SMALL_BUFFER)
1629 cifs_small_buf_release(iov[0].iov_base);
1630 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1631 cifs_buf_release(iov[0].iov_base);
1633 /* Note: On -EAGAIN error only caller can retry on handle based calls
1634 since file handle passed in no longer valid */
1636 return rc;
1641 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1642 const __u16 smb_file_id, const __u64 len,
1643 const __u64 offset, const __u32 numUnlock,
1644 const __u32 numLock, const __u8 lockType,
1645 const bool waitFlag, const __u8 oplock_level)
1647 int rc = 0;
1648 LOCK_REQ *pSMB = NULL;
1649 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1650 int bytes_returned;
1651 int timeout = 0;
1652 __u16 count;
1654 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1655 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1657 if (rc)
1658 return rc;
1660 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1661 timeout = CIFS_ASYNC_OP; /* no response expected */
1662 pSMB->Timeout = 0;
1663 } else if (waitFlag) {
1664 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1665 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1666 } else {
1667 pSMB->Timeout = 0;
1670 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1671 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1672 pSMB->LockType = lockType;
1673 pSMB->OplockLevel = oplock_level;
1674 pSMB->AndXCommand = 0xFF; /* none */
1675 pSMB->Fid = smb_file_id; /* netfid stays le */
1677 if ((numLock != 0) || (numUnlock != 0)) {
1678 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1679 /* BB where to store pid high? */
1680 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1681 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1682 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1683 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1684 count = sizeof(LOCKING_ANDX_RANGE);
1685 } else {
1686 /* oplock break */
1687 count = 0;
1689 pSMB->hdr.smb_buf_length += count;
1690 pSMB->ByteCount = cpu_to_le16(count);
1692 if (waitFlag) {
1693 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1694 (struct smb_hdr *) pSMB, &bytes_returned);
1695 cifs_small_buf_release(pSMB);
1696 } else {
1697 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1698 timeout);
1699 /* SMB buffer freed by function above */
1701 cifs_stats_inc(&tcon->num_locks);
1702 if (rc)
1703 cFYI(1, ("Send error in Lock = %d", rc));
1705 /* Note: On -EAGAIN error only caller can retry on handle based calls
1706 since file handle passed in no longer valid */
1707 return rc;
1711 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1712 const __u16 smb_file_id, const int get_flag, const __u64 len,
1713 struct file_lock *pLockData, const __u16 lock_type,
1714 const bool waitFlag)
1716 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1717 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1718 struct cifs_posix_lock *parm_data;
1719 int rc = 0;
1720 int timeout = 0;
1721 int bytes_returned = 0;
1722 int resp_buf_type = 0;
1723 __u16 params, param_offset, offset, byte_count, count;
1724 struct kvec iov[1];
1726 cFYI(1, ("Posix Lock"));
1728 if (pLockData == NULL)
1729 return -EINVAL;
1731 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1733 if (rc)
1734 return rc;
1736 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1738 params = 6;
1739 pSMB->MaxSetupCount = 0;
1740 pSMB->Reserved = 0;
1741 pSMB->Flags = 0;
1742 pSMB->Reserved2 = 0;
1743 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1744 offset = param_offset + params;
1746 count = sizeof(struct cifs_posix_lock);
1747 pSMB->MaxParameterCount = cpu_to_le16(2);
1748 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1749 pSMB->SetupCount = 1;
1750 pSMB->Reserved3 = 0;
1751 if (get_flag)
1752 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1753 else
1754 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1755 byte_count = 3 /* pad */ + params + count;
1756 pSMB->DataCount = cpu_to_le16(count);
1757 pSMB->ParameterCount = cpu_to_le16(params);
1758 pSMB->TotalDataCount = pSMB->DataCount;
1759 pSMB->TotalParameterCount = pSMB->ParameterCount;
1760 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1761 parm_data = (struct cifs_posix_lock *)
1762 (((char *) &pSMB->hdr.Protocol) + offset);
1764 parm_data->lock_type = cpu_to_le16(lock_type);
1765 if (waitFlag) {
1766 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1767 parm_data->lock_flags = cpu_to_le16(1);
1768 pSMB->Timeout = cpu_to_le32(-1);
1769 } else
1770 pSMB->Timeout = 0;
1772 parm_data->pid = cpu_to_le32(current->tgid);
1773 parm_data->start = cpu_to_le64(pLockData->fl_start);
1774 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1776 pSMB->DataOffset = cpu_to_le16(offset);
1777 pSMB->Fid = smb_file_id;
1778 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1779 pSMB->Reserved4 = 0;
1780 pSMB->hdr.smb_buf_length += byte_count;
1781 pSMB->ByteCount = cpu_to_le16(byte_count);
1782 if (waitFlag) {
1783 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1784 (struct smb_hdr *) pSMBr, &bytes_returned);
1785 } else {
1786 iov[0].iov_base = (char *)pSMB;
1787 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1788 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1789 &resp_buf_type, timeout);
1790 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1791 not try to free it twice below on exit */
1792 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1795 if (rc) {
1796 cFYI(1, ("Send error in Posix Lock = %d", rc));
1797 } else if (get_flag) {
1798 /* lock structure can be returned on get */
1799 __u16 data_offset;
1800 __u16 data_count;
1801 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1803 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1804 rc = -EIO; /* bad smb */
1805 goto plk_err_exit;
1807 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1808 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1809 if (data_count < sizeof(struct cifs_posix_lock)) {
1810 rc = -EIO;
1811 goto plk_err_exit;
1813 parm_data = (struct cifs_posix_lock *)
1814 ((char *)&pSMBr->hdr.Protocol + data_offset);
1815 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1816 pLockData->fl_type = F_UNLCK;
1819 plk_err_exit:
1820 if (pSMB)
1821 cifs_small_buf_release(pSMB);
1823 if (resp_buf_type == CIFS_SMALL_BUFFER)
1824 cifs_small_buf_release(iov[0].iov_base);
1825 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1826 cifs_buf_release(iov[0].iov_base);
1828 /* Note: On -EAGAIN error only caller can retry on handle based calls
1829 since file handle passed in no longer valid */
1831 return rc;
1836 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1838 int rc = 0;
1839 CLOSE_REQ *pSMB = NULL;
1840 cFYI(1, ("In CIFSSMBClose"));
1842 /* do not retry on dead session on close */
1843 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1844 if (rc == -EAGAIN)
1845 return 0;
1846 if (rc)
1847 return rc;
1849 pSMB->FileID = (__u16) smb_file_id;
1850 pSMB->LastWriteTime = 0xFFFFFFFF;
1851 pSMB->ByteCount = 0;
1852 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1853 cifs_stats_inc(&tcon->num_closes);
1854 if (rc) {
1855 if (rc != -EINTR) {
1856 /* EINTR is expected when user ctl-c to kill app */
1857 cERROR(1, ("Send error in Close = %d", rc));
1861 /* Since session is dead, file will be closed on server already */
1862 if (rc == -EAGAIN)
1863 rc = 0;
1865 return rc;
1869 CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1871 int rc = 0;
1872 FLUSH_REQ *pSMB = NULL;
1873 cFYI(1, ("In CIFSSMBFlush"));
1875 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1876 if (rc)
1877 return rc;
1879 pSMB->FileID = (__u16) smb_file_id;
1880 pSMB->ByteCount = 0;
1881 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1882 cifs_stats_inc(&tcon->num_flushes);
1883 if (rc)
1884 cERROR(1, ("Send error in Flush = %d", rc));
1886 return rc;
1890 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1891 const char *fromName, const char *toName,
1892 const struct nls_table *nls_codepage, int remap)
1894 int rc = 0;
1895 RENAME_REQ *pSMB = NULL;
1896 RENAME_RSP *pSMBr = NULL;
1897 int bytes_returned;
1898 int name_len, name_len2;
1899 __u16 count;
1901 cFYI(1, ("In CIFSSMBRename"));
1902 renameRetry:
1903 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1904 (void **) &pSMBr);
1905 if (rc)
1906 return rc;
1908 pSMB->BufferFormat = 0x04;
1909 pSMB->SearchAttributes =
1910 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1911 ATTR_DIRECTORY);
1913 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1914 name_len =
1915 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1916 PATH_MAX, nls_codepage, remap);
1917 name_len++; /* trailing null */
1918 name_len *= 2;
1919 pSMB->OldFileName[name_len] = 0x04; /* pad */
1920 /* protocol requires ASCII signature byte on Unicode string */
1921 pSMB->OldFileName[name_len + 1] = 0x00;
1922 name_len2 =
1923 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1924 toName, PATH_MAX, nls_codepage, remap);
1925 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1926 name_len2 *= 2; /* convert to bytes */
1927 } else { /* BB improve the check for buffer overruns BB */
1928 name_len = strnlen(fromName, PATH_MAX);
1929 name_len++; /* trailing null */
1930 strncpy(pSMB->OldFileName, fromName, name_len);
1931 name_len2 = strnlen(toName, PATH_MAX);
1932 name_len2++; /* trailing null */
1933 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1934 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1935 name_len2++; /* trailing null */
1936 name_len2++; /* signature byte */
1939 count = 1 /* 1st signature byte */ + name_len + name_len2;
1940 pSMB->hdr.smb_buf_length += count;
1941 pSMB->ByteCount = cpu_to_le16(count);
1943 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1944 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1945 cifs_stats_inc(&tcon->num_renames);
1946 if (rc)
1947 cFYI(1, ("Send error in rename = %d", rc));
1949 cifs_buf_release(pSMB);
1951 if (rc == -EAGAIN)
1952 goto renameRetry;
1954 return rc;
1957 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1958 int netfid, const char *target_name,
1959 const struct nls_table *nls_codepage, int remap)
1961 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1962 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1963 struct set_file_rename *rename_info;
1964 char *data_offset;
1965 char dummy_string[30];
1966 int rc = 0;
1967 int bytes_returned = 0;
1968 int len_of_str;
1969 __u16 params, param_offset, offset, count, byte_count;
1971 cFYI(1, ("Rename to File by handle"));
1972 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1973 (void **) &pSMBr);
1974 if (rc)
1975 return rc;
1977 params = 6;
1978 pSMB->MaxSetupCount = 0;
1979 pSMB->Reserved = 0;
1980 pSMB->Flags = 0;
1981 pSMB->Timeout = 0;
1982 pSMB->Reserved2 = 0;
1983 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1984 offset = param_offset + params;
1986 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1987 rename_info = (struct set_file_rename *) data_offset;
1988 pSMB->MaxParameterCount = cpu_to_le16(2);
1989 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1990 pSMB->SetupCount = 1;
1991 pSMB->Reserved3 = 0;
1992 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1993 byte_count = 3 /* pad */ + params;
1994 pSMB->ParameterCount = cpu_to_le16(params);
1995 pSMB->TotalParameterCount = pSMB->ParameterCount;
1996 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1997 pSMB->DataOffset = cpu_to_le16(offset);
1998 /* construct random name ".cifs_tmp<inodenum><mid>" */
1999 rename_info->overwrite = cpu_to_le32(1);
2000 rename_info->root_fid = 0;
2001 /* unicode only call */
2002 if (target_name == NULL) {
2003 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2004 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2005 dummy_string, 24, nls_codepage, remap);
2006 } else {
2007 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2008 target_name, PATH_MAX, nls_codepage,
2009 remap);
2011 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2012 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2013 byte_count += count;
2014 pSMB->DataCount = cpu_to_le16(count);
2015 pSMB->TotalDataCount = pSMB->DataCount;
2016 pSMB->Fid = netfid;
2017 pSMB->InformationLevel =
2018 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2019 pSMB->Reserved4 = 0;
2020 pSMB->hdr.smb_buf_length += byte_count;
2021 pSMB->ByteCount = cpu_to_le16(byte_count);
2022 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2023 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2024 cifs_stats_inc(&pTcon->num_t2renames);
2025 if (rc)
2026 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2028 cifs_buf_release(pSMB);
2030 /* Note: On -EAGAIN error only caller can retry on handle based calls
2031 since file handle passed in no longer valid */
2033 return rc;
2037 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2038 const __u16 target_tid, const char *toName, const int flags,
2039 const struct nls_table *nls_codepage, int remap)
2041 int rc = 0;
2042 COPY_REQ *pSMB = NULL;
2043 COPY_RSP *pSMBr = NULL;
2044 int bytes_returned;
2045 int name_len, name_len2;
2046 __u16 count;
2048 cFYI(1, ("In CIFSSMBCopy"));
2049 copyRetry:
2050 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2051 (void **) &pSMBr);
2052 if (rc)
2053 return rc;
2055 pSMB->BufferFormat = 0x04;
2056 pSMB->Tid2 = target_tid;
2058 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2060 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2061 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2062 fromName, PATH_MAX, nls_codepage,
2063 remap);
2064 name_len++; /* trailing null */
2065 name_len *= 2;
2066 pSMB->OldFileName[name_len] = 0x04; /* pad */
2067 /* protocol requires ASCII signature byte on Unicode string */
2068 pSMB->OldFileName[name_len + 1] = 0x00;
2069 name_len2 =
2070 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2071 toName, PATH_MAX, nls_codepage, remap);
2072 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2073 name_len2 *= 2; /* convert to bytes */
2074 } else { /* BB improve the check for buffer overruns BB */
2075 name_len = strnlen(fromName, PATH_MAX);
2076 name_len++; /* trailing null */
2077 strncpy(pSMB->OldFileName, fromName, name_len);
2078 name_len2 = strnlen(toName, PATH_MAX);
2079 name_len2++; /* trailing null */
2080 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2081 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2082 name_len2++; /* trailing null */
2083 name_len2++; /* signature byte */
2086 count = 1 /* 1st signature byte */ + name_len + name_len2;
2087 pSMB->hdr.smb_buf_length += count;
2088 pSMB->ByteCount = cpu_to_le16(count);
2090 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2092 if (rc) {
2093 cFYI(1, ("Send error in copy = %d with %d files copied",
2094 rc, le16_to_cpu(pSMBr->CopyCount)));
2096 cifs_buf_release(pSMB);
2098 if (rc == -EAGAIN)
2099 goto copyRetry;
2101 return rc;
2105 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2106 const char *fromName, const char *toName,
2107 const struct nls_table *nls_codepage)
2109 TRANSACTION2_SPI_REQ *pSMB = NULL;
2110 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2111 char *data_offset;
2112 int name_len;
2113 int name_len_target;
2114 int rc = 0;
2115 int bytes_returned = 0;
2116 __u16 params, param_offset, offset, byte_count;
2118 cFYI(1, ("In Symlink Unix style"));
2119 createSymLinkRetry:
2120 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2121 (void **) &pSMBr);
2122 if (rc)
2123 return rc;
2125 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2126 name_len =
2127 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2128 /* find define for this maxpathcomponent */
2129 , nls_codepage);
2130 name_len++; /* trailing null */
2131 name_len *= 2;
2133 } else { /* BB improve the check for buffer overruns BB */
2134 name_len = strnlen(fromName, PATH_MAX);
2135 name_len++; /* trailing null */
2136 strncpy(pSMB->FileName, fromName, name_len);
2138 params = 6 + name_len;
2139 pSMB->MaxSetupCount = 0;
2140 pSMB->Reserved = 0;
2141 pSMB->Flags = 0;
2142 pSMB->Timeout = 0;
2143 pSMB->Reserved2 = 0;
2144 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2145 InformationLevel) - 4;
2146 offset = param_offset + params;
2148 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2149 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2150 name_len_target =
2151 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2152 /* find define for this maxpathcomponent */
2153 , nls_codepage);
2154 name_len_target++; /* trailing null */
2155 name_len_target *= 2;
2156 } else { /* BB improve the check for buffer overruns BB */
2157 name_len_target = strnlen(toName, PATH_MAX);
2158 name_len_target++; /* trailing null */
2159 strncpy(data_offset, toName, name_len_target);
2162 pSMB->MaxParameterCount = cpu_to_le16(2);
2163 /* BB find exact max on data count below from sess */
2164 pSMB->MaxDataCount = cpu_to_le16(1000);
2165 pSMB->SetupCount = 1;
2166 pSMB->Reserved3 = 0;
2167 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2168 byte_count = 3 /* pad */ + params + name_len_target;
2169 pSMB->DataCount = cpu_to_le16(name_len_target);
2170 pSMB->ParameterCount = cpu_to_le16(params);
2171 pSMB->TotalDataCount = pSMB->DataCount;
2172 pSMB->TotalParameterCount = pSMB->ParameterCount;
2173 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2174 pSMB->DataOffset = cpu_to_le16(offset);
2175 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2176 pSMB->Reserved4 = 0;
2177 pSMB->hdr.smb_buf_length += byte_count;
2178 pSMB->ByteCount = cpu_to_le16(byte_count);
2179 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2180 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2181 cifs_stats_inc(&tcon->num_symlinks);
2182 if (rc)
2183 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2185 cifs_buf_release(pSMB);
2187 if (rc == -EAGAIN)
2188 goto createSymLinkRetry;
2190 return rc;
2194 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2195 const char *fromName, const char *toName,
2196 const struct nls_table *nls_codepage, int remap)
2198 TRANSACTION2_SPI_REQ *pSMB = NULL;
2199 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2200 char *data_offset;
2201 int name_len;
2202 int name_len_target;
2203 int rc = 0;
2204 int bytes_returned = 0;
2205 __u16 params, param_offset, offset, byte_count;
2207 cFYI(1, ("In Create Hard link Unix style"));
2208 createHardLinkRetry:
2209 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2210 (void **) &pSMBr);
2211 if (rc)
2212 return rc;
2214 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2215 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2216 PATH_MAX, nls_codepage, remap);
2217 name_len++; /* trailing null */
2218 name_len *= 2;
2220 } else { /* BB improve the check for buffer overruns BB */
2221 name_len = strnlen(toName, PATH_MAX);
2222 name_len++; /* trailing null */
2223 strncpy(pSMB->FileName, toName, name_len);
2225 params = 6 + name_len;
2226 pSMB->MaxSetupCount = 0;
2227 pSMB->Reserved = 0;
2228 pSMB->Flags = 0;
2229 pSMB->Timeout = 0;
2230 pSMB->Reserved2 = 0;
2231 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2232 InformationLevel) - 4;
2233 offset = param_offset + params;
2235 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2236 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2237 name_len_target =
2238 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2239 nls_codepage, remap);
2240 name_len_target++; /* trailing null */
2241 name_len_target *= 2;
2242 } else { /* BB improve the check for buffer overruns BB */
2243 name_len_target = strnlen(fromName, PATH_MAX);
2244 name_len_target++; /* trailing null */
2245 strncpy(data_offset, fromName, name_len_target);
2248 pSMB->MaxParameterCount = cpu_to_le16(2);
2249 /* BB find exact max on data count below from sess*/
2250 pSMB->MaxDataCount = cpu_to_le16(1000);
2251 pSMB->SetupCount = 1;
2252 pSMB->Reserved3 = 0;
2253 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2254 byte_count = 3 /* pad */ + params + name_len_target;
2255 pSMB->ParameterCount = cpu_to_le16(params);
2256 pSMB->TotalParameterCount = pSMB->ParameterCount;
2257 pSMB->DataCount = cpu_to_le16(name_len_target);
2258 pSMB->TotalDataCount = pSMB->DataCount;
2259 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2260 pSMB->DataOffset = cpu_to_le16(offset);
2261 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2262 pSMB->Reserved4 = 0;
2263 pSMB->hdr.smb_buf_length += byte_count;
2264 pSMB->ByteCount = cpu_to_le16(byte_count);
2265 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2266 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2267 cifs_stats_inc(&tcon->num_hardlinks);
2268 if (rc)
2269 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2271 cifs_buf_release(pSMB);
2272 if (rc == -EAGAIN)
2273 goto createHardLinkRetry;
2275 return rc;
2279 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2280 const char *fromName, const char *toName,
2281 const struct nls_table *nls_codepage, int remap)
2283 int rc = 0;
2284 NT_RENAME_REQ *pSMB = NULL;
2285 RENAME_RSP *pSMBr = NULL;
2286 int bytes_returned;
2287 int name_len, name_len2;
2288 __u16 count;
2290 cFYI(1, ("In CIFSCreateHardLink"));
2291 winCreateHardLinkRetry:
2293 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2294 (void **) &pSMBr);
2295 if (rc)
2296 return rc;
2298 pSMB->SearchAttributes =
2299 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2300 ATTR_DIRECTORY);
2301 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2302 pSMB->ClusterCount = 0;
2304 pSMB->BufferFormat = 0x04;
2306 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2307 name_len =
2308 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2309 PATH_MAX, nls_codepage, remap);
2310 name_len++; /* trailing null */
2311 name_len *= 2;
2313 /* protocol specifies ASCII buffer format (0x04) for unicode */
2314 pSMB->OldFileName[name_len] = 0x04;
2315 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2316 name_len2 =
2317 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2318 toName, PATH_MAX, nls_codepage, remap);
2319 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2320 name_len2 *= 2; /* convert to bytes */
2321 } else { /* BB improve the check for buffer overruns BB */
2322 name_len = strnlen(fromName, PATH_MAX);
2323 name_len++; /* trailing null */
2324 strncpy(pSMB->OldFileName, fromName, name_len);
2325 name_len2 = strnlen(toName, PATH_MAX);
2326 name_len2++; /* trailing null */
2327 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2328 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2329 name_len2++; /* trailing null */
2330 name_len2++; /* signature byte */
2333 count = 1 /* string type byte */ + name_len + name_len2;
2334 pSMB->hdr.smb_buf_length += count;
2335 pSMB->ByteCount = cpu_to_le16(count);
2337 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2338 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2339 cifs_stats_inc(&tcon->num_hardlinks);
2340 if (rc)
2341 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2343 cifs_buf_release(pSMB);
2344 if (rc == -EAGAIN)
2345 goto winCreateHardLinkRetry;
2347 return rc;
2351 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2352 const unsigned char *searchName, char **symlinkinfo,
2353 const struct nls_table *nls_codepage)
2355 /* SMB_QUERY_FILE_UNIX_LINK */
2356 TRANSACTION2_QPI_REQ *pSMB = NULL;
2357 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2358 int rc = 0;
2359 int bytes_returned;
2360 int name_len;
2361 __u16 params, byte_count;
2362 char *data_start;
2364 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2366 querySymLinkRetry:
2367 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2368 (void **) &pSMBr);
2369 if (rc)
2370 return rc;
2372 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2373 name_len =
2374 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2375 PATH_MAX, nls_codepage);
2376 name_len++; /* trailing null */
2377 name_len *= 2;
2378 } else { /* BB improve the check for buffer overruns BB */
2379 name_len = strnlen(searchName, PATH_MAX);
2380 name_len++; /* trailing null */
2381 strncpy(pSMB->FileName, searchName, name_len);
2384 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2385 pSMB->TotalDataCount = 0;
2386 pSMB->MaxParameterCount = cpu_to_le16(2);
2387 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
2388 pSMB->MaxSetupCount = 0;
2389 pSMB->Reserved = 0;
2390 pSMB->Flags = 0;
2391 pSMB->Timeout = 0;
2392 pSMB->Reserved2 = 0;
2393 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2394 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2395 pSMB->DataCount = 0;
2396 pSMB->DataOffset = 0;
2397 pSMB->SetupCount = 1;
2398 pSMB->Reserved3 = 0;
2399 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2400 byte_count = params + 1 /* pad */ ;
2401 pSMB->TotalParameterCount = cpu_to_le16(params);
2402 pSMB->ParameterCount = pSMB->TotalParameterCount;
2403 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2404 pSMB->Reserved4 = 0;
2405 pSMB->hdr.smb_buf_length += byte_count;
2406 pSMB->ByteCount = cpu_to_le16(byte_count);
2408 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2409 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2410 if (rc) {
2411 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2412 } else {
2413 /* decode response */
2415 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2416 /* BB also check enough total bytes returned */
2417 if (rc || (pSMBr->ByteCount < 2))
2418 rc = -EIO;
2419 else {
2420 bool is_unicode;
2421 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2423 data_start = ((char *) &pSMBr->hdr.Protocol) +
2424 le16_to_cpu(pSMBr->t2.DataOffset);
2426 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2427 is_unicode = true;
2428 else
2429 is_unicode = false;
2431 /* BB FIXME investigate remapping reserved chars here */
2432 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
2433 is_unicode, nls_codepage);
2434 if (!*symlinkinfo)
2435 rc = -ENOMEM;
2438 cifs_buf_release(pSMB);
2439 if (rc == -EAGAIN)
2440 goto querySymLinkRetry;
2441 return rc;
2444 #ifdef CONFIG_CIFS_EXPERIMENTAL
2445 /* Initialize NT TRANSACT SMB into small smb request buffer.
2446 This assumes that all NT TRANSACTS that we init here have
2447 total parm and data under about 400 bytes (to fit in small cifs
2448 buffer size), which is the case so far, it easily fits. NB:
2449 Setup words themselves and ByteCount
2450 MaxSetupCount (size of returned setup area) and
2451 MaxParameterCount (returned parms size) must be set by caller */
2452 static int
2453 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2454 const int parm_len, struct cifsTconInfo *tcon,
2455 void **ret_buf)
2457 int rc;
2458 __u32 temp_offset;
2459 struct smb_com_ntransact_req *pSMB;
2461 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2462 (void **)&pSMB);
2463 if (rc)
2464 return rc;
2465 *ret_buf = (void *)pSMB;
2466 pSMB->Reserved = 0;
2467 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2468 pSMB->TotalDataCount = 0;
2469 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2470 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2471 pSMB->ParameterCount = pSMB->TotalParameterCount;
2472 pSMB->DataCount = pSMB->TotalDataCount;
2473 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2474 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2475 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2476 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2477 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2478 pSMB->SubCommand = cpu_to_le16(sub_command);
2479 return 0;
2482 static int
2483 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2484 __u32 *pparmlen, __u32 *pdatalen)
2486 char *end_of_smb;
2487 __u32 data_count, data_offset, parm_count, parm_offset;
2488 struct smb_com_ntransact_rsp *pSMBr;
2490 *pdatalen = 0;
2491 *pparmlen = 0;
2493 if (buf == NULL)
2494 return -EINVAL;
2496 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2498 /* ByteCount was converted from little endian in SendReceive */
2499 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2500 (char *)&pSMBr->ByteCount;
2502 data_offset = le32_to_cpu(pSMBr->DataOffset);
2503 data_count = le32_to_cpu(pSMBr->DataCount);
2504 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2505 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2507 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2508 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2510 /* should we also check that parm and data areas do not overlap? */
2511 if (*ppparm > end_of_smb) {
2512 cFYI(1, ("parms start after end of smb"));
2513 return -EINVAL;
2514 } else if (parm_count + *ppparm > end_of_smb) {
2515 cFYI(1, ("parm end after end of smb"));
2516 return -EINVAL;
2517 } else if (*ppdata > end_of_smb) {
2518 cFYI(1, ("data starts after end of smb"));
2519 return -EINVAL;
2520 } else if (data_count + *ppdata > end_of_smb) {
2521 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2522 *ppdata, data_count, (data_count + *ppdata),
2523 end_of_smb, pSMBr));
2524 return -EINVAL;
2525 } else if (parm_count + data_count > pSMBr->ByteCount) {
2526 cFYI(1, ("parm count and data count larger than SMB"));
2527 return -EINVAL;
2529 *pdatalen = data_count;
2530 *pparmlen = parm_count;
2531 return 0;
2535 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2536 const unsigned char *searchName,
2537 char *symlinkinfo, const int buflen, __u16 fid,
2538 const struct nls_table *nls_codepage)
2540 int rc = 0;
2541 int bytes_returned;
2542 struct smb_com_transaction_ioctl_req *pSMB;
2543 struct smb_com_transaction_ioctl_rsp *pSMBr;
2545 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2546 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2547 (void **) &pSMBr);
2548 if (rc)
2549 return rc;
2551 pSMB->TotalParameterCount = 0 ;
2552 pSMB->TotalDataCount = 0;
2553 pSMB->MaxParameterCount = cpu_to_le32(2);
2554 /* BB find exact data count max from sess structure BB */
2555 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2556 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2557 pSMB->MaxSetupCount = 4;
2558 pSMB->Reserved = 0;
2559 pSMB->ParameterOffset = 0;
2560 pSMB->DataCount = 0;
2561 pSMB->DataOffset = 0;
2562 pSMB->SetupCount = 4;
2563 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2564 pSMB->ParameterCount = pSMB->TotalParameterCount;
2565 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2566 pSMB->IsFsctl = 1; /* FSCTL */
2567 pSMB->IsRootFlag = 0;
2568 pSMB->Fid = fid; /* file handle always le */
2569 pSMB->ByteCount = 0;
2571 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2572 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2573 if (rc) {
2574 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2575 } else { /* decode response */
2576 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2577 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2578 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
2579 /* BB also check enough total bytes returned */
2580 rc = -EIO; /* bad smb */
2581 goto qreparse_out;
2583 if (data_count && (data_count < 2048)) {
2584 char *end_of_smb = 2 /* sizeof byte count */ +
2585 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
2587 struct reparse_data *reparse_buf =
2588 (struct reparse_data *)
2589 ((char *)&pSMBr->hdr.Protocol
2590 + data_offset);
2591 if ((char *)reparse_buf >= end_of_smb) {
2592 rc = -EIO;
2593 goto qreparse_out;
2595 if ((reparse_buf->LinkNamesBuf +
2596 reparse_buf->TargetNameOffset +
2597 reparse_buf->TargetNameLen) > end_of_smb) {
2598 cFYI(1, ("reparse buf beyond SMB"));
2599 rc = -EIO;
2600 goto qreparse_out;
2603 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2604 cifs_from_ucs2(symlinkinfo, (__le16 *)
2605 (reparse_buf->LinkNamesBuf +
2606 reparse_buf->TargetNameOffset),
2607 buflen,
2608 reparse_buf->TargetNameLen,
2609 nls_codepage, 0);
2610 } else { /* ASCII names */
2611 strncpy(symlinkinfo,
2612 reparse_buf->LinkNamesBuf +
2613 reparse_buf->TargetNameOffset,
2614 min_t(const int, buflen,
2615 reparse_buf->TargetNameLen));
2617 } else {
2618 rc = -EIO;
2619 cFYI(1, ("Invalid return data count on "
2620 "get reparse info ioctl"));
2622 symlinkinfo[buflen] = 0; /* just in case so the caller
2623 does not go off the end of the buffer */
2624 cFYI(1, ("readlink result - %s", symlinkinfo));
2627 qreparse_out:
2628 cifs_buf_release(pSMB);
2630 /* Note: On -EAGAIN error only caller can retry on handle based calls
2631 since file handle passed in no longer valid */
2633 return rc;
2635 #endif /* CIFS_EXPERIMENTAL */
2637 #ifdef CONFIG_CIFS_POSIX
2639 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2640 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2641 struct cifs_posix_ace *cifs_ace)
2643 /* u8 cifs fields do not need le conversion */
2644 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2645 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2646 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2647 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2649 return;
2652 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2653 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2654 const int acl_type, const int size_of_data_area)
2656 int size = 0;
2657 int i;
2658 __u16 count;
2659 struct cifs_posix_ace *pACE;
2660 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2661 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2663 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2664 return -EOPNOTSUPP;
2666 if (acl_type & ACL_TYPE_ACCESS) {
2667 count = le16_to_cpu(cifs_acl->access_entry_count);
2668 pACE = &cifs_acl->ace_array[0];
2669 size = sizeof(struct cifs_posix_acl);
2670 size += sizeof(struct cifs_posix_ace) * count;
2671 /* check if we would go beyond end of SMB */
2672 if (size_of_data_area < size) {
2673 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2674 size_of_data_area, size));
2675 return -EINVAL;
2677 } else if (acl_type & ACL_TYPE_DEFAULT) {
2678 count = le16_to_cpu(cifs_acl->access_entry_count);
2679 size = sizeof(struct cifs_posix_acl);
2680 size += sizeof(struct cifs_posix_ace) * count;
2681 /* skip past access ACEs to get to default ACEs */
2682 pACE = &cifs_acl->ace_array[count];
2683 count = le16_to_cpu(cifs_acl->default_entry_count);
2684 size += sizeof(struct cifs_posix_ace) * count;
2685 /* check if we would go beyond end of SMB */
2686 if (size_of_data_area < size)
2687 return -EINVAL;
2688 } else {
2689 /* illegal type */
2690 return -EINVAL;
2693 size = posix_acl_xattr_size(count);
2694 if ((buflen == 0) || (local_acl == NULL)) {
2695 /* used to query ACL EA size */
2696 } else if (size > buflen) {
2697 return -ERANGE;
2698 } else /* buffer big enough */ {
2699 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2700 for (i = 0; i < count ; i++) {
2701 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2702 pACE++;
2705 return size;
2708 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2709 const posix_acl_xattr_entry *local_ace)
2711 __u16 rc = 0; /* 0 = ACL converted ok */
2713 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2714 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2715 /* BB is there a better way to handle the large uid? */
2716 if (local_ace->e_id == cpu_to_le32(-1)) {
2717 /* Probably no need to le convert -1 on any arch but can not hurt */
2718 cifs_ace->cifs_uid = cpu_to_le64(-1);
2719 } else
2720 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2721 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2722 return rc;
2725 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2726 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2727 const int buflen, const int acl_type)
2729 __u16 rc = 0;
2730 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2731 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2732 int count;
2733 int i;
2735 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2736 return 0;
2738 count = posix_acl_xattr_count((size_t)buflen);
2739 cFYI(1, ("setting acl with %d entries from buf of length %d and "
2740 "version of %d",
2741 count, buflen, le32_to_cpu(local_acl->a_version)));
2742 if (le32_to_cpu(local_acl->a_version) != 2) {
2743 cFYI(1, ("unknown POSIX ACL version %d",
2744 le32_to_cpu(local_acl->a_version)));
2745 return 0;
2747 cifs_acl->version = cpu_to_le16(1);
2748 if (acl_type == ACL_TYPE_ACCESS)
2749 cifs_acl->access_entry_count = cpu_to_le16(count);
2750 else if (acl_type == ACL_TYPE_DEFAULT)
2751 cifs_acl->default_entry_count = cpu_to_le16(count);
2752 else {
2753 cFYI(1, ("unknown ACL type %d", acl_type));
2754 return 0;
2756 for (i = 0; i < count; i++) {
2757 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2758 &local_acl->a_entries[i]);
2759 if (rc != 0) {
2760 /* ACE not converted */
2761 break;
2764 if (rc == 0) {
2765 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2766 rc += sizeof(struct cifs_posix_acl);
2767 /* BB add check to make sure ACL does not overflow SMB */
2769 return rc;
2773 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2774 const unsigned char *searchName,
2775 char *acl_inf, const int buflen, const int acl_type,
2776 const struct nls_table *nls_codepage, int remap)
2778 /* SMB_QUERY_POSIX_ACL */
2779 TRANSACTION2_QPI_REQ *pSMB = NULL;
2780 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2781 int rc = 0;
2782 int bytes_returned;
2783 int name_len;
2784 __u16 params, byte_count;
2786 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2788 queryAclRetry:
2789 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2790 (void **) &pSMBr);
2791 if (rc)
2792 return rc;
2794 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2795 name_len =
2796 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2797 PATH_MAX, nls_codepage, remap);
2798 name_len++; /* trailing null */
2799 name_len *= 2;
2800 pSMB->FileName[name_len] = 0;
2801 pSMB->FileName[name_len+1] = 0;
2802 } else { /* BB improve the check for buffer overruns BB */
2803 name_len = strnlen(searchName, PATH_MAX);
2804 name_len++; /* trailing null */
2805 strncpy(pSMB->FileName, searchName, name_len);
2808 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2809 pSMB->TotalDataCount = 0;
2810 pSMB->MaxParameterCount = cpu_to_le16(2);
2811 /* BB find exact max data count below from sess structure BB */
2812 pSMB->MaxDataCount = cpu_to_le16(4000);
2813 pSMB->MaxSetupCount = 0;
2814 pSMB->Reserved = 0;
2815 pSMB->Flags = 0;
2816 pSMB->Timeout = 0;
2817 pSMB->Reserved2 = 0;
2818 pSMB->ParameterOffset = cpu_to_le16(
2819 offsetof(struct smb_com_transaction2_qpi_req,
2820 InformationLevel) - 4);
2821 pSMB->DataCount = 0;
2822 pSMB->DataOffset = 0;
2823 pSMB->SetupCount = 1;
2824 pSMB->Reserved3 = 0;
2825 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2826 byte_count = params + 1 /* pad */ ;
2827 pSMB->TotalParameterCount = cpu_to_le16(params);
2828 pSMB->ParameterCount = pSMB->TotalParameterCount;
2829 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2830 pSMB->Reserved4 = 0;
2831 pSMB->hdr.smb_buf_length += byte_count;
2832 pSMB->ByteCount = cpu_to_le16(byte_count);
2834 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2835 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2836 cifs_stats_inc(&tcon->num_acl_get);
2837 if (rc) {
2838 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2839 } else {
2840 /* decode response */
2842 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2843 if (rc || (pSMBr->ByteCount < 2))
2844 /* BB also check enough total bytes returned */
2845 rc = -EIO; /* bad smb */
2846 else {
2847 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2848 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2849 rc = cifs_copy_posix_acl(acl_inf,
2850 (char *)&pSMBr->hdr.Protocol+data_offset,
2851 buflen, acl_type, count);
2854 cifs_buf_release(pSMB);
2855 if (rc == -EAGAIN)
2856 goto queryAclRetry;
2857 return rc;
2861 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2862 const unsigned char *fileName,
2863 const char *local_acl, const int buflen,
2864 const int acl_type,
2865 const struct nls_table *nls_codepage, int remap)
2867 struct smb_com_transaction2_spi_req *pSMB = NULL;
2868 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2869 char *parm_data;
2870 int name_len;
2871 int rc = 0;
2872 int bytes_returned = 0;
2873 __u16 params, byte_count, data_count, param_offset, offset;
2875 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2876 setAclRetry:
2877 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2878 (void **) &pSMBr);
2879 if (rc)
2880 return rc;
2881 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2882 name_len =
2883 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2884 PATH_MAX, nls_codepage, remap);
2885 name_len++; /* trailing null */
2886 name_len *= 2;
2887 } else { /* BB improve the check for buffer overruns BB */
2888 name_len = strnlen(fileName, PATH_MAX);
2889 name_len++; /* trailing null */
2890 strncpy(pSMB->FileName, fileName, name_len);
2892 params = 6 + name_len;
2893 pSMB->MaxParameterCount = cpu_to_le16(2);
2894 /* BB find max SMB size from sess */
2895 pSMB->MaxDataCount = cpu_to_le16(1000);
2896 pSMB->MaxSetupCount = 0;
2897 pSMB->Reserved = 0;
2898 pSMB->Flags = 0;
2899 pSMB->Timeout = 0;
2900 pSMB->Reserved2 = 0;
2901 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2902 InformationLevel) - 4;
2903 offset = param_offset + params;
2904 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2905 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2907 /* convert to on the wire format for POSIX ACL */
2908 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2910 if (data_count == 0) {
2911 rc = -EOPNOTSUPP;
2912 goto setACLerrorExit;
2914 pSMB->DataOffset = cpu_to_le16(offset);
2915 pSMB->SetupCount = 1;
2916 pSMB->Reserved3 = 0;
2917 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2918 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2919 byte_count = 3 /* pad */ + params + data_count;
2920 pSMB->DataCount = cpu_to_le16(data_count);
2921 pSMB->TotalDataCount = pSMB->DataCount;
2922 pSMB->ParameterCount = cpu_to_le16(params);
2923 pSMB->TotalParameterCount = pSMB->ParameterCount;
2924 pSMB->Reserved4 = 0;
2925 pSMB->hdr.smb_buf_length += byte_count;
2926 pSMB->ByteCount = cpu_to_le16(byte_count);
2927 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2928 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2929 if (rc)
2930 cFYI(1, ("Set POSIX ACL returned %d", rc));
2932 setACLerrorExit:
2933 cifs_buf_release(pSMB);
2934 if (rc == -EAGAIN)
2935 goto setAclRetry;
2936 return rc;
2939 /* BB fix tabs in this function FIXME BB */
2941 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2942 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2944 int rc = 0;
2945 struct smb_t2_qfi_req *pSMB = NULL;
2946 struct smb_t2_qfi_rsp *pSMBr = NULL;
2947 int bytes_returned;
2948 __u16 params, byte_count;
2950 cFYI(1, ("In GetExtAttr"));
2951 if (tcon == NULL)
2952 return -ENODEV;
2954 GetExtAttrRetry:
2955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2956 (void **) &pSMBr);
2957 if (rc)
2958 return rc;
2960 params = 2 /* level */ + 2 /* fid */;
2961 pSMB->t2.TotalDataCount = 0;
2962 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2963 /* BB find exact max data count below from sess structure BB */
2964 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2965 pSMB->t2.MaxSetupCount = 0;
2966 pSMB->t2.Reserved = 0;
2967 pSMB->t2.Flags = 0;
2968 pSMB->t2.Timeout = 0;
2969 pSMB->t2.Reserved2 = 0;
2970 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2971 Fid) - 4);
2972 pSMB->t2.DataCount = 0;
2973 pSMB->t2.DataOffset = 0;
2974 pSMB->t2.SetupCount = 1;
2975 pSMB->t2.Reserved3 = 0;
2976 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2977 byte_count = params + 1 /* pad */ ;
2978 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2979 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2980 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2981 pSMB->Pad = 0;
2982 pSMB->Fid = netfid;
2983 pSMB->hdr.smb_buf_length += byte_count;
2984 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2986 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2987 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2988 if (rc) {
2989 cFYI(1, ("error %d in GetExtAttr", rc));
2990 } else {
2991 /* decode response */
2992 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2993 if (rc || (pSMBr->ByteCount < 2))
2994 /* BB also check enough total bytes returned */
2995 /* If rc should we check for EOPNOSUPP and
2996 disable the srvino flag? or in caller? */
2997 rc = -EIO; /* bad smb */
2998 else {
2999 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3000 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3001 struct file_chattr_info *pfinfo;
3002 /* BB Do we need a cast or hash here ? */
3003 if (count != 16) {
3004 cFYI(1, ("Illegal size ret in GetExtAttr"));
3005 rc = -EIO;
3006 goto GetExtAttrOut;
3008 pfinfo = (struct file_chattr_info *)
3009 (data_offset + (char *) &pSMBr->hdr.Protocol);
3010 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3011 *pMask = le64_to_cpu(pfinfo->mask);
3014 GetExtAttrOut:
3015 cifs_buf_release(pSMB);
3016 if (rc == -EAGAIN)
3017 goto GetExtAttrRetry;
3018 return rc;
3021 #endif /* CONFIG_POSIX */
3023 #ifdef CONFIG_CIFS_EXPERIMENTAL
3024 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3026 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3027 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3029 int rc = 0;
3030 int buf_type = 0;
3031 QUERY_SEC_DESC_REQ *pSMB;
3032 struct kvec iov[1];
3034 cFYI(1, ("GetCifsACL"));
3036 *pbuflen = 0;
3037 *acl_inf = NULL;
3039 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3040 8 /* parm len */, tcon, (void **) &pSMB);
3041 if (rc)
3042 return rc;
3044 pSMB->MaxParameterCount = cpu_to_le32(4);
3045 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3046 pSMB->MaxSetupCount = 0;
3047 pSMB->Fid = fid; /* file handle always le */
3048 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3049 CIFS_ACL_DACL);
3050 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3051 pSMB->hdr.smb_buf_length += 11;
3052 iov[0].iov_base = (char *)pSMB;
3053 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3055 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3056 CIFS_STD_OP);
3057 cifs_stats_inc(&tcon->num_acl_get);
3058 if (rc) {
3059 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3060 } else { /* decode response */
3061 __le32 *parm;
3062 __u32 parm_len;
3063 __u32 acl_len;
3064 struct smb_com_ntransact_rsp *pSMBr;
3065 char *pdata;
3067 /* validate_nttransact */
3068 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3069 &pdata, &parm_len, pbuflen);
3070 if (rc)
3071 goto qsec_out;
3072 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3074 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3076 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3077 rc = -EIO; /* bad smb */
3078 *pbuflen = 0;
3079 goto qsec_out;
3082 /* BB check that data area is minimum length and as big as acl_len */
3084 acl_len = le32_to_cpu(*parm);
3085 if (acl_len != *pbuflen) {
3086 cERROR(1, ("acl length %d does not match %d",
3087 acl_len, *pbuflen));
3088 if (*pbuflen > acl_len)
3089 *pbuflen = acl_len;
3092 /* check if buffer is big enough for the acl
3093 header followed by the smallest SID */
3094 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3095 (*pbuflen >= 64 * 1024)) {
3096 cERROR(1, ("bad acl length %d", *pbuflen));
3097 rc = -EINVAL;
3098 *pbuflen = 0;
3099 } else {
3100 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3101 if (*acl_inf == NULL) {
3102 *pbuflen = 0;
3103 rc = -ENOMEM;
3105 memcpy(*acl_inf, pdata, *pbuflen);
3108 qsec_out:
3109 if (buf_type == CIFS_SMALL_BUFFER)
3110 cifs_small_buf_release(iov[0].iov_base);
3111 else if (buf_type == CIFS_LARGE_BUFFER)
3112 cifs_buf_release(iov[0].iov_base);
3113 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3114 return rc;
3118 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3119 struct cifs_ntsd *pntsd, __u32 acllen)
3121 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3122 int rc = 0;
3123 int bytes_returned = 0;
3124 SET_SEC_DESC_REQ *pSMB = NULL;
3125 NTRANSACT_RSP *pSMBr = NULL;
3127 setCifsAclRetry:
3128 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3129 (void **) &pSMBr);
3130 if (rc)
3131 return (rc);
3133 pSMB->MaxSetupCount = 0;
3134 pSMB->Reserved = 0;
3136 param_count = 8;
3137 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3138 data_count = acllen;
3139 data_offset = param_offset + param_count;
3140 byte_count = 3 /* pad */ + param_count;
3142 pSMB->DataCount = cpu_to_le32(data_count);
3143 pSMB->TotalDataCount = pSMB->DataCount;
3144 pSMB->MaxParameterCount = cpu_to_le32(4);
3145 pSMB->MaxDataCount = cpu_to_le32(16384);
3146 pSMB->ParameterCount = cpu_to_le32(param_count);
3147 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3148 pSMB->TotalParameterCount = pSMB->ParameterCount;
3149 pSMB->DataOffset = cpu_to_le32(data_offset);
3150 pSMB->SetupCount = 0;
3151 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3152 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3154 pSMB->Fid = fid; /* file handle always le */
3155 pSMB->Reserved2 = 0;
3156 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3158 if (pntsd && acllen) {
3159 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3160 (char *) pntsd,
3161 acllen);
3162 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3164 } else
3165 pSMB->hdr.smb_buf_length += byte_count;
3167 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3168 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3170 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3171 if (rc)
3172 cFYI(1, ("Set CIFS ACL returned %d", rc));
3173 cifs_buf_release(pSMB);
3175 if (rc == -EAGAIN)
3176 goto setCifsAclRetry;
3178 return (rc);
3181 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3183 /* Legacy Query Path Information call for lookup to old servers such
3184 as Win9x/WinME */
3185 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3186 const unsigned char *searchName,
3187 FILE_ALL_INFO *pFinfo,
3188 const struct nls_table *nls_codepage, int remap)
3190 QUERY_INFORMATION_REQ *pSMB;
3191 QUERY_INFORMATION_RSP *pSMBr;
3192 int rc = 0;
3193 int bytes_returned;
3194 int name_len;
3196 cFYI(1, ("In SMBQPath path %s", searchName));
3197 QInfRetry:
3198 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3199 (void **) &pSMBr);
3200 if (rc)
3201 return rc;
3203 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3204 name_len =
3205 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3206 PATH_MAX, nls_codepage, remap);
3207 name_len++; /* trailing null */
3208 name_len *= 2;
3209 } else {
3210 name_len = strnlen(searchName, PATH_MAX);
3211 name_len++; /* trailing null */
3212 strncpy(pSMB->FileName, searchName, name_len);
3214 pSMB->BufferFormat = 0x04;
3215 name_len++; /* account for buffer type byte */
3216 pSMB->hdr.smb_buf_length += (__u16) name_len;
3217 pSMB->ByteCount = cpu_to_le16(name_len);
3219 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3220 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3221 if (rc) {
3222 cFYI(1, ("Send error in QueryInfo = %d", rc));
3223 } else if (pFinfo) {
3224 struct timespec ts;
3225 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3227 /* decode response */
3228 /* BB FIXME - add time zone adjustment BB */
3229 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3230 ts.tv_nsec = 0;
3231 ts.tv_sec = time;
3232 /* decode time fields */
3233 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3234 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3235 pFinfo->LastAccessTime = 0;
3236 pFinfo->AllocationSize =
3237 cpu_to_le64(le32_to_cpu(pSMBr->size));
3238 pFinfo->EndOfFile = pFinfo->AllocationSize;
3239 pFinfo->Attributes =
3240 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3241 } else
3242 rc = -EIO; /* bad buffer passed in */
3244 cifs_buf_release(pSMB);
3246 if (rc == -EAGAIN)
3247 goto QInfRetry;
3249 return rc;
3256 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3257 const unsigned char *searchName,
3258 FILE_ALL_INFO *pFindData,
3259 int legacy /* old style infolevel */,
3260 const struct nls_table *nls_codepage, int remap)
3262 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3263 TRANSACTION2_QPI_REQ *pSMB = NULL;
3264 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3265 int rc = 0;
3266 int bytes_returned;
3267 int name_len;
3268 __u16 params, byte_count;
3270 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3271 QPathInfoRetry:
3272 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3273 (void **) &pSMBr);
3274 if (rc)
3275 return rc;
3277 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3278 name_len =
3279 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3280 PATH_MAX, nls_codepage, remap);
3281 name_len++; /* trailing null */
3282 name_len *= 2;
3283 } else { /* BB improve the check for buffer overruns BB */
3284 name_len = strnlen(searchName, PATH_MAX);
3285 name_len++; /* trailing null */
3286 strncpy(pSMB->FileName, searchName, name_len);
3289 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3290 pSMB->TotalDataCount = 0;
3291 pSMB->MaxParameterCount = cpu_to_le16(2);
3292 /* BB find exact max SMB PDU from sess structure BB */
3293 pSMB->MaxDataCount = cpu_to_le16(4000);
3294 pSMB->MaxSetupCount = 0;
3295 pSMB->Reserved = 0;
3296 pSMB->Flags = 0;
3297 pSMB->Timeout = 0;
3298 pSMB->Reserved2 = 0;
3299 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3300 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3301 pSMB->DataCount = 0;
3302 pSMB->DataOffset = 0;
3303 pSMB->SetupCount = 1;
3304 pSMB->Reserved3 = 0;
3305 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3306 byte_count = params + 1 /* pad */ ;
3307 pSMB->TotalParameterCount = cpu_to_le16(params);
3308 pSMB->ParameterCount = pSMB->TotalParameterCount;
3309 if (legacy)
3310 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3311 else
3312 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3313 pSMB->Reserved4 = 0;
3314 pSMB->hdr.smb_buf_length += byte_count;
3315 pSMB->ByteCount = cpu_to_le16(byte_count);
3317 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3318 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3319 if (rc) {
3320 cFYI(1, ("Send error in QPathInfo = %d", rc));
3321 } else { /* decode response */
3322 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3324 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3325 rc = -EIO;
3326 else if (!legacy && (pSMBr->ByteCount < 40))
3327 rc = -EIO; /* bad smb */
3328 else if (legacy && (pSMBr->ByteCount < 24))
3329 rc = -EIO; /* 24 or 26 expected but we do not read
3330 last field */
3331 else if (pFindData) {
3332 int size;
3333 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3335 /* On legacy responses we do not read the last field,
3336 EAsize, fortunately since it varies by subdialect and
3337 also note it differs on Set vs. Get, ie two bytes or 4
3338 bytes depending but we don't care here */
3339 if (legacy)
3340 size = sizeof(FILE_INFO_STANDARD);
3341 else
3342 size = sizeof(FILE_ALL_INFO);
3343 memcpy((char *) pFindData,
3344 (char *) &pSMBr->hdr.Protocol +
3345 data_offset, size);
3346 } else
3347 rc = -ENOMEM;
3349 cifs_buf_release(pSMB);
3350 if (rc == -EAGAIN)
3351 goto QPathInfoRetry;
3353 return rc;
3357 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3358 const unsigned char *searchName,
3359 FILE_UNIX_BASIC_INFO *pFindData,
3360 const struct nls_table *nls_codepage, int remap)
3362 /* SMB_QUERY_FILE_UNIX_BASIC */
3363 TRANSACTION2_QPI_REQ *pSMB = NULL;
3364 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3365 int rc = 0;
3366 int bytes_returned = 0;
3367 int name_len;
3368 __u16 params, byte_count;
3370 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3371 UnixQPathInfoRetry:
3372 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3373 (void **) &pSMBr);
3374 if (rc)
3375 return rc;
3377 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3378 name_len =
3379 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3380 PATH_MAX, nls_codepage, remap);
3381 name_len++; /* trailing null */
3382 name_len *= 2;
3383 } else { /* BB improve the check for buffer overruns BB */
3384 name_len = strnlen(searchName, PATH_MAX);
3385 name_len++; /* trailing null */
3386 strncpy(pSMB->FileName, searchName, name_len);
3389 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3390 pSMB->TotalDataCount = 0;
3391 pSMB->MaxParameterCount = cpu_to_le16(2);
3392 /* BB find exact max SMB PDU from sess structure BB */
3393 pSMB->MaxDataCount = cpu_to_le16(4000);
3394 pSMB->MaxSetupCount = 0;
3395 pSMB->Reserved = 0;
3396 pSMB->Flags = 0;
3397 pSMB->Timeout = 0;
3398 pSMB->Reserved2 = 0;
3399 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3400 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3401 pSMB->DataCount = 0;
3402 pSMB->DataOffset = 0;
3403 pSMB->SetupCount = 1;
3404 pSMB->Reserved3 = 0;
3405 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3406 byte_count = params + 1 /* pad */ ;
3407 pSMB->TotalParameterCount = cpu_to_le16(params);
3408 pSMB->ParameterCount = pSMB->TotalParameterCount;
3409 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3410 pSMB->Reserved4 = 0;
3411 pSMB->hdr.smb_buf_length += byte_count;
3412 pSMB->ByteCount = cpu_to_le16(byte_count);
3414 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3415 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3416 if (rc) {
3417 cFYI(1, ("Send error in QPathInfo = %d", rc));
3418 } else { /* decode response */
3419 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3421 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3422 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3423 "Unix Extensions can be disabled on mount "
3424 "by specifying the nosfu mount option."));
3425 rc = -EIO; /* bad smb */
3426 } else {
3427 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3428 memcpy((char *) pFindData,
3429 (char *) &pSMBr->hdr.Protocol +
3430 data_offset,
3431 sizeof(FILE_UNIX_BASIC_INFO));
3434 cifs_buf_release(pSMB);
3435 if (rc == -EAGAIN)
3436 goto UnixQPathInfoRetry;
3438 return rc;
3441 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3443 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3444 const char *searchName,
3445 const struct nls_table *nls_codepage,
3446 __u16 *pnetfid,
3447 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3449 /* level 257 SMB_ */
3450 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3451 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3452 T2_FFIRST_RSP_PARMS *parms;
3453 int rc = 0;
3454 int bytes_returned = 0;
3455 int name_len;
3456 __u16 params, byte_count;
3458 cFYI(1, ("In FindFirst for %s", searchName));
3460 findFirstRetry:
3461 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3462 (void **) &pSMBr);
3463 if (rc)
3464 return rc;
3466 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3467 name_len =
3468 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3469 PATH_MAX, nls_codepage, remap);
3470 /* We can not add the asterik earlier in case
3471 it got remapped to 0xF03A as if it were part of the
3472 directory name instead of a wildcard */
3473 name_len *= 2;
3474 pSMB->FileName[name_len] = dirsep;
3475 pSMB->FileName[name_len+1] = 0;
3476 pSMB->FileName[name_len+2] = '*';
3477 pSMB->FileName[name_len+3] = 0;
3478 name_len += 4; /* now the trailing null */
3479 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3480 pSMB->FileName[name_len+1] = 0;
3481 name_len += 2;
3482 } else { /* BB add check for overrun of SMB buf BB */
3483 name_len = strnlen(searchName, PATH_MAX);
3484 /* BB fix here and in unicode clause above ie
3485 if (name_len > buffersize-header)
3486 free buffer exit; BB */
3487 strncpy(pSMB->FileName, searchName, name_len);
3488 pSMB->FileName[name_len] = dirsep;
3489 pSMB->FileName[name_len+1] = '*';
3490 pSMB->FileName[name_len+2] = 0;
3491 name_len += 3;
3494 params = 12 + name_len /* includes null */ ;
3495 pSMB->TotalDataCount = 0; /* no EAs */
3496 pSMB->MaxParameterCount = cpu_to_le16(10);
3497 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3498 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3499 pSMB->MaxSetupCount = 0;
3500 pSMB->Reserved = 0;
3501 pSMB->Flags = 0;
3502 pSMB->Timeout = 0;
3503 pSMB->Reserved2 = 0;
3504 byte_count = params + 1 /* pad */ ;
3505 pSMB->TotalParameterCount = cpu_to_le16(params);
3506 pSMB->ParameterCount = pSMB->TotalParameterCount;
3507 pSMB->ParameterOffset = cpu_to_le16(
3508 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3509 - 4);
3510 pSMB->DataCount = 0;
3511 pSMB->DataOffset = 0;
3512 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3513 pSMB->Reserved3 = 0;
3514 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3515 pSMB->SearchAttributes =
3516 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3517 ATTR_DIRECTORY);
3518 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3519 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3520 CIFS_SEARCH_RETURN_RESUME);
3521 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3523 /* BB what should we set StorageType to? Does it matter? BB */
3524 pSMB->SearchStorageType = 0;
3525 pSMB->hdr.smb_buf_length += byte_count;
3526 pSMB->ByteCount = cpu_to_le16(byte_count);
3528 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3529 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3530 cifs_stats_inc(&tcon->num_ffirst);
3532 if (rc) {/* BB add logic to retry regular search if Unix search
3533 rejected unexpectedly by server */
3534 /* BB Add code to handle unsupported level rc */
3535 cFYI(1, ("Error in FindFirst = %d", rc));
3537 cifs_buf_release(pSMB);
3539 /* BB eventually could optimize out free and realloc of buf */
3540 /* for this case */
3541 if (rc == -EAGAIN)
3542 goto findFirstRetry;
3543 } else { /* decode response */
3544 /* BB remember to free buffer if error BB */
3545 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3546 if (rc == 0) {
3547 unsigned int lnoff;
3549 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3550 psrch_inf->unicode = true;
3551 else
3552 psrch_inf->unicode = false;
3554 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3555 psrch_inf->smallBuf = 0;
3556 psrch_inf->srch_entries_start =
3557 (char *) &pSMBr->hdr.Protocol +
3558 le16_to_cpu(pSMBr->t2.DataOffset);
3559 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3560 le16_to_cpu(pSMBr->t2.ParameterOffset));
3562 if (parms->EndofSearch)
3563 psrch_inf->endOfSearch = true;
3564 else
3565 psrch_inf->endOfSearch = false;
3567 psrch_inf->entries_in_buffer =
3568 le16_to_cpu(parms->SearchCount);
3569 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3570 psrch_inf->entries_in_buffer;
3571 lnoff = le16_to_cpu(parms->LastNameOffset);
3572 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3573 lnoff) {
3574 cERROR(1, ("ignoring corrupt resume name"));
3575 psrch_inf->last_entry = NULL;
3576 return rc;
3579 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3580 lnoff;
3582 *pnetfid = parms->SearchHandle;
3583 } else {
3584 cifs_buf_release(pSMB);
3588 return rc;
3591 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3592 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3594 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3595 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3596 T2_FNEXT_RSP_PARMS *parms;
3597 char *response_data;
3598 int rc = 0;
3599 int bytes_returned, name_len;
3600 __u16 params, byte_count;
3602 cFYI(1, ("In FindNext"));
3604 if (psrch_inf->endOfSearch)
3605 return -ENOENT;
3607 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3608 (void **) &pSMBr);
3609 if (rc)
3610 return rc;
3612 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3613 byte_count = 0;
3614 pSMB->TotalDataCount = 0; /* no EAs */
3615 pSMB->MaxParameterCount = cpu_to_le16(8);
3616 pSMB->MaxDataCount =
3617 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3618 0xFFFFFF00);
3619 pSMB->MaxSetupCount = 0;
3620 pSMB->Reserved = 0;
3621 pSMB->Flags = 0;
3622 pSMB->Timeout = 0;
3623 pSMB->Reserved2 = 0;
3624 pSMB->ParameterOffset = cpu_to_le16(
3625 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3626 pSMB->DataCount = 0;
3627 pSMB->DataOffset = 0;
3628 pSMB->SetupCount = 1;
3629 pSMB->Reserved3 = 0;
3630 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3631 pSMB->SearchHandle = searchHandle; /* always kept as le */
3632 pSMB->SearchCount =
3633 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3634 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3635 pSMB->ResumeKey = psrch_inf->resume_key;
3636 pSMB->SearchFlags =
3637 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3639 name_len = psrch_inf->resume_name_len;
3640 params += name_len;
3641 if (name_len < PATH_MAX) {
3642 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3643 byte_count += name_len;
3644 /* 14 byte parm len above enough for 2 byte null terminator */
3645 pSMB->ResumeFileName[name_len] = 0;
3646 pSMB->ResumeFileName[name_len+1] = 0;
3647 } else {
3648 rc = -EINVAL;
3649 goto FNext2_err_exit;
3651 byte_count = params + 1 /* pad */ ;
3652 pSMB->TotalParameterCount = cpu_to_le16(params);
3653 pSMB->ParameterCount = pSMB->TotalParameterCount;
3654 pSMB->hdr.smb_buf_length += byte_count;
3655 pSMB->ByteCount = cpu_to_le16(byte_count);
3657 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3658 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3659 cifs_stats_inc(&tcon->num_fnext);
3660 if (rc) {
3661 if (rc == -EBADF) {
3662 psrch_inf->endOfSearch = true;
3663 cifs_buf_release(pSMB);
3664 rc = 0; /* search probably was closed at end of search*/
3665 } else
3666 cFYI(1, ("FindNext returned = %d", rc));
3667 } else { /* decode response */
3668 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3670 if (rc == 0) {
3671 unsigned int lnoff;
3673 /* BB fixme add lock for file (srch_info) struct here */
3674 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3675 psrch_inf->unicode = true;
3676 else
3677 psrch_inf->unicode = false;
3678 response_data = (char *) &pSMBr->hdr.Protocol +
3679 le16_to_cpu(pSMBr->t2.ParameterOffset);
3680 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3681 response_data = (char *)&pSMBr->hdr.Protocol +
3682 le16_to_cpu(pSMBr->t2.DataOffset);
3683 if (psrch_inf->smallBuf)
3684 cifs_small_buf_release(
3685 psrch_inf->ntwrk_buf_start);
3686 else
3687 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3688 psrch_inf->srch_entries_start = response_data;
3689 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3690 psrch_inf->smallBuf = 0;
3691 if (parms->EndofSearch)
3692 psrch_inf->endOfSearch = true;
3693 else
3694 psrch_inf->endOfSearch = false;
3695 psrch_inf->entries_in_buffer =
3696 le16_to_cpu(parms->SearchCount);
3697 psrch_inf->index_of_last_entry +=
3698 psrch_inf->entries_in_buffer;
3699 lnoff = le16_to_cpu(parms->LastNameOffset);
3700 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3701 lnoff) {
3702 cERROR(1, ("ignoring corrupt resume name"));
3703 psrch_inf->last_entry = NULL;
3704 return rc;
3705 } else
3706 psrch_inf->last_entry =
3707 psrch_inf->srch_entries_start + lnoff;
3709 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3710 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3712 /* BB fixme add unlock here */
3717 /* BB On error, should we leave previous search buf (and count and
3718 last entry fields) intact or free the previous one? */
3720 /* Note: On -EAGAIN error only caller can retry on handle based calls
3721 since file handle passed in no longer valid */
3722 FNext2_err_exit:
3723 if (rc != 0)
3724 cifs_buf_release(pSMB);
3725 return rc;
3729 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3730 const __u16 searchHandle)
3732 int rc = 0;
3733 FINDCLOSE_REQ *pSMB = NULL;
3735 cFYI(1, ("In CIFSSMBFindClose"));
3736 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3738 /* no sense returning error if session restarted
3739 as file handle has been closed */
3740 if (rc == -EAGAIN)
3741 return 0;
3742 if (rc)
3743 return rc;
3745 pSMB->FileID = searchHandle;
3746 pSMB->ByteCount = 0;
3747 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3748 if (rc)
3749 cERROR(1, ("Send error in FindClose = %d", rc));
3751 cifs_stats_inc(&tcon->num_fclose);
3753 /* Since session is dead, search handle closed on server already */
3754 if (rc == -EAGAIN)
3755 rc = 0;
3757 return rc;
3761 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3762 const unsigned char *searchName,
3763 __u64 *inode_number,
3764 const struct nls_table *nls_codepage, int remap)
3766 int rc = 0;
3767 TRANSACTION2_QPI_REQ *pSMB = NULL;
3768 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3769 int name_len, bytes_returned;
3770 __u16 params, byte_count;
3772 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3773 if (tcon == NULL)
3774 return -ENODEV;
3776 GetInodeNumberRetry:
3777 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3778 (void **) &pSMBr);
3779 if (rc)
3780 return rc;
3782 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3783 name_len =
3784 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3785 PATH_MAX, nls_codepage, remap);
3786 name_len++; /* trailing null */
3787 name_len *= 2;
3788 } else { /* BB improve the check for buffer overruns BB */
3789 name_len = strnlen(searchName, PATH_MAX);
3790 name_len++; /* trailing null */
3791 strncpy(pSMB->FileName, searchName, name_len);
3794 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3795 pSMB->TotalDataCount = 0;
3796 pSMB->MaxParameterCount = cpu_to_le16(2);
3797 /* BB find exact max data count below from sess structure BB */
3798 pSMB->MaxDataCount = cpu_to_le16(4000);
3799 pSMB->MaxSetupCount = 0;
3800 pSMB->Reserved = 0;
3801 pSMB->Flags = 0;
3802 pSMB->Timeout = 0;
3803 pSMB->Reserved2 = 0;
3804 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3805 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3806 pSMB->DataCount = 0;
3807 pSMB->DataOffset = 0;
3808 pSMB->SetupCount = 1;
3809 pSMB->Reserved3 = 0;
3810 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3811 byte_count = params + 1 /* pad */ ;
3812 pSMB->TotalParameterCount = cpu_to_le16(params);
3813 pSMB->ParameterCount = pSMB->TotalParameterCount;
3814 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3815 pSMB->Reserved4 = 0;
3816 pSMB->hdr.smb_buf_length += byte_count;
3817 pSMB->ByteCount = cpu_to_le16(byte_count);
3819 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3820 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3821 if (rc) {
3822 cFYI(1, ("error %d in QueryInternalInfo", rc));
3823 } else {
3824 /* decode response */
3825 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3826 if (rc || (pSMBr->ByteCount < 2))
3827 /* BB also check enough total bytes returned */
3828 /* If rc should we check for EOPNOSUPP and
3829 disable the srvino flag? or in caller? */
3830 rc = -EIO; /* bad smb */
3831 else {
3832 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3833 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3834 struct file_internal_info *pfinfo;
3835 /* BB Do we need a cast or hash here ? */
3836 if (count < 8) {
3837 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3838 rc = -EIO;
3839 goto GetInodeNumOut;
3841 pfinfo = (struct file_internal_info *)
3842 (data_offset + (char *) &pSMBr->hdr.Protocol);
3843 *inode_number = le64_to_cpu(pfinfo->UniqueId);
3846 GetInodeNumOut:
3847 cifs_buf_release(pSMB);
3848 if (rc == -EAGAIN)
3849 goto GetInodeNumberRetry;
3850 return rc;
3853 /* parses DFS refferal V3 structure
3854 * caller is responsible for freeing target_nodes
3855 * returns:
3856 * on success - 0
3857 * on failure - errno
3859 static int
3860 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
3861 unsigned int *num_of_nodes,
3862 struct dfs_info3_param **target_nodes,
3863 const struct nls_table *nls_codepage, int remap,
3864 const char *searchName)
3866 int i, rc = 0;
3867 char *data_end;
3868 bool is_unicode;
3869 struct dfs_referral_level_3 *ref;
3871 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3872 is_unicode = true;
3873 else
3874 is_unicode = false;
3875 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3877 if (*num_of_nodes < 1) {
3878 cERROR(1, ("num_referrals: must be at least > 0,"
3879 "but we get num_referrals = %d\n", *num_of_nodes));
3880 rc = -EINVAL;
3881 goto parse_DFS_referrals_exit;
3884 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
3885 if (ref->VersionNumber != cpu_to_le16(3)) {
3886 cERROR(1, ("Referrals of V%d version are not supported,"
3887 "should be V3", le16_to_cpu(ref->VersionNumber)));
3888 rc = -EINVAL;
3889 goto parse_DFS_referrals_exit;
3892 /* get the upper boundary of the resp buffer */
3893 data_end = (char *)(&(pSMBr->PathConsumed)) +
3894 le16_to_cpu(pSMBr->t2.DataCount);
3896 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3897 *num_of_nodes,
3898 le32_to_cpu(pSMBr->DFSFlags)));
3900 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3901 *num_of_nodes, GFP_KERNEL);
3902 if (*target_nodes == NULL) {
3903 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3904 rc = -ENOMEM;
3905 goto parse_DFS_referrals_exit;
3908 /* collect neccessary data from referrals */
3909 for (i = 0; i < *num_of_nodes; i++) {
3910 char *temp;
3911 int max_len;
3912 struct dfs_info3_param *node = (*target_nodes)+i;
3914 node->flags = le32_to_cpu(pSMBr->DFSFlags);
3915 if (is_unicode) {
3916 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3917 GFP_KERNEL);
3918 if (tmp == NULL) {
3919 rc = -ENOMEM;
3920 goto parse_DFS_referrals_exit;
3922 cifsConvertToUCS((__le16 *) tmp, searchName,
3923 PATH_MAX, nls_codepage, remap);
3924 node->path_consumed = cifs_ucs2_bytes(tmp,
3925 le16_to_cpu(pSMBr->PathConsumed),
3926 nls_codepage);
3927 kfree(tmp);
3928 } else
3929 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3931 node->server_type = le16_to_cpu(ref->ServerType);
3932 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3934 /* copy DfsPath */
3935 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3936 max_len = data_end - temp;
3937 node->path_name = cifs_strndup_from_ucs(temp, max_len,
3938 is_unicode, nls_codepage);
3939 if (!node->path_name) {
3940 rc = -ENOMEM;
3941 goto parse_DFS_referrals_exit;
3944 /* copy link target UNC */
3945 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3946 max_len = data_end - temp;
3947 node->node_name = cifs_strndup_from_ucs(temp, max_len,
3948 is_unicode, nls_codepage);
3949 if (!node->node_name)
3950 rc = -ENOMEM;
3953 parse_DFS_referrals_exit:
3954 if (rc) {
3955 free_dfs_info_array(*target_nodes, *num_of_nodes);
3956 *target_nodes = NULL;
3957 *num_of_nodes = 0;
3959 return rc;
3963 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3964 const unsigned char *searchName,
3965 struct dfs_info3_param **target_nodes,
3966 unsigned int *num_of_nodes,
3967 const struct nls_table *nls_codepage, int remap)
3969 /* TRANS2_GET_DFS_REFERRAL */
3970 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3971 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3972 int rc = 0;
3973 int bytes_returned;
3974 int name_len;
3975 __u16 params, byte_count;
3976 *num_of_nodes = 0;
3977 *target_nodes = NULL;
3979 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3980 if (ses == NULL)
3981 return -ENODEV;
3982 getDFSRetry:
3983 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3984 (void **) &pSMBr);
3985 if (rc)
3986 return rc;
3988 /* server pointer checked in called function,
3989 but should never be null here anyway */
3990 pSMB->hdr.Mid = GetNextMid(ses->server);
3991 pSMB->hdr.Tid = ses->ipc_tid;
3992 pSMB->hdr.Uid = ses->Suid;
3993 if (ses->capabilities & CAP_STATUS32)
3994 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3995 if (ses->capabilities & CAP_DFS)
3996 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3998 if (ses->capabilities & CAP_UNICODE) {
3999 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4000 name_len =
4001 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4002 searchName, PATH_MAX, nls_codepage, remap);
4003 name_len++; /* trailing null */
4004 name_len *= 2;
4005 } else { /* BB improve the check for buffer overruns BB */
4006 name_len = strnlen(searchName, PATH_MAX);
4007 name_len++; /* trailing null */
4008 strncpy(pSMB->RequestFileName, searchName, name_len);
4011 if (ses->server) {
4012 if (ses->server->secMode &
4013 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4014 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4017 pSMB->hdr.Uid = ses->Suid;
4019 params = 2 /* level */ + name_len /*includes null */ ;
4020 pSMB->TotalDataCount = 0;
4021 pSMB->DataCount = 0;
4022 pSMB->DataOffset = 0;
4023 pSMB->MaxParameterCount = 0;
4024 /* BB find exact max SMB PDU from sess structure BB */
4025 pSMB->MaxDataCount = cpu_to_le16(4000);
4026 pSMB->MaxSetupCount = 0;
4027 pSMB->Reserved = 0;
4028 pSMB->Flags = 0;
4029 pSMB->Timeout = 0;
4030 pSMB->Reserved2 = 0;
4031 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4032 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4033 pSMB->SetupCount = 1;
4034 pSMB->Reserved3 = 0;
4035 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4036 byte_count = params + 3 /* pad */ ;
4037 pSMB->ParameterCount = cpu_to_le16(params);
4038 pSMB->TotalParameterCount = pSMB->ParameterCount;
4039 pSMB->MaxReferralLevel = cpu_to_le16(3);
4040 pSMB->hdr.smb_buf_length += byte_count;
4041 pSMB->ByteCount = cpu_to_le16(byte_count);
4043 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4044 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4045 if (rc) {
4046 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
4047 goto GetDFSRefExit;
4049 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4051 /* BB Also check if enough total bytes returned? */
4052 if (rc || (pSMBr->ByteCount < 17)) {
4053 rc = -EIO; /* bad smb */
4054 goto GetDFSRefExit;
4057 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4058 pSMBr->ByteCount,
4059 le16_to_cpu(pSMBr->t2.DataOffset)));
4061 /* parse returned result into more usable form */
4062 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4063 target_nodes, nls_codepage, remap,
4064 searchName);
4066 GetDFSRefExit:
4067 cifs_buf_release(pSMB);
4069 if (rc == -EAGAIN)
4070 goto getDFSRetry;
4072 return rc;
4075 /* Query File System Info such as free space to old servers such as Win 9x */
4077 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4079 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4080 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4081 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4082 FILE_SYSTEM_ALLOC_INFO *response_data;
4083 int rc = 0;
4084 int bytes_returned = 0;
4085 __u16 params, byte_count;
4087 cFYI(1, ("OldQFSInfo"));
4088 oldQFSInfoRetry:
4089 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4090 (void **) &pSMBr);
4091 if (rc)
4092 return rc;
4094 params = 2; /* level */
4095 pSMB->TotalDataCount = 0;
4096 pSMB->MaxParameterCount = cpu_to_le16(2);
4097 pSMB->MaxDataCount = cpu_to_le16(1000);
4098 pSMB->MaxSetupCount = 0;
4099 pSMB->Reserved = 0;
4100 pSMB->Flags = 0;
4101 pSMB->Timeout = 0;
4102 pSMB->Reserved2 = 0;
4103 byte_count = params + 1 /* pad */ ;
4104 pSMB->TotalParameterCount = cpu_to_le16(params);
4105 pSMB->ParameterCount = pSMB->TotalParameterCount;
4106 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4107 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4108 pSMB->DataCount = 0;
4109 pSMB->DataOffset = 0;
4110 pSMB->SetupCount = 1;
4111 pSMB->Reserved3 = 0;
4112 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4113 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4114 pSMB->hdr.smb_buf_length += byte_count;
4115 pSMB->ByteCount = cpu_to_le16(byte_count);
4117 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4118 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4119 if (rc) {
4120 cFYI(1, ("Send error in QFSInfo = %d", rc));
4121 } else { /* decode response */
4122 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4124 if (rc || (pSMBr->ByteCount < 18))
4125 rc = -EIO; /* bad smb */
4126 else {
4127 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4128 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4129 pSMBr->ByteCount, data_offset));
4131 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4132 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4133 FSData->f_bsize =
4134 le16_to_cpu(response_data->BytesPerSector) *
4135 le32_to_cpu(response_data->
4136 SectorsPerAllocationUnit);
4137 FSData->f_blocks =
4138 le32_to_cpu(response_data->TotalAllocationUnits);
4139 FSData->f_bfree = FSData->f_bavail =
4140 le32_to_cpu(response_data->FreeAllocationUnits);
4141 cFYI(1,
4142 ("Blocks: %lld Free: %lld Block size %ld",
4143 (unsigned long long)FSData->f_blocks,
4144 (unsigned long long)FSData->f_bfree,
4145 FSData->f_bsize));
4148 cifs_buf_release(pSMB);
4150 if (rc == -EAGAIN)
4151 goto oldQFSInfoRetry;
4153 return rc;
4157 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4159 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4160 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4161 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4162 FILE_SYSTEM_INFO *response_data;
4163 int rc = 0;
4164 int bytes_returned = 0;
4165 __u16 params, byte_count;
4167 cFYI(1, ("In QFSInfo"));
4168 QFSInfoRetry:
4169 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4170 (void **) &pSMBr);
4171 if (rc)
4172 return rc;
4174 params = 2; /* level */
4175 pSMB->TotalDataCount = 0;
4176 pSMB->MaxParameterCount = cpu_to_le16(2);
4177 pSMB->MaxDataCount = cpu_to_le16(1000);
4178 pSMB->MaxSetupCount = 0;
4179 pSMB->Reserved = 0;
4180 pSMB->Flags = 0;
4181 pSMB->Timeout = 0;
4182 pSMB->Reserved2 = 0;
4183 byte_count = params + 1 /* pad */ ;
4184 pSMB->TotalParameterCount = cpu_to_le16(params);
4185 pSMB->ParameterCount = pSMB->TotalParameterCount;
4186 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4187 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4188 pSMB->DataCount = 0;
4189 pSMB->DataOffset = 0;
4190 pSMB->SetupCount = 1;
4191 pSMB->Reserved3 = 0;
4192 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4193 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4194 pSMB->hdr.smb_buf_length += byte_count;
4195 pSMB->ByteCount = cpu_to_le16(byte_count);
4197 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4198 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4199 if (rc) {
4200 cFYI(1, ("Send error in QFSInfo = %d", rc));
4201 } else { /* decode response */
4202 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4204 if (rc || (pSMBr->ByteCount < 24))
4205 rc = -EIO; /* bad smb */
4206 else {
4207 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4209 response_data =
4210 (FILE_SYSTEM_INFO
4211 *) (((char *) &pSMBr->hdr.Protocol) +
4212 data_offset);
4213 FSData->f_bsize =
4214 le32_to_cpu(response_data->BytesPerSector) *
4215 le32_to_cpu(response_data->
4216 SectorsPerAllocationUnit);
4217 FSData->f_blocks =
4218 le64_to_cpu(response_data->TotalAllocationUnits);
4219 FSData->f_bfree = FSData->f_bavail =
4220 le64_to_cpu(response_data->FreeAllocationUnits);
4221 cFYI(1,
4222 ("Blocks: %lld Free: %lld Block size %ld",
4223 (unsigned long long)FSData->f_blocks,
4224 (unsigned long long)FSData->f_bfree,
4225 FSData->f_bsize));
4228 cifs_buf_release(pSMB);
4230 if (rc == -EAGAIN)
4231 goto QFSInfoRetry;
4233 return rc;
4237 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4239 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4240 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4241 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4242 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4243 int rc = 0;
4244 int bytes_returned = 0;
4245 __u16 params, byte_count;
4247 cFYI(1, ("In QFSAttributeInfo"));
4248 QFSAttributeRetry:
4249 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4250 (void **) &pSMBr);
4251 if (rc)
4252 return rc;
4254 params = 2; /* level */
4255 pSMB->TotalDataCount = 0;
4256 pSMB->MaxParameterCount = cpu_to_le16(2);
4257 /* BB find exact max SMB PDU from sess structure BB */
4258 pSMB->MaxDataCount = cpu_to_le16(1000);
4259 pSMB->MaxSetupCount = 0;
4260 pSMB->Reserved = 0;
4261 pSMB->Flags = 0;
4262 pSMB->Timeout = 0;
4263 pSMB->Reserved2 = 0;
4264 byte_count = params + 1 /* pad */ ;
4265 pSMB->TotalParameterCount = cpu_to_le16(params);
4266 pSMB->ParameterCount = pSMB->TotalParameterCount;
4267 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4268 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4269 pSMB->DataCount = 0;
4270 pSMB->DataOffset = 0;
4271 pSMB->SetupCount = 1;
4272 pSMB->Reserved3 = 0;
4273 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4274 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4275 pSMB->hdr.smb_buf_length += byte_count;
4276 pSMB->ByteCount = cpu_to_le16(byte_count);
4278 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4279 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4280 if (rc) {
4281 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4282 } else { /* decode response */
4283 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4285 if (rc || (pSMBr->ByteCount < 13)) {
4286 /* BB also check if enough bytes returned */
4287 rc = -EIO; /* bad smb */
4288 } else {
4289 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4290 response_data =
4291 (FILE_SYSTEM_ATTRIBUTE_INFO
4292 *) (((char *) &pSMBr->hdr.Protocol) +
4293 data_offset);
4294 memcpy(&tcon->fsAttrInfo, response_data,
4295 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4298 cifs_buf_release(pSMB);
4300 if (rc == -EAGAIN)
4301 goto QFSAttributeRetry;
4303 return rc;
4307 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4309 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4310 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4311 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4312 FILE_SYSTEM_DEVICE_INFO *response_data;
4313 int rc = 0;
4314 int bytes_returned = 0;
4315 __u16 params, byte_count;
4317 cFYI(1, ("In QFSDeviceInfo"));
4318 QFSDeviceRetry:
4319 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4320 (void **) &pSMBr);
4321 if (rc)
4322 return rc;
4324 params = 2; /* level */
4325 pSMB->TotalDataCount = 0;
4326 pSMB->MaxParameterCount = cpu_to_le16(2);
4327 /* BB find exact max SMB PDU from sess structure BB */
4328 pSMB->MaxDataCount = cpu_to_le16(1000);
4329 pSMB->MaxSetupCount = 0;
4330 pSMB->Reserved = 0;
4331 pSMB->Flags = 0;
4332 pSMB->Timeout = 0;
4333 pSMB->Reserved2 = 0;
4334 byte_count = params + 1 /* pad */ ;
4335 pSMB->TotalParameterCount = cpu_to_le16(params);
4336 pSMB->ParameterCount = pSMB->TotalParameterCount;
4337 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4338 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4340 pSMB->DataCount = 0;
4341 pSMB->DataOffset = 0;
4342 pSMB->SetupCount = 1;
4343 pSMB->Reserved3 = 0;
4344 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4345 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4346 pSMB->hdr.smb_buf_length += byte_count;
4347 pSMB->ByteCount = cpu_to_le16(byte_count);
4349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4351 if (rc) {
4352 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4353 } else { /* decode response */
4354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4356 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4357 rc = -EIO; /* bad smb */
4358 else {
4359 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4360 response_data =
4361 (FILE_SYSTEM_DEVICE_INFO *)
4362 (((char *) &pSMBr->hdr.Protocol) +
4363 data_offset);
4364 memcpy(&tcon->fsDevInfo, response_data,
4365 sizeof(FILE_SYSTEM_DEVICE_INFO));
4368 cifs_buf_release(pSMB);
4370 if (rc == -EAGAIN)
4371 goto QFSDeviceRetry;
4373 return rc;
4377 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4379 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4380 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4381 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4382 FILE_SYSTEM_UNIX_INFO *response_data;
4383 int rc = 0;
4384 int bytes_returned = 0;
4385 __u16 params, byte_count;
4387 cFYI(1, ("In QFSUnixInfo"));
4388 QFSUnixRetry:
4389 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4390 (void **) &pSMBr);
4391 if (rc)
4392 return rc;
4394 params = 2; /* level */
4395 pSMB->TotalDataCount = 0;
4396 pSMB->DataCount = 0;
4397 pSMB->DataOffset = 0;
4398 pSMB->MaxParameterCount = cpu_to_le16(2);
4399 /* BB find exact max SMB PDU from sess structure BB */
4400 pSMB->MaxDataCount = cpu_to_le16(100);
4401 pSMB->MaxSetupCount = 0;
4402 pSMB->Reserved = 0;
4403 pSMB->Flags = 0;
4404 pSMB->Timeout = 0;
4405 pSMB->Reserved2 = 0;
4406 byte_count = params + 1 /* pad */ ;
4407 pSMB->ParameterCount = cpu_to_le16(params);
4408 pSMB->TotalParameterCount = pSMB->ParameterCount;
4409 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4410 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4411 pSMB->SetupCount = 1;
4412 pSMB->Reserved3 = 0;
4413 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4414 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4415 pSMB->hdr.smb_buf_length += byte_count;
4416 pSMB->ByteCount = cpu_to_le16(byte_count);
4418 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4419 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4420 if (rc) {
4421 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4422 } else { /* decode response */
4423 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4425 if (rc || (pSMBr->ByteCount < 13)) {
4426 rc = -EIO; /* bad smb */
4427 } else {
4428 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4429 response_data =
4430 (FILE_SYSTEM_UNIX_INFO
4431 *) (((char *) &pSMBr->hdr.Protocol) +
4432 data_offset);
4433 memcpy(&tcon->fsUnixInfo, response_data,
4434 sizeof(FILE_SYSTEM_UNIX_INFO));
4437 cifs_buf_release(pSMB);
4439 if (rc == -EAGAIN)
4440 goto QFSUnixRetry;
4443 return rc;
4447 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4449 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4450 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4451 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4452 int rc = 0;
4453 int bytes_returned = 0;
4454 __u16 params, param_offset, offset, byte_count;
4456 cFYI(1, ("In SETFSUnixInfo"));
4457 SETFSUnixRetry:
4458 /* BB switch to small buf init to save memory */
4459 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4460 (void **) &pSMBr);
4461 if (rc)
4462 return rc;
4464 params = 4; /* 2 bytes zero followed by info level. */
4465 pSMB->MaxSetupCount = 0;
4466 pSMB->Reserved = 0;
4467 pSMB->Flags = 0;
4468 pSMB->Timeout = 0;
4469 pSMB->Reserved2 = 0;
4470 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4471 - 4;
4472 offset = param_offset + params;
4474 pSMB->MaxParameterCount = cpu_to_le16(4);
4475 /* BB find exact max SMB PDU from sess structure BB */
4476 pSMB->MaxDataCount = cpu_to_le16(100);
4477 pSMB->SetupCount = 1;
4478 pSMB->Reserved3 = 0;
4479 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4480 byte_count = 1 /* pad */ + params + 12;
4482 pSMB->DataCount = cpu_to_le16(12);
4483 pSMB->ParameterCount = cpu_to_le16(params);
4484 pSMB->TotalDataCount = pSMB->DataCount;
4485 pSMB->TotalParameterCount = pSMB->ParameterCount;
4486 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4487 pSMB->DataOffset = cpu_to_le16(offset);
4489 /* Params. */
4490 pSMB->FileNum = 0;
4491 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4493 /* Data. */
4494 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4495 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4496 pSMB->ClientUnixCap = cpu_to_le64(cap);
4498 pSMB->hdr.smb_buf_length += byte_count;
4499 pSMB->ByteCount = cpu_to_le16(byte_count);
4501 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4502 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4503 if (rc) {
4504 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4505 } else { /* decode response */
4506 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4507 if (rc)
4508 rc = -EIO; /* bad smb */
4510 cifs_buf_release(pSMB);
4512 if (rc == -EAGAIN)
4513 goto SETFSUnixRetry;
4515 return rc;
4521 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4522 struct kstatfs *FSData)
4524 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4525 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4526 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4527 FILE_SYSTEM_POSIX_INFO *response_data;
4528 int rc = 0;
4529 int bytes_returned = 0;
4530 __u16 params, byte_count;
4532 cFYI(1, ("In QFSPosixInfo"));
4533 QFSPosixRetry:
4534 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4535 (void **) &pSMBr);
4536 if (rc)
4537 return rc;
4539 params = 2; /* level */
4540 pSMB->TotalDataCount = 0;
4541 pSMB->DataCount = 0;
4542 pSMB->DataOffset = 0;
4543 pSMB->MaxParameterCount = cpu_to_le16(2);
4544 /* BB find exact max SMB PDU from sess structure BB */
4545 pSMB->MaxDataCount = cpu_to_le16(100);
4546 pSMB->MaxSetupCount = 0;
4547 pSMB->Reserved = 0;
4548 pSMB->Flags = 0;
4549 pSMB->Timeout = 0;
4550 pSMB->Reserved2 = 0;
4551 byte_count = params + 1 /* pad */ ;
4552 pSMB->ParameterCount = cpu_to_le16(params);
4553 pSMB->TotalParameterCount = pSMB->ParameterCount;
4554 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4555 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4556 pSMB->SetupCount = 1;
4557 pSMB->Reserved3 = 0;
4558 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4559 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4560 pSMB->hdr.smb_buf_length += byte_count;
4561 pSMB->ByteCount = cpu_to_le16(byte_count);
4563 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4564 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4565 if (rc) {
4566 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4567 } else { /* decode response */
4568 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4570 if (rc || (pSMBr->ByteCount < 13)) {
4571 rc = -EIO; /* bad smb */
4572 } else {
4573 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4574 response_data =
4575 (FILE_SYSTEM_POSIX_INFO
4576 *) (((char *) &pSMBr->hdr.Protocol) +
4577 data_offset);
4578 FSData->f_bsize =
4579 le32_to_cpu(response_data->BlockSize);
4580 FSData->f_blocks =
4581 le64_to_cpu(response_data->TotalBlocks);
4582 FSData->f_bfree =
4583 le64_to_cpu(response_data->BlocksAvail);
4584 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4585 FSData->f_bavail = FSData->f_bfree;
4586 } else {
4587 FSData->f_bavail =
4588 le64_to_cpu(response_data->UserBlocksAvail);
4590 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4591 FSData->f_files =
4592 le64_to_cpu(response_data->TotalFileNodes);
4593 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4594 FSData->f_ffree =
4595 le64_to_cpu(response_data->FreeFileNodes);
4598 cifs_buf_release(pSMB);
4600 if (rc == -EAGAIN)
4601 goto QFSPosixRetry;
4603 return rc;
4607 /* We can not use write of zero bytes trick to
4608 set file size due to need for large file support. Also note that
4609 this SetPathInfo is preferred to SetFileInfo based method in next
4610 routine which is only needed to work around a sharing violation bug
4611 in Samba which this routine can run into */
4614 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4615 __u64 size, bool SetAllocation,
4616 const struct nls_table *nls_codepage, int remap)
4618 struct smb_com_transaction2_spi_req *pSMB = NULL;
4619 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4620 struct file_end_of_file_info *parm_data;
4621 int name_len;
4622 int rc = 0;
4623 int bytes_returned = 0;
4624 __u16 params, byte_count, data_count, param_offset, offset;
4626 cFYI(1, ("In SetEOF"));
4627 SetEOFRetry:
4628 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4629 (void **) &pSMBr);
4630 if (rc)
4631 return rc;
4633 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4634 name_len =
4635 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4636 PATH_MAX, nls_codepage, remap);
4637 name_len++; /* trailing null */
4638 name_len *= 2;
4639 } else { /* BB improve the check for buffer overruns BB */
4640 name_len = strnlen(fileName, PATH_MAX);
4641 name_len++; /* trailing null */
4642 strncpy(pSMB->FileName, fileName, name_len);
4644 params = 6 + name_len;
4645 data_count = sizeof(struct file_end_of_file_info);
4646 pSMB->MaxParameterCount = cpu_to_le16(2);
4647 pSMB->MaxDataCount = cpu_to_le16(4100);
4648 pSMB->MaxSetupCount = 0;
4649 pSMB->Reserved = 0;
4650 pSMB->Flags = 0;
4651 pSMB->Timeout = 0;
4652 pSMB->Reserved2 = 0;
4653 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4654 InformationLevel) - 4;
4655 offset = param_offset + params;
4656 if (SetAllocation) {
4657 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4658 pSMB->InformationLevel =
4659 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4660 else
4661 pSMB->InformationLevel =
4662 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4663 } else /* Set File Size */ {
4664 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4665 pSMB->InformationLevel =
4666 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4667 else
4668 pSMB->InformationLevel =
4669 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4672 parm_data =
4673 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4674 offset);
4675 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4676 pSMB->DataOffset = cpu_to_le16(offset);
4677 pSMB->SetupCount = 1;
4678 pSMB->Reserved3 = 0;
4679 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4680 byte_count = 3 /* pad */ + params + data_count;
4681 pSMB->DataCount = cpu_to_le16(data_count);
4682 pSMB->TotalDataCount = pSMB->DataCount;
4683 pSMB->ParameterCount = cpu_to_le16(params);
4684 pSMB->TotalParameterCount = pSMB->ParameterCount;
4685 pSMB->Reserved4 = 0;
4686 pSMB->hdr.smb_buf_length += byte_count;
4687 parm_data->FileSize = cpu_to_le64(size);
4688 pSMB->ByteCount = cpu_to_le16(byte_count);
4689 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4690 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4691 if (rc)
4692 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4694 cifs_buf_release(pSMB);
4696 if (rc == -EAGAIN)
4697 goto SetEOFRetry;
4699 return rc;
4703 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4704 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4706 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4707 char *data_offset;
4708 struct file_end_of_file_info *parm_data;
4709 int rc = 0;
4710 __u16 params, param_offset, offset, byte_count, count;
4712 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4713 (long long)size));
4714 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4716 if (rc)
4717 return rc;
4719 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4720 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4722 params = 6;
4723 pSMB->MaxSetupCount = 0;
4724 pSMB->Reserved = 0;
4725 pSMB->Flags = 0;
4726 pSMB->Timeout = 0;
4727 pSMB->Reserved2 = 0;
4728 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4729 offset = param_offset + params;
4731 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4733 count = sizeof(struct file_end_of_file_info);
4734 pSMB->MaxParameterCount = cpu_to_le16(2);
4735 /* BB find exact max SMB PDU from sess structure BB */
4736 pSMB->MaxDataCount = cpu_to_le16(1000);
4737 pSMB->SetupCount = 1;
4738 pSMB->Reserved3 = 0;
4739 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4740 byte_count = 3 /* pad */ + params + count;
4741 pSMB->DataCount = cpu_to_le16(count);
4742 pSMB->ParameterCount = cpu_to_le16(params);
4743 pSMB->TotalDataCount = pSMB->DataCount;
4744 pSMB->TotalParameterCount = pSMB->ParameterCount;
4745 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4746 parm_data =
4747 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4748 + offset);
4749 pSMB->DataOffset = cpu_to_le16(offset);
4750 parm_data->FileSize = cpu_to_le64(size);
4751 pSMB->Fid = fid;
4752 if (SetAllocation) {
4753 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4754 pSMB->InformationLevel =
4755 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4756 else
4757 pSMB->InformationLevel =
4758 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4759 } else /* Set File Size */ {
4760 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4761 pSMB->InformationLevel =
4762 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4763 else
4764 pSMB->InformationLevel =
4765 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4767 pSMB->Reserved4 = 0;
4768 pSMB->hdr.smb_buf_length += byte_count;
4769 pSMB->ByteCount = cpu_to_le16(byte_count);
4770 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4771 if (rc) {
4772 cFYI(1,
4773 ("Send error in SetFileInfo (SetFileSize) = %d",
4774 rc));
4777 /* Note: On -EAGAIN error only caller can retry on handle based calls
4778 since file handle passed in no longer valid */
4780 return rc;
4783 /* Some legacy servers such as NT4 require that the file times be set on
4784 an open handle, rather than by pathname - this is awkward due to
4785 potential access conflicts on the open, but it is unavoidable for these
4786 old servers since the only other choice is to go from 100 nanosecond DCE
4787 time and resort to the original setpathinfo level which takes the ancient
4788 DOS time format with 2 second granularity */
4790 CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4791 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4793 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4794 char *data_offset;
4795 int rc = 0;
4796 __u16 params, param_offset, offset, byte_count, count;
4798 cFYI(1, ("Set Times (via SetFileInfo)"));
4799 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4801 if (rc)
4802 return rc;
4804 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4805 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4807 params = 6;
4808 pSMB->MaxSetupCount = 0;
4809 pSMB->Reserved = 0;
4810 pSMB->Flags = 0;
4811 pSMB->Timeout = 0;
4812 pSMB->Reserved2 = 0;
4813 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4814 offset = param_offset + params;
4816 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4818 count = sizeof(FILE_BASIC_INFO);
4819 pSMB->MaxParameterCount = cpu_to_le16(2);
4820 /* BB find max SMB PDU from sess */
4821 pSMB->MaxDataCount = cpu_to_le16(1000);
4822 pSMB->SetupCount = 1;
4823 pSMB->Reserved3 = 0;
4824 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4825 byte_count = 3 /* pad */ + params + count;
4826 pSMB->DataCount = cpu_to_le16(count);
4827 pSMB->ParameterCount = cpu_to_le16(params);
4828 pSMB->TotalDataCount = pSMB->DataCount;
4829 pSMB->TotalParameterCount = pSMB->ParameterCount;
4830 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4831 pSMB->DataOffset = cpu_to_le16(offset);
4832 pSMB->Fid = fid;
4833 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4834 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4835 else
4836 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4837 pSMB->Reserved4 = 0;
4838 pSMB->hdr.smb_buf_length += byte_count;
4839 pSMB->ByteCount = cpu_to_le16(byte_count);
4840 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4841 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4842 if (rc)
4843 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4845 /* Note: On -EAGAIN error only caller can retry on handle based calls
4846 since file handle passed in no longer valid */
4848 return rc;
4852 CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4853 bool delete_file, __u16 fid, __u32 pid_of_opener)
4855 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4856 char *data_offset;
4857 int rc = 0;
4858 __u16 params, param_offset, offset, byte_count, count;
4860 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4861 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4863 if (rc)
4864 return rc;
4866 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4867 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4869 params = 6;
4870 pSMB->MaxSetupCount = 0;
4871 pSMB->Reserved = 0;
4872 pSMB->Flags = 0;
4873 pSMB->Timeout = 0;
4874 pSMB->Reserved2 = 0;
4875 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4876 offset = param_offset + params;
4878 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4880 count = 1;
4881 pSMB->MaxParameterCount = cpu_to_le16(2);
4882 /* BB find max SMB PDU from sess */
4883 pSMB->MaxDataCount = cpu_to_le16(1000);
4884 pSMB->SetupCount = 1;
4885 pSMB->Reserved3 = 0;
4886 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4887 byte_count = 3 /* pad */ + params + count;
4888 pSMB->DataCount = cpu_to_le16(count);
4889 pSMB->ParameterCount = cpu_to_le16(params);
4890 pSMB->TotalDataCount = pSMB->DataCount;
4891 pSMB->TotalParameterCount = pSMB->ParameterCount;
4892 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4893 pSMB->DataOffset = cpu_to_le16(offset);
4894 pSMB->Fid = fid;
4895 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4896 pSMB->Reserved4 = 0;
4897 pSMB->hdr.smb_buf_length += byte_count;
4898 pSMB->ByteCount = cpu_to_le16(byte_count);
4899 *data_offset = delete_file ? 1 : 0;
4900 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4901 if (rc)
4902 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4904 return rc;
4908 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4909 const char *fileName, const FILE_BASIC_INFO *data,
4910 const struct nls_table *nls_codepage, int remap)
4912 TRANSACTION2_SPI_REQ *pSMB = NULL;
4913 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4914 int name_len;
4915 int rc = 0;
4916 int bytes_returned = 0;
4917 char *data_offset;
4918 __u16 params, param_offset, offset, byte_count, count;
4920 cFYI(1, ("In SetTimes"));
4922 SetTimesRetry:
4923 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4924 (void **) &pSMBr);
4925 if (rc)
4926 return rc;
4928 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4929 name_len =
4930 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4931 PATH_MAX, nls_codepage, remap);
4932 name_len++; /* trailing null */
4933 name_len *= 2;
4934 } else { /* BB improve the check for buffer overruns BB */
4935 name_len = strnlen(fileName, PATH_MAX);
4936 name_len++; /* trailing null */
4937 strncpy(pSMB->FileName, fileName, name_len);
4940 params = 6 + name_len;
4941 count = sizeof(FILE_BASIC_INFO);
4942 pSMB->MaxParameterCount = cpu_to_le16(2);
4943 /* BB find max SMB PDU from sess structure BB */
4944 pSMB->MaxDataCount = cpu_to_le16(1000);
4945 pSMB->MaxSetupCount = 0;
4946 pSMB->Reserved = 0;
4947 pSMB->Flags = 0;
4948 pSMB->Timeout = 0;
4949 pSMB->Reserved2 = 0;
4950 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4951 InformationLevel) - 4;
4952 offset = param_offset + params;
4953 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4954 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4955 pSMB->DataOffset = cpu_to_le16(offset);
4956 pSMB->SetupCount = 1;
4957 pSMB->Reserved3 = 0;
4958 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4959 byte_count = 3 /* pad */ + params + count;
4961 pSMB->DataCount = cpu_to_le16(count);
4962 pSMB->ParameterCount = cpu_to_le16(params);
4963 pSMB->TotalDataCount = pSMB->DataCount;
4964 pSMB->TotalParameterCount = pSMB->ParameterCount;
4965 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4966 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4967 else
4968 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4969 pSMB->Reserved4 = 0;
4970 pSMB->hdr.smb_buf_length += byte_count;
4971 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4972 pSMB->ByteCount = cpu_to_le16(byte_count);
4973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4975 if (rc)
4976 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4978 cifs_buf_release(pSMB);
4980 if (rc == -EAGAIN)
4981 goto SetTimesRetry;
4983 return rc;
4986 /* Can not be used to set time stamps yet (due to old DOS time format) */
4987 /* Can be used to set attributes */
4988 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4989 handling it anyway and NT4 was what we thought it would be needed for
4990 Do not delete it until we prove whether needed for Win9x though */
4992 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4993 __u16 dos_attrs, const struct nls_table *nls_codepage)
4995 SETATTR_REQ *pSMB = NULL;
4996 SETATTR_RSP *pSMBr = NULL;
4997 int rc = 0;
4998 int bytes_returned;
4999 int name_len;
5001 cFYI(1, ("In SetAttrLegacy"));
5003 SetAttrLgcyRetry:
5004 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5005 (void **) &pSMBr);
5006 if (rc)
5007 return rc;
5009 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5010 name_len =
5011 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
5012 PATH_MAX, nls_codepage);
5013 name_len++; /* trailing null */
5014 name_len *= 2;
5015 } else { /* BB improve the check for buffer overruns BB */
5016 name_len = strnlen(fileName, PATH_MAX);
5017 name_len++; /* trailing null */
5018 strncpy(pSMB->fileName, fileName, name_len);
5020 pSMB->attr = cpu_to_le16(dos_attrs);
5021 pSMB->BufferFormat = 0x04;
5022 pSMB->hdr.smb_buf_length += name_len + 1;
5023 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5024 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5025 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5026 if (rc)
5027 cFYI(1, ("Error in LegacySetAttr = %d", rc));
5029 cifs_buf_release(pSMB);
5031 if (rc == -EAGAIN)
5032 goto SetAttrLgcyRetry;
5034 return rc;
5036 #endif /* temporarily unneeded SetAttr legacy function */
5038 static void
5039 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5040 const struct cifs_unix_set_info_args *args)
5042 u64 mode = args->mode;
5045 * Samba server ignores set of file size to zero due to bugs in some
5046 * older clients, but we should be precise - we use SetFileSize to
5047 * set file size and do not want to truncate file size to zero
5048 * accidently as happened on one Samba server beta by putting
5049 * zero instead of -1 here
5051 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5052 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5053 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5054 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5055 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5056 data_offset->Uid = cpu_to_le64(args->uid);
5057 data_offset->Gid = cpu_to_le64(args->gid);
5058 /* better to leave device as zero when it is */
5059 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5060 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5061 data_offset->Permissions = cpu_to_le64(mode);
5063 if (S_ISREG(mode))
5064 data_offset->Type = cpu_to_le32(UNIX_FILE);
5065 else if (S_ISDIR(mode))
5066 data_offset->Type = cpu_to_le32(UNIX_DIR);
5067 else if (S_ISLNK(mode))
5068 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5069 else if (S_ISCHR(mode))
5070 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5071 else if (S_ISBLK(mode))
5072 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5073 else if (S_ISFIFO(mode))
5074 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5075 else if (S_ISSOCK(mode))
5076 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5080 CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5081 const struct cifs_unix_set_info_args *args,
5082 u16 fid, u32 pid_of_opener)
5084 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5085 FILE_UNIX_BASIC_INFO *data_offset;
5086 int rc = 0;
5087 u16 params, param_offset, offset, byte_count, count;
5089 cFYI(1, ("Set Unix Info (via SetFileInfo)"));
5090 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5092 if (rc)
5093 return rc;
5095 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5096 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5098 params = 6;
5099 pSMB->MaxSetupCount = 0;
5100 pSMB->Reserved = 0;
5101 pSMB->Flags = 0;
5102 pSMB->Timeout = 0;
5103 pSMB->Reserved2 = 0;
5104 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5105 offset = param_offset + params;
5107 data_offset = (FILE_UNIX_BASIC_INFO *)
5108 ((char *)(&pSMB->hdr.Protocol) + offset);
5109 count = sizeof(FILE_UNIX_BASIC_INFO);
5111 pSMB->MaxParameterCount = cpu_to_le16(2);
5112 /* BB find max SMB PDU from sess */
5113 pSMB->MaxDataCount = cpu_to_le16(1000);
5114 pSMB->SetupCount = 1;
5115 pSMB->Reserved3 = 0;
5116 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5117 byte_count = 3 /* pad */ + params + count;
5118 pSMB->DataCount = cpu_to_le16(count);
5119 pSMB->ParameterCount = cpu_to_le16(params);
5120 pSMB->TotalDataCount = pSMB->DataCount;
5121 pSMB->TotalParameterCount = pSMB->ParameterCount;
5122 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5123 pSMB->DataOffset = cpu_to_le16(offset);
5124 pSMB->Fid = fid;
5125 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5126 pSMB->Reserved4 = 0;
5127 pSMB->hdr.smb_buf_length += byte_count;
5128 pSMB->ByteCount = cpu_to_le16(byte_count);
5130 cifs_fill_unix_set_info(data_offset, args);
5132 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5133 if (rc)
5134 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
5136 /* Note: On -EAGAIN error only caller can retry on handle based calls
5137 since file handle passed in no longer valid */
5139 return rc;
5143 CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5144 const struct cifs_unix_set_info_args *args,
5145 const struct nls_table *nls_codepage, int remap)
5147 TRANSACTION2_SPI_REQ *pSMB = NULL;
5148 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5149 int name_len;
5150 int rc = 0;
5151 int bytes_returned = 0;
5152 FILE_UNIX_BASIC_INFO *data_offset;
5153 __u16 params, param_offset, offset, count, byte_count;
5155 cFYI(1, ("In SetUID/GID/Mode"));
5156 setPermsRetry:
5157 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5158 (void **) &pSMBr);
5159 if (rc)
5160 return rc;
5162 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5163 name_len =
5164 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5165 PATH_MAX, nls_codepage, remap);
5166 name_len++; /* trailing null */
5167 name_len *= 2;
5168 } else { /* BB improve the check for buffer overruns BB */
5169 name_len = strnlen(fileName, PATH_MAX);
5170 name_len++; /* trailing null */
5171 strncpy(pSMB->FileName, fileName, name_len);
5174 params = 6 + name_len;
5175 count = sizeof(FILE_UNIX_BASIC_INFO);
5176 pSMB->MaxParameterCount = cpu_to_le16(2);
5177 /* BB find max SMB PDU from sess structure BB */
5178 pSMB->MaxDataCount = cpu_to_le16(1000);
5179 pSMB->MaxSetupCount = 0;
5180 pSMB->Reserved = 0;
5181 pSMB->Flags = 0;
5182 pSMB->Timeout = 0;
5183 pSMB->Reserved2 = 0;
5184 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5185 InformationLevel) - 4;
5186 offset = param_offset + params;
5187 data_offset =
5188 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5189 offset);
5190 memset(data_offset, 0, count);
5191 pSMB->DataOffset = cpu_to_le16(offset);
5192 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5193 pSMB->SetupCount = 1;
5194 pSMB->Reserved3 = 0;
5195 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5196 byte_count = 3 /* pad */ + params + count;
5197 pSMB->ParameterCount = cpu_to_le16(params);
5198 pSMB->DataCount = cpu_to_le16(count);
5199 pSMB->TotalParameterCount = pSMB->ParameterCount;
5200 pSMB->TotalDataCount = pSMB->DataCount;
5201 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5202 pSMB->Reserved4 = 0;
5203 pSMB->hdr.smb_buf_length += byte_count;
5205 cifs_fill_unix_set_info(data_offset, args);
5207 pSMB->ByteCount = cpu_to_le16(byte_count);
5208 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5209 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5210 if (rc)
5211 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5213 cifs_buf_release(pSMB);
5214 if (rc == -EAGAIN)
5215 goto setPermsRetry;
5216 return rc;
5219 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5220 const int notify_subdirs, const __u16 netfid,
5221 __u32 filter, struct file *pfile, int multishot,
5222 const struct nls_table *nls_codepage)
5224 int rc = 0;
5225 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5226 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5227 struct dir_notify_req *dnotify_req;
5228 int bytes_returned;
5230 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5231 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5232 (void **) &pSMBr);
5233 if (rc)
5234 return rc;
5236 pSMB->TotalParameterCount = 0 ;
5237 pSMB->TotalDataCount = 0;
5238 pSMB->MaxParameterCount = cpu_to_le32(2);
5239 /* BB find exact data count max from sess structure BB */
5240 pSMB->MaxDataCount = 0; /* same in little endian or be */
5241 /* BB VERIFY verify which is correct for above BB */
5242 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5243 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5245 pSMB->MaxSetupCount = 4;
5246 pSMB->Reserved = 0;
5247 pSMB->ParameterOffset = 0;
5248 pSMB->DataCount = 0;
5249 pSMB->DataOffset = 0;
5250 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5251 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5252 pSMB->ParameterCount = pSMB->TotalParameterCount;
5253 if (notify_subdirs)
5254 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5255 pSMB->Reserved2 = 0;
5256 pSMB->CompletionFilter = cpu_to_le32(filter);
5257 pSMB->Fid = netfid; /* file handle always le */
5258 pSMB->ByteCount = 0;
5260 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5261 (struct smb_hdr *)pSMBr, &bytes_returned,
5262 CIFS_ASYNC_OP);
5263 if (rc) {
5264 cFYI(1, ("Error in Notify = %d", rc));
5265 } else {
5266 /* Add file to outstanding requests */
5267 /* BB change to kmem cache alloc */
5268 dnotify_req = kmalloc(
5269 sizeof(struct dir_notify_req),
5270 GFP_KERNEL);
5271 if (dnotify_req) {
5272 dnotify_req->Pid = pSMB->hdr.Pid;
5273 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5274 dnotify_req->Mid = pSMB->hdr.Mid;
5275 dnotify_req->Tid = pSMB->hdr.Tid;
5276 dnotify_req->Uid = pSMB->hdr.Uid;
5277 dnotify_req->netfid = netfid;
5278 dnotify_req->pfile = pfile;
5279 dnotify_req->filter = filter;
5280 dnotify_req->multishot = multishot;
5281 spin_lock(&GlobalMid_Lock);
5282 list_add_tail(&dnotify_req->lhead,
5283 &GlobalDnotifyReqList);
5284 spin_unlock(&GlobalMid_Lock);
5285 } else
5286 rc = -ENOMEM;
5288 cifs_buf_release(pSMB);
5289 return rc;
5291 #ifdef CONFIG_CIFS_XATTR
5292 ssize_t
5293 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5294 const unsigned char *searchName,
5295 char *EAData, size_t buf_size,
5296 const struct nls_table *nls_codepage, int remap)
5298 /* BB assumes one setup word */
5299 TRANSACTION2_QPI_REQ *pSMB = NULL;
5300 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5301 int rc = 0;
5302 int bytes_returned;
5303 int name_len;
5304 struct fea *temp_fea;
5305 char *temp_ptr;
5306 __u16 params, byte_count;
5308 cFYI(1, ("In Query All EAs path %s", searchName));
5309 QAllEAsRetry:
5310 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5311 (void **) &pSMBr);
5312 if (rc)
5313 return rc;
5315 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5316 name_len =
5317 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5318 PATH_MAX, nls_codepage, remap);
5319 name_len++; /* trailing null */
5320 name_len *= 2;
5321 } else { /* BB improve the check for buffer overruns BB */
5322 name_len = strnlen(searchName, PATH_MAX);
5323 name_len++; /* trailing null */
5324 strncpy(pSMB->FileName, searchName, name_len);
5327 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5328 pSMB->TotalDataCount = 0;
5329 pSMB->MaxParameterCount = cpu_to_le16(2);
5330 /* BB find exact max SMB PDU from sess structure BB */
5331 pSMB->MaxDataCount = cpu_to_le16(4000);
5332 pSMB->MaxSetupCount = 0;
5333 pSMB->Reserved = 0;
5334 pSMB->Flags = 0;
5335 pSMB->Timeout = 0;
5336 pSMB->Reserved2 = 0;
5337 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5338 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5339 pSMB->DataCount = 0;
5340 pSMB->DataOffset = 0;
5341 pSMB->SetupCount = 1;
5342 pSMB->Reserved3 = 0;
5343 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5344 byte_count = params + 1 /* pad */ ;
5345 pSMB->TotalParameterCount = cpu_to_le16(params);
5346 pSMB->ParameterCount = pSMB->TotalParameterCount;
5347 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5348 pSMB->Reserved4 = 0;
5349 pSMB->hdr.smb_buf_length += byte_count;
5350 pSMB->ByteCount = cpu_to_le16(byte_count);
5352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5353 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5354 if (rc) {
5355 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5356 } else { /* decode response */
5357 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5359 /* BB also check enough total bytes returned */
5360 /* BB we need to improve the validity checking
5361 of these trans2 responses */
5362 if (rc || (pSMBr->ByteCount < 4))
5363 rc = -EIO; /* bad smb */
5364 /* else if (pFindData){
5365 memcpy((char *) pFindData,
5366 (char *) &pSMBr->hdr.Protocol +
5367 data_offset, kl);
5368 }*/ else {
5369 /* check that length of list is not more than bcc */
5370 /* check that each entry does not go beyond length
5371 of list */
5372 /* check that each element of each entry does not
5373 go beyond end of list */
5374 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5375 struct fealist *ea_response_data;
5376 rc = 0;
5377 /* validate_trans2_offsets() */
5378 /* BB check if start of smb + data_offset > &bcc+ bcc */
5379 ea_response_data = (struct fealist *)
5380 (((char *) &pSMBr->hdr.Protocol) +
5381 data_offset);
5382 name_len = le32_to_cpu(ea_response_data->list_len);
5383 cFYI(1, ("ea length %d", name_len));
5384 if (name_len <= 8) {
5385 /* returned EA size zeroed at top of function */
5386 cFYI(1, ("empty EA list returned from server"));
5387 } else {
5388 /* account for ea list len */
5389 name_len -= 4;
5390 temp_fea = ea_response_data->list;
5391 temp_ptr = (char *)temp_fea;
5392 while (name_len > 0) {
5393 __u16 value_len;
5394 name_len -= 4;
5395 temp_ptr += 4;
5396 rc += temp_fea->name_len;
5397 /* account for prefix user. and trailing null */
5398 rc = rc + 5 + 1;
5399 if (rc < (int)buf_size) {
5400 memcpy(EAData, "user.", 5);
5401 EAData += 5;
5402 memcpy(EAData, temp_ptr,
5403 temp_fea->name_len);
5404 EAData += temp_fea->name_len;
5405 /* null terminate name */
5406 *EAData = 0;
5407 EAData = EAData + 1;
5408 } else if (buf_size == 0) {
5409 /* skip copy - calc size only */
5410 } else {
5411 /* stop before overrun buffer */
5412 rc = -ERANGE;
5413 break;
5415 name_len -= temp_fea->name_len;
5416 temp_ptr += temp_fea->name_len;
5417 /* account for trailing null */
5418 name_len--;
5419 temp_ptr++;
5420 value_len =
5421 le16_to_cpu(temp_fea->value_len);
5422 name_len -= value_len;
5423 temp_ptr += value_len;
5424 /* BB check that temp_ptr is still
5425 within the SMB BB*/
5427 /* no trailing null to account for
5428 in value len */
5429 /* go on to next EA */
5430 temp_fea = (struct fea *)temp_ptr;
5435 cifs_buf_release(pSMB);
5436 if (rc == -EAGAIN)
5437 goto QAllEAsRetry;
5439 return (ssize_t)rc;
5442 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5443 const unsigned char *searchName, const unsigned char *ea_name,
5444 unsigned char *ea_value, size_t buf_size,
5445 const struct nls_table *nls_codepage, int remap)
5447 TRANSACTION2_QPI_REQ *pSMB = NULL;
5448 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5449 int rc = 0;
5450 int bytes_returned;
5451 int name_len;
5452 struct fea *temp_fea;
5453 char *temp_ptr;
5454 __u16 params, byte_count;
5456 cFYI(1, ("In Query EA path %s", searchName));
5457 QEARetry:
5458 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5459 (void **) &pSMBr);
5460 if (rc)
5461 return rc;
5463 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5464 name_len =
5465 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5466 PATH_MAX, nls_codepage, remap);
5467 name_len++; /* trailing null */
5468 name_len *= 2;
5469 } else { /* BB improve the check for buffer overruns BB */
5470 name_len = strnlen(searchName, PATH_MAX);
5471 name_len++; /* trailing null */
5472 strncpy(pSMB->FileName, searchName, name_len);
5475 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5476 pSMB->TotalDataCount = 0;
5477 pSMB->MaxParameterCount = cpu_to_le16(2);
5478 /* BB find exact max SMB PDU from sess structure BB */
5479 pSMB->MaxDataCount = cpu_to_le16(4000);
5480 pSMB->MaxSetupCount = 0;
5481 pSMB->Reserved = 0;
5482 pSMB->Flags = 0;
5483 pSMB->Timeout = 0;
5484 pSMB->Reserved2 = 0;
5485 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5486 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5487 pSMB->DataCount = 0;
5488 pSMB->DataOffset = 0;
5489 pSMB->SetupCount = 1;
5490 pSMB->Reserved3 = 0;
5491 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5492 byte_count = params + 1 /* pad */ ;
5493 pSMB->TotalParameterCount = cpu_to_le16(params);
5494 pSMB->ParameterCount = pSMB->TotalParameterCount;
5495 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5496 pSMB->Reserved4 = 0;
5497 pSMB->hdr.smb_buf_length += byte_count;
5498 pSMB->ByteCount = cpu_to_le16(byte_count);
5500 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5501 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5502 if (rc) {
5503 cFYI(1, ("Send error in Query EA = %d", rc));
5504 } else { /* decode response */
5505 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5507 /* BB also check enough total bytes returned */
5508 /* BB we need to improve the validity checking
5509 of these trans2 responses */
5510 if (rc || (pSMBr->ByteCount < 4))
5511 rc = -EIO; /* bad smb */
5512 /* else if (pFindData){
5513 memcpy((char *) pFindData,
5514 (char *) &pSMBr->hdr.Protocol +
5515 data_offset, kl);
5516 }*/ else {
5517 /* check that length of list is not more than bcc */
5518 /* check that each entry does not go beyond length
5519 of list */
5520 /* check that each element of each entry does not
5521 go beyond end of list */
5522 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5523 struct fealist *ea_response_data;
5524 rc = -ENODATA;
5525 /* validate_trans2_offsets() */
5526 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5527 ea_response_data = (struct fealist *)
5528 (((char *) &pSMBr->hdr.Protocol) +
5529 data_offset);
5530 name_len = le32_to_cpu(ea_response_data->list_len);
5531 cFYI(1, ("ea length %d", name_len));
5532 if (name_len <= 8) {
5533 /* returned EA size zeroed at top of function */
5534 cFYI(1, ("empty EA list returned from server"));
5535 } else {
5536 /* account for ea list len */
5537 name_len -= 4;
5538 temp_fea = ea_response_data->list;
5539 temp_ptr = (char *)temp_fea;
5540 /* loop through checking if we have a matching
5541 name and then return the associated value */
5542 while (name_len > 0) {
5543 __u16 value_len;
5544 name_len -= 4;
5545 temp_ptr += 4;
5546 value_len =
5547 le16_to_cpu(temp_fea->value_len);
5548 /* BB validate that value_len falls within SMB,
5549 even though maximum for name_len is 255 */
5550 if (memcmp(temp_fea->name, ea_name,
5551 temp_fea->name_len) == 0) {
5552 /* found a match */
5553 rc = value_len;
5554 /* account for prefix user. and trailing null */
5555 if (rc <= (int)buf_size) {
5556 memcpy(ea_value,
5557 temp_fea->name+temp_fea->name_len+1,
5558 rc);
5559 /* ea values, unlike ea
5560 names, are not null
5561 terminated */
5562 } else if (buf_size == 0) {
5563 /* skip copy - calc size only */
5564 } else {
5565 /* stop before overrun buffer */
5566 rc = -ERANGE;
5568 break;
5570 name_len -= temp_fea->name_len;
5571 temp_ptr += temp_fea->name_len;
5572 /* account for trailing null */
5573 name_len--;
5574 temp_ptr++;
5575 name_len -= value_len;
5576 temp_ptr += value_len;
5577 /* No trailing null to account for in
5578 value_len. Go on to next EA */
5579 temp_fea = (struct fea *)temp_ptr;
5584 cifs_buf_release(pSMB);
5585 if (rc == -EAGAIN)
5586 goto QEARetry;
5588 return (ssize_t)rc;
5592 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5593 const char *ea_name, const void *ea_value,
5594 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5595 int remap)
5597 struct smb_com_transaction2_spi_req *pSMB = NULL;
5598 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5599 struct fealist *parm_data;
5600 int name_len;
5601 int rc = 0;
5602 int bytes_returned = 0;
5603 __u16 params, param_offset, byte_count, offset, count;
5605 cFYI(1, ("In SetEA"));
5606 SetEARetry:
5607 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5608 (void **) &pSMBr);
5609 if (rc)
5610 return rc;
5612 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5613 name_len =
5614 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5615 PATH_MAX, nls_codepage, remap);
5616 name_len++; /* trailing null */
5617 name_len *= 2;
5618 } else { /* BB improve the check for buffer overruns BB */
5619 name_len = strnlen(fileName, PATH_MAX);
5620 name_len++; /* trailing null */
5621 strncpy(pSMB->FileName, fileName, name_len);
5624 params = 6 + name_len;
5626 /* done calculating parms using name_len of file name,
5627 now use name_len to calculate length of ea name
5628 we are going to create in the inode xattrs */
5629 if (ea_name == NULL)
5630 name_len = 0;
5631 else
5632 name_len = strnlen(ea_name, 255);
5634 count = sizeof(*parm_data) + ea_value_len + name_len;
5635 pSMB->MaxParameterCount = cpu_to_le16(2);
5636 /* BB find max SMB PDU from sess */
5637 pSMB->MaxDataCount = cpu_to_le16(1000);
5638 pSMB->MaxSetupCount = 0;
5639 pSMB->Reserved = 0;
5640 pSMB->Flags = 0;
5641 pSMB->Timeout = 0;
5642 pSMB->Reserved2 = 0;
5643 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5644 InformationLevel) - 4;
5645 offset = param_offset + params;
5646 pSMB->InformationLevel =
5647 cpu_to_le16(SMB_SET_FILE_EA);
5649 parm_data =
5650 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5651 offset);
5652 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5653 pSMB->DataOffset = cpu_to_le16(offset);
5654 pSMB->SetupCount = 1;
5655 pSMB->Reserved3 = 0;
5656 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5657 byte_count = 3 /* pad */ + params + count;
5658 pSMB->DataCount = cpu_to_le16(count);
5659 parm_data->list_len = cpu_to_le32(count);
5660 parm_data->list[0].EA_flags = 0;
5661 /* we checked above that name len is less than 255 */
5662 parm_data->list[0].name_len = (__u8)name_len;
5663 /* EA names are always ASCII */
5664 if (ea_name)
5665 strncpy(parm_data->list[0].name, ea_name, name_len);
5666 parm_data->list[0].name[name_len] = 0;
5667 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5668 /* caller ensures that ea_value_len is less than 64K but
5669 we need to ensure that it fits within the smb */
5671 /*BB add length check to see if it would fit in
5672 negotiated SMB buffer size BB */
5673 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5674 if (ea_value_len)
5675 memcpy(parm_data->list[0].name+name_len+1,
5676 ea_value, ea_value_len);
5678 pSMB->TotalDataCount = pSMB->DataCount;
5679 pSMB->ParameterCount = cpu_to_le16(params);
5680 pSMB->TotalParameterCount = pSMB->ParameterCount;
5681 pSMB->Reserved4 = 0;
5682 pSMB->hdr.smb_buf_length += byte_count;
5683 pSMB->ByteCount = cpu_to_le16(byte_count);
5684 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5685 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5686 if (rc)
5687 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5689 cifs_buf_release(pSMB);
5691 if (rc == -EAGAIN)
5692 goto SetEARetry;
5694 return rc;
5697 #endif