netxen: Fix Unlikely(x) > y
[linux-2.6/mini2440.git] / fs / cifs / cifssmb.c
blob301e307e127900e71eb1291ae80c050a03d8aa98
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;
98 write_unlock(&GlobalSMBSeslock);
99 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
100 to this tcon */
103 /* reconnect the socket, tcon, and smb session if needed */
104 static int
105 cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
107 int rc = 0;
108 struct cifsSesInfo *ses;
109 struct TCP_Server_Info *server;
110 struct nls_table *nls_codepage;
113 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
114 * tcp and smb session status done differently for those three - in the
115 * calling routine
117 if (!tcon)
118 return 0;
120 ses = tcon->ses;
121 server = ses->server;
124 * only tree disconnect, open, and write, (and ulogoff which does not
125 * have tcon) are allowed as we start force umount
127 if (tcon->tidStatus == CifsExiting) {
128 if (smb_command != SMB_COM_WRITE_ANDX &&
129 smb_command != SMB_COM_OPEN_ANDX &&
130 smb_command != SMB_COM_TREE_DISCONNECT) {
131 cFYI(1, ("can not send cmd %d while umounting",
132 smb_command));
133 return -ENODEV;
137 if (ses->status == CifsExiting)
138 return -EIO;
141 * Give demultiplex thread up to 10 seconds to reconnect, should be
142 * greater than cifs socket timeout which is 7 seconds
144 while (server->tcpStatus == CifsNeedReconnect) {
145 wait_event_interruptible_timeout(server->response_q,
146 (server->tcpStatus == CifsGood), 10 * HZ);
148 /* is TCP session is reestablished now ?*/
149 if (server->tcpStatus != CifsNeedReconnect)
150 break;
153 * on "soft" mounts we wait once. Hard mounts keep
154 * retrying until process is killed or server comes
155 * back on-line
157 if (!tcon->retry || ses->status == CifsExiting) {
158 cFYI(1, ("gave up waiting on reconnect in smb_init"));
159 return -EHOSTDOWN;
163 if (!ses->need_reconnect && !tcon->need_reconnect)
164 return 0;
166 nls_codepage = load_nls_default();
169 * need to prevent multiple threads trying to simultaneously
170 * reconnect the same SMB session
172 down(&ses->sesSem);
173 if (ses->need_reconnect)
174 rc = cifs_setup_session(0, ses, nls_codepage);
176 /* do we need to reconnect tcon? */
177 if (rc || !tcon->need_reconnect) {
178 up(&ses->sesSem);
179 goto out;
182 mark_open_files_invalid(tcon);
183 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
184 up(&ses->sesSem);
185 cFYI(1, ("reconnect tcon rc = %d", rc));
187 if (rc)
188 goto out;
191 * FIXME: check if wsize needs updated due to negotiated smb buffer
192 * size shrinking
194 atomic_inc(&tconInfoReconnectCount);
196 /* tell server Unix caps we support */
197 if (ses->capabilities & CAP_UNIX)
198 reset_cifs_unix_caps(0, tcon, NULL, NULL);
201 * Removed call to reopen open files here. It is safer (and faster) to
202 * reopen files one at a time as needed in read and write.
204 * FIXME: what about file locks? don't we need to reclaim them ASAP?
207 out:
209 * Check if handle based operation so we know whether we can continue
210 * or not without returning to caller to reset file handle
212 switch (smb_command) {
213 case SMB_COM_READ_ANDX:
214 case SMB_COM_WRITE_ANDX:
215 case SMB_COM_CLOSE:
216 case SMB_COM_FIND_CLOSE2:
217 case SMB_COM_LOCKING_ANDX:
218 rc = -EAGAIN;
221 unload_nls(nls_codepage);
222 return rc;
225 /* Allocate and return pointer to an SMB request buffer, and set basic
226 SMB information in the SMB header. If the return code is zero, this
227 function must have filled in request_buf pointer */
228 static int
229 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
230 void **request_buf)
232 int rc = 0;
234 rc = cifs_reconnect_tcon(tcon, smb_command);
235 if (rc)
236 return rc;
238 *request_buf = cifs_small_buf_get();
239 if (*request_buf == NULL) {
240 /* BB should we add a retry in here if not a writepage? */
241 return -ENOMEM;
244 header_assemble((struct smb_hdr *) *request_buf, smb_command,
245 tcon, wct);
247 if (tcon != NULL)
248 cifs_stats_inc(&tcon->num_smbs_sent);
250 return rc;
254 small_smb_init_no_tc(const int smb_command, const int wct,
255 struct cifsSesInfo *ses, void **request_buf)
257 int rc;
258 struct smb_hdr *buffer;
260 rc = small_smb_init(smb_command, wct, NULL, request_buf);
261 if (rc)
262 return rc;
264 buffer = (struct smb_hdr *)*request_buf;
265 buffer->Mid = GetNextMid(ses->server);
266 if (ses->capabilities & CAP_UNICODE)
267 buffer->Flags2 |= SMBFLG2_UNICODE;
268 if (ses->capabilities & CAP_STATUS32)
269 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
271 /* uid, tid can stay at zero as set in header assemble */
273 /* BB add support for turning on the signing when
274 this function is used after 1st of session setup requests */
276 return rc;
279 /* If the return code is zero, this function must fill in request_buf pointer */
280 static int
281 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
282 void **request_buf /* returned */ ,
283 void **response_buf /* returned */ )
285 int rc = 0;
287 rc = cifs_reconnect_tcon(tcon, smb_command);
288 if (rc)
289 return rc;
291 *request_buf = cifs_buf_get();
292 if (*request_buf == NULL) {
293 /* BB should we add a retry in here if not a writepage? */
294 return -ENOMEM;
296 /* Although the original thought was we needed the response buf for */
297 /* potential retries of smb operations it turns out we can determine */
298 /* from the mid flags when the request buffer can be resent without */
299 /* having to use a second distinct buffer for the response */
300 if (response_buf)
301 *response_buf = *request_buf;
303 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
304 wct);
306 if (tcon != NULL)
307 cifs_stats_inc(&tcon->num_smbs_sent);
309 return rc;
312 static int validate_t2(struct smb_t2_rsp *pSMB)
314 int rc = -EINVAL;
315 int total_size;
316 char *pBCC;
318 /* check for plausible wct, bcc and t2 data and parm sizes */
319 /* check for parm and data offset going beyond end of smb */
320 if (pSMB->hdr.WordCount >= 10) {
321 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
322 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
323 /* check that bcc is at least as big as parms + data */
324 /* check that bcc is less than negotiated smb buffer */
325 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
326 if (total_size < 512) {
327 total_size +=
328 le16_to_cpu(pSMB->t2_rsp.DataCount);
329 /* BCC le converted in SendReceive */
330 pBCC = (pSMB->hdr.WordCount * 2) +
331 sizeof(struct smb_hdr) +
332 (char *)pSMB;
333 if ((total_size <= (*(u16 *)pBCC)) &&
334 (total_size <
335 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
336 return 0;
341 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
342 sizeof(struct smb_t2_rsp) + 16);
343 return rc;
346 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
348 NEGOTIATE_REQ *pSMB;
349 NEGOTIATE_RSP *pSMBr;
350 int rc = 0;
351 int bytes_returned;
352 int i;
353 struct TCP_Server_Info *server;
354 u16 count;
355 unsigned int secFlags;
356 u16 dialect;
358 if (ses->server)
359 server = ses->server;
360 else {
361 rc = -EIO;
362 return rc;
364 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
365 (void **) &pSMB, (void **) &pSMBr);
366 if (rc)
367 return rc;
369 /* if any of auth flags (ie not sign or seal) are overriden use them */
370 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
371 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
372 else /* if override flags set only sign/seal OR them with global auth */
373 secFlags = extended_security | ses->overrideSecFlg;
375 cFYI(1, ("secFlags 0x%x", secFlags));
377 pSMB->hdr.Mid = GetNextMid(server);
378 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
380 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
381 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
382 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
383 cFYI(1, ("Kerberos only mechanism, enable extended security"));
384 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
386 #ifdef CONFIG_CIFS_EXPERIMENTAL
387 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
388 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
389 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
390 cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
391 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
393 #endif
395 count = 0;
396 for (i = 0; i < CIFS_NUM_PROT; i++) {
397 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
398 count += strlen(protocols[i].name) + 1;
399 /* null at end of source and target buffers anyway */
401 pSMB->hdr.smb_buf_length += count;
402 pSMB->ByteCount = cpu_to_le16(count);
404 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
405 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
406 if (rc != 0)
407 goto neg_err_exit;
409 dialect = le16_to_cpu(pSMBr->DialectIndex);
410 cFYI(1, ("Dialect: %d", dialect));
411 /* Check wct = 1 error case */
412 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
413 /* core returns wct = 1, but we do not ask for core - otherwise
414 small wct just comes when dialect index is -1 indicating we
415 could not negotiate a common dialect */
416 rc = -EOPNOTSUPP;
417 goto neg_err_exit;
418 #ifdef CONFIG_CIFS_WEAK_PW_HASH
419 } else if ((pSMBr->hdr.WordCount == 13)
420 && ((dialect == LANMAN_PROT)
421 || (dialect == LANMAN2_PROT))) {
422 __s16 tmp;
423 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
425 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
426 (secFlags & CIFSSEC_MAY_PLNTXT))
427 server->secType = LANMAN;
428 else {
429 cERROR(1, ("mount failed weak security disabled"
430 " in /proc/fs/cifs/SecurityFlags"));
431 rc = -EOPNOTSUPP;
432 goto neg_err_exit;
434 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
435 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
436 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
437 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
438 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
439 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
440 /* even though we do not use raw we might as well set this
441 accurately, in case we ever find a need for it */
442 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
443 server->max_rw = 0xFF00;
444 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
445 } else {
446 server->max_rw = 0;/* do not need to use raw anyway */
447 server->capabilities = CAP_MPX_MODE;
449 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
450 if (tmp == -1) {
451 /* OS/2 often does not set timezone therefore
452 * we must use server time to calc time zone.
453 * Could deviate slightly from the right zone.
454 * Smallest defined timezone difference is 15 minutes
455 * (i.e. Nepal). Rounding up/down is done to match
456 * this requirement.
458 int val, seconds, remain, result;
459 struct timespec ts, utc;
460 utc = CURRENT_TIME;
461 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
462 rsp->SrvTime.Time, 0);
463 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
464 (int)ts.tv_sec, (int)utc.tv_sec,
465 (int)(utc.tv_sec - ts.tv_sec)));
466 val = (int)(utc.tv_sec - ts.tv_sec);
467 seconds = abs(val);
468 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
469 remain = seconds % MIN_TZ_ADJ;
470 if (remain >= (MIN_TZ_ADJ / 2))
471 result += MIN_TZ_ADJ;
472 if (val < 0)
473 result = -result;
474 server->timeAdj = result;
475 } else {
476 server->timeAdj = (int)tmp;
477 server->timeAdj *= 60; /* also in seconds */
479 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
482 /* BB get server time for time conversions and add
483 code to use it and timezone since this is not UTC */
485 if (rsp->EncryptionKeyLength ==
486 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
487 memcpy(server->cryptKey, rsp->EncryptionKey,
488 CIFS_CRYPTO_KEY_SIZE);
489 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
490 rc = -EIO; /* need cryptkey unless plain text */
491 goto neg_err_exit;
494 cFYI(1, ("LANMAN negotiated"));
495 /* we will not end up setting signing flags - as no signing
496 was in LANMAN and server did not return the flags on */
497 goto signing_check;
498 #else /* weak security disabled */
499 } else if (pSMBr->hdr.WordCount == 13) {
500 cERROR(1, ("mount failed, cifs module not built "
501 "with CIFS_WEAK_PW_HASH support"));
502 rc = -EOPNOTSUPP;
503 #endif /* WEAK_PW_HASH */
504 goto neg_err_exit;
505 } else if (pSMBr->hdr.WordCount != 17) {
506 /* unknown wct */
507 rc = -EOPNOTSUPP;
508 goto neg_err_exit;
510 /* else wct == 17 NTLM */
511 server->secMode = pSMBr->SecurityMode;
512 if ((server->secMode & SECMODE_USER) == 0)
513 cFYI(1, ("share mode security"));
515 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
516 #ifdef CONFIG_CIFS_WEAK_PW_HASH
517 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
518 #endif /* CIFS_WEAK_PW_HASH */
519 cERROR(1, ("Server requests plain text password"
520 " but client support disabled"));
522 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
523 server->secType = NTLMv2;
524 else if (secFlags & CIFSSEC_MAY_NTLM)
525 server->secType = NTLM;
526 else if (secFlags & CIFSSEC_MAY_NTLMV2)
527 server->secType = NTLMv2;
528 else if (secFlags & CIFSSEC_MAY_KRB5)
529 server->secType = Kerberos;
530 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
531 server->secType = RawNTLMSSP;
532 else if (secFlags & CIFSSEC_MAY_LANMAN)
533 server->secType = LANMAN;
534 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
535 else if (secFlags & CIFSSEC_MAY_PLNTXT)
536 server->secType = ??
537 #endif */
538 else {
539 rc = -EOPNOTSUPP;
540 cERROR(1, ("Invalid security type"));
541 goto neg_err_exit;
543 /* else ... any others ...? */
545 /* one byte, so no need to convert this or EncryptionKeyLen from
546 little endian */
547 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
548 /* probably no need to store and check maxvcs */
549 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
550 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
551 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
552 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
553 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
554 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
555 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
556 server->timeAdj *= 60;
557 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
558 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
559 CIFS_CRYPTO_KEY_SIZE);
560 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
561 && (pSMBr->EncryptionKeyLength == 0)) {
562 /* decode security blob */
563 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
564 rc = -EIO; /* no crypt key only if plain text pwd */
565 goto neg_err_exit;
568 /* BB might be helpful to save off the domain of server here */
570 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
571 (server->capabilities & CAP_EXTENDED_SECURITY)) {
572 count = pSMBr->ByteCount;
573 if (count < 16) {
574 rc = -EIO;
575 goto neg_err_exit;
577 read_lock(&cifs_tcp_ses_lock);
578 if (server->srv_count > 1) {
579 read_unlock(&cifs_tcp_ses_lock);
580 if (memcmp(server->server_GUID,
581 pSMBr->u.extended_response.
582 GUID, 16) != 0) {
583 cFYI(1, ("server UID changed"));
584 memcpy(server->server_GUID,
585 pSMBr->u.extended_response.GUID,
586 16);
588 } else {
589 read_unlock(&cifs_tcp_ses_lock);
590 memcpy(server->server_GUID,
591 pSMBr->u.extended_response.GUID, 16);
594 if (count == 16) {
595 server->secType = RawNTLMSSP;
596 } else {
597 rc = decode_negTokenInit(pSMBr->u.extended_response.
598 SecurityBlob,
599 count - 16,
600 &server->secType);
601 if (rc == 1)
602 rc = 0;
603 else
604 rc = -EINVAL;
606 } else
607 server->capabilities &= ~CAP_EXTENDED_SECURITY;
609 #ifdef CONFIG_CIFS_WEAK_PW_HASH
610 signing_check:
611 #endif
612 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
613 /* MUST_SIGN already includes the MAY_SIGN FLAG
614 so if this is zero it means that signing is disabled */
615 cFYI(1, ("Signing disabled"));
616 if (server->secMode & SECMODE_SIGN_REQUIRED) {
617 cERROR(1, ("Server requires "
618 "packet signing to be enabled in "
619 "/proc/fs/cifs/SecurityFlags."));
620 rc = -EOPNOTSUPP;
622 server->secMode &=
623 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
624 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
625 /* signing required */
626 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
627 if ((server->secMode &
628 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
629 cERROR(1,
630 ("signing required but server lacks support"));
631 rc = -EOPNOTSUPP;
632 } else
633 server->secMode |= SECMODE_SIGN_REQUIRED;
634 } else {
635 /* signing optional ie CIFSSEC_MAY_SIGN */
636 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
637 server->secMode &=
638 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
641 neg_err_exit:
642 cifs_buf_release(pSMB);
644 cFYI(1, ("negprot rc %d", rc));
645 return rc;
649 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
651 struct smb_hdr *smb_buffer;
652 int rc = 0;
654 cFYI(1, ("In tree disconnect"));
656 /* BB: do we need to check this? These should never be NULL. */
657 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
658 return -EIO;
661 * No need to return error on this operation if tid invalidated and
662 * closed on server already e.g. due to tcp session crashing. Also,
663 * the tcon is no longer on the list, so no need to take lock before
664 * checking this.
666 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
667 return 0;
669 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
670 (void **)&smb_buffer);
671 if (rc)
672 return rc;
674 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
675 if (rc)
676 cFYI(1, ("Tree disconnect failed %d", rc));
678 /* No need to return error on this operation if tid invalidated and
679 closed on server already e.g. due to tcp session crashing */
680 if (rc == -EAGAIN)
681 rc = 0;
683 return rc;
687 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
689 LOGOFF_ANDX_REQ *pSMB;
690 int rc = 0;
692 cFYI(1, ("In SMBLogoff for session disconnect"));
695 * BB: do we need to check validity of ses and server? They should
696 * always be valid since we have an active reference. If not, that
697 * should probably be a BUG()
699 if (!ses || !ses->server)
700 return -EIO;
702 down(&ses->sesSem);
703 if (ses->need_reconnect)
704 goto session_already_dead; /* no need to send SMBlogoff if uid
705 already closed due to reconnect */
706 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
707 if (rc) {
708 up(&ses->sesSem);
709 return rc;
712 pSMB->hdr.Mid = GetNextMid(ses->server);
714 if (ses->server->secMode &
715 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
716 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
718 pSMB->hdr.Uid = ses->Suid;
720 pSMB->AndXCommand = 0xFF;
721 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
722 session_already_dead:
723 up(&ses->sesSem);
725 /* if session dead then we do not need to do ulogoff,
726 since server closed smb session, no sense reporting
727 error */
728 if (rc == -EAGAIN)
729 rc = 0;
730 return rc;
734 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
735 __u16 type, const struct nls_table *nls_codepage, int remap)
737 TRANSACTION2_SPI_REQ *pSMB = NULL;
738 TRANSACTION2_SPI_RSP *pSMBr = NULL;
739 struct unlink_psx_rq *pRqD;
740 int name_len;
741 int rc = 0;
742 int bytes_returned = 0;
743 __u16 params, param_offset, offset, byte_count;
745 cFYI(1, ("In POSIX delete"));
746 PsxDelete:
747 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
748 (void **) &pSMBr);
749 if (rc)
750 return rc;
752 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
753 name_len =
754 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
755 PATH_MAX, nls_codepage, remap);
756 name_len++; /* trailing null */
757 name_len *= 2;
758 } else { /* BB add path length overrun check */
759 name_len = strnlen(fileName, PATH_MAX);
760 name_len++; /* trailing null */
761 strncpy(pSMB->FileName, fileName, name_len);
764 params = 6 + name_len;
765 pSMB->MaxParameterCount = cpu_to_le16(2);
766 pSMB->MaxDataCount = 0; /* BB double check this with jra */
767 pSMB->MaxSetupCount = 0;
768 pSMB->Reserved = 0;
769 pSMB->Flags = 0;
770 pSMB->Timeout = 0;
771 pSMB->Reserved2 = 0;
772 param_offset = offsetof(struct smb_com_transaction2_spi_req,
773 InformationLevel) - 4;
774 offset = param_offset + params;
776 /* Setup pointer to Request Data (inode type) */
777 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
778 pRqD->type = cpu_to_le16(type);
779 pSMB->ParameterOffset = cpu_to_le16(param_offset);
780 pSMB->DataOffset = cpu_to_le16(offset);
781 pSMB->SetupCount = 1;
782 pSMB->Reserved3 = 0;
783 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
784 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
786 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
787 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
788 pSMB->ParameterCount = cpu_to_le16(params);
789 pSMB->TotalParameterCount = pSMB->ParameterCount;
790 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
791 pSMB->Reserved4 = 0;
792 pSMB->hdr.smb_buf_length += byte_count;
793 pSMB->ByteCount = cpu_to_le16(byte_count);
794 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
795 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
796 if (rc)
797 cFYI(1, ("Posix delete returned %d", rc));
798 cifs_buf_release(pSMB);
800 cifs_stats_inc(&tcon->num_deletes);
802 if (rc == -EAGAIN)
803 goto PsxDelete;
805 return rc;
809 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
810 const struct nls_table *nls_codepage, int remap)
812 DELETE_FILE_REQ *pSMB = NULL;
813 DELETE_FILE_RSP *pSMBr = NULL;
814 int rc = 0;
815 int bytes_returned;
816 int name_len;
818 DelFileRetry:
819 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
820 (void **) &pSMBr);
821 if (rc)
822 return rc;
824 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
825 name_len =
826 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
827 PATH_MAX, nls_codepage, remap);
828 name_len++; /* trailing null */
829 name_len *= 2;
830 } else { /* BB improve check for buffer overruns BB */
831 name_len = strnlen(fileName, PATH_MAX);
832 name_len++; /* trailing null */
833 strncpy(pSMB->fileName, fileName, name_len);
835 pSMB->SearchAttributes =
836 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
837 pSMB->BufferFormat = 0x04;
838 pSMB->hdr.smb_buf_length += name_len + 1;
839 pSMB->ByteCount = cpu_to_le16(name_len + 1);
840 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
842 cifs_stats_inc(&tcon->num_deletes);
843 if (rc)
844 cFYI(1, ("Error in RMFile = %d", rc));
846 cifs_buf_release(pSMB);
847 if (rc == -EAGAIN)
848 goto DelFileRetry;
850 return rc;
854 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
855 const struct nls_table *nls_codepage, int remap)
857 DELETE_DIRECTORY_REQ *pSMB = NULL;
858 DELETE_DIRECTORY_RSP *pSMBr = NULL;
859 int rc = 0;
860 int bytes_returned;
861 int name_len;
863 cFYI(1, ("In CIFSSMBRmDir"));
864 RmDirRetry:
865 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
866 (void **) &pSMBr);
867 if (rc)
868 return rc;
870 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
871 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
872 PATH_MAX, nls_codepage, remap);
873 name_len++; /* trailing null */
874 name_len *= 2;
875 } else { /* BB improve check for buffer overruns BB */
876 name_len = strnlen(dirName, PATH_MAX);
877 name_len++; /* trailing null */
878 strncpy(pSMB->DirName, dirName, name_len);
881 pSMB->BufferFormat = 0x04;
882 pSMB->hdr.smb_buf_length += name_len + 1;
883 pSMB->ByteCount = cpu_to_le16(name_len + 1);
884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
886 cifs_stats_inc(&tcon->num_rmdirs);
887 if (rc)
888 cFYI(1, ("Error in RMDir = %d", rc));
890 cifs_buf_release(pSMB);
891 if (rc == -EAGAIN)
892 goto RmDirRetry;
893 return rc;
897 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
898 const char *name, const struct nls_table *nls_codepage, int remap)
900 int rc = 0;
901 CREATE_DIRECTORY_REQ *pSMB = NULL;
902 CREATE_DIRECTORY_RSP *pSMBr = NULL;
903 int bytes_returned;
904 int name_len;
906 cFYI(1, ("In CIFSSMBMkDir"));
907 MkDirRetry:
908 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
909 (void **) &pSMBr);
910 if (rc)
911 return rc;
913 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
914 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
915 PATH_MAX, nls_codepage, remap);
916 name_len++; /* trailing null */
917 name_len *= 2;
918 } else { /* BB improve check for buffer overruns BB */
919 name_len = strnlen(name, PATH_MAX);
920 name_len++; /* trailing null */
921 strncpy(pSMB->DirName, name, name_len);
924 pSMB->BufferFormat = 0x04;
925 pSMB->hdr.smb_buf_length += name_len + 1;
926 pSMB->ByteCount = cpu_to_le16(name_len + 1);
927 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
928 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
929 cifs_stats_inc(&tcon->num_mkdirs);
930 if (rc)
931 cFYI(1, ("Error in Mkdir = %d", rc));
933 cifs_buf_release(pSMB);
934 if (rc == -EAGAIN)
935 goto MkDirRetry;
936 return rc;
940 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
941 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
942 __u32 *pOplock, const char *name,
943 const struct nls_table *nls_codepage, int remap)
945 TRANSACTION2_SPI_REQ *pSMB = NULL;
946 TRANSACTION2_SPI_RSP *pSMBr = NULL;
947 int name_len;
948 int rc = 0;
949 int bytes_returned = 0;
950 __u16 params, param_offset, offset, byte_count, count;
951 OPEN_PSX_REQ *pdata;
952 OPEN_PSX_RSP *psx_rsp;
954 cFYI(1, ("In POSIX Create"));
955 PsxCreat:
956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
957 (void **) &pSMBr);
958 if (rc)
959 return rc;
961 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
962 name_len =
963 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
964 PATH_MAX, nls_codepage, remap);
965 name_len++; /* trailing null */
966 name_len *= 2;
967 } else { /* BB improve the check for buffer overruns BB */
968 name_len = strnlen(name, PATH_MAX);
969 name_len++; /* trailing null */
970 strncpy(pSMB->FileName, name, name_len);
973 params = 6 + name_len;
974 count = sizeof(OPEN_PSX_REQ);
975 pSMB->MaxParameterCount = cpu_to_le16(2);
976 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
977 pSMB->MaxSetupCount = 0;
978 pSMB->Reserved = 0;
979 pSMB->Flags = 0;
980 pSMB->Timeout = 0;
981 pSMB->Reserved2 = 0;
982 param_offset = offsetof(struct smb_com_transaction2_spi_req,
983 InformationLevel) - 4;
984 offset = param_offset + params;
985 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
986 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
987 pdata->Permissions = cpu_to_le64(mode);
988 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
989 pdata->OpenFlags = cpu_to_le32(*pOplock);
990 pSMB->ParameterOffset = cpu_to_le16(param_offset);
991 pSMB->DataOffset = cpu_to_le16(offset);
992 pSMB->SetupCount = 1;
993 pSMB->Reserved3 = 0;
994 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
995 byte_count = 3 /* pad */ + params + count;
997 pSMB->DataCount = cpu_to_le16(count);
998 pSMB->ParameterCount = cpu_to_le16(params);
999 pSMB->TotalDataCount = pSMB->DataCount;
1000 pSMB->TotalParameterCount = pSMB->ParameterCount;
1001 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1002 pSMB->Reserved4 = 0;
1003 pSMB->hdr.smb_buf_length += byte_count;
1004 pSMB->ByteCount = cpu_to_le16(byte_count);
1005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1007 if (rc) {
1008 cFYI(1, ("Posix create returned %d", rc));
1009 goto psx_create_err;
1012 cFYI(1, ("copying inode info"));
1013 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1015 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1016 rc = -EIO; /* bad smb */
1017 goto psx_create_err;
1020 /* copy return information to pRetData */
1021 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1022 + le16_to_cpu(pSMBr->t2.DataOffset));
1024 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1025 if (netfid)
1026 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1027 /* Let caller know file was created so we can set the mode. */
1028 /* Do we care about the CreateAction in any other cases? */
1029 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1030 *pOplock |= CIFS_CREATE_ACTION;
1031 /* check to make sure response data is there */
1032 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1033 pRetData->Type = cpu_to_le32(-1); /* unknown */
1034 cFYI(DBG2, ("unknown type"));
1035 } else {
1036 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1037 + sizeof(FILE_UNIX_BASIC_INFO)) {
1038 cERROR(1, ("Open response data too small"));
1039 pRetData->Type = cpu_to_le32(-1);
1040 goto psx_create_err;
1042 memcpy((char *) pRetData,
1043 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1044 sizeof(FILE_UNIX_BASIC_INFO));
1047 psx_create_err:
1048 cifs_buf_release(pSMB);
1050 if (posix_flags & SMB_O_DIRECTORY)
1051 cifs_stats_inc(&tcon->num_posixmkdirs);
1052 else
1053 cifs_stats_inc(&tcon->num_posixopens);
1055 if (rc == -EAGAIN)
1056 goto PsxCreat;
1058 return rc;
1061 static __u16 convert_disposition(int disposition)
1063 __u16 ofun = 0;
1065 switch (disposition) {
1066 case FILE_SUPERSEDE:
1067 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1068 break;
1069 case FILE_OPEN:
1070 ofun = SMBOPEN_OAPPEND;
1071 break;
1072 case FILE_CREATE:
1073 ofun = SMBOPEN_OCREATE;
1074 break;
1075 case FILE_OPEN_IF:
1076 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1077 break;
1078 case FILE_OVERWRITE:
1079 ofun = SMBOPEN_OTRUNC;
1080 break;
1081 case FILE_OVERWRITE_IF:
1082 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1083 break;
1084 default:
1085 cFYI(1, ("unknown disposition %d", disposition));
1086 ofun = SMBOPEN_OAPPEND; /* regular open */
1088 return ofun;
1091 static int
1092 access_flags_to_smbopen_mode(const int access_flags)
1094 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1096 if (masked_flags == GENERIC_READ)
1097 return SMBOPEN_READ;
1098 else if (masked_flags == GENERIC_WRITE)
1099 return SMBOPEN_WRITE;
1101 /* just go for read/write */
1102 return SMBOPEN_READWRITE;
1106 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1107 const char *fileName, const int openDisposition,
1108 const int access_flags, const int create_options, __u16 *netfid,
1109 int *pOplock, FILE_ALL_INFO *pfile_info,
1110 const struct nls_table *nls_codepage, int remap)
1112 int rc = -EACCES;
1113 OPENX_REQ *pSMB = NULL;
1114 OPENX_RSP *pSMBr = NULL;
1115 int bytes_returned;
1116 int name_len;
1117 __u16 count;
1119 OldOpenRetry:
1120 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1121 (void **) &pSMBr);
1122 if (rc)
1123 return rc;
1125 pSMB->AndXCommand = 0xFF; /* none */
1127 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1128 count = 1; /* account for one byte pad to word boundary */
1129 name_len =
1130 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1131 fileName, PATH_MAX, nls_codepage, remap);
1132 name_len++; /* trailing null */
1133 name_len *= 2;
1134 } else { /* BB improve check for buffer overruns BB */
1135 count = 0; /* no pad */
1136 name_len = strnlen(fileName, PATH_MAX);
1137 name_len++; /* trailing null */
1138 strncpy(pSMB->fileName, fileName, name_len);
1140 if (*pOplock & REQ_OPLOCK)
1141 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1142 else if (*pOplock & REQ_BATCHOPLOCK)
1143 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1145 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1146 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1147 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1148 /* set file as system file if special file such
1149 as fifo and server expecting SFU style and
1150 no Unix extensions */
1152 if (create_options & CREATE_OPTION_SPECIAL)
1153 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1154 else /* BB FIXME BB */
1155 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1157 if (create_options & CREATE_OPTION_READONLY)
1158 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1160 /* BB FIXME BB */
1161 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1162 CREATE_OPTIONS_MASK); */
1163 /* BB FIXME END BB */
1165 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1166 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1167 count += name_len;
1168 pSMB->hdr.smb_buf_length += count;
1170 pSMB->ByteCount = cpu_to_le16(count);
1171 /* long_op set to 1 to allow for oplock break timeouts */
1172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1173 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1174 cifs_stats_inc(&tcon->num_opens);
1175 if (rc) {
1176 cFYI(1, ("Error in Open = %d", rc));
1177 } else {
1178 /* BB verify if wct == 15 */
1180 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1182 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1183 /* Let caller know file was created so we can set the mode. */
1184 /* Do we care about the CreateAction in any other cases? */
1185 /* BB FIXME BB */
1186 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1187 *pOplock |= CIFS_CREATE_ACTION; */
1188 /* BB FIXME END */
1190 if (pfile_info) {
1191 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1192 pfile_info->LastAccessTime = 0; /* BB fixme */
1193 pfile_info->LastWriteTime = 0; /* BB fixme */
1194 pfile_info->ChangeTime = 0; /* BB fixme */
1195 pfile_info->Attributes =
1196 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1197 /* the file_info buf is endian converted by caller */
1198 pfile_info->AllocationSize =
1199 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1200 pfile_info->EndOfFile = pfile_info->AllocationSize;
1201 pfile_info->NumberOfLinks = cpu_to_le32(1);
1202 pfile_info->DeletePending = 0;
1206 cifs_buf_release(pSMB);
1207 if (rc == -EAGAIN)
1208 goto OldOpenRetry;
1209 return rc;
1213 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1214 const char *fileName, const int openDisposition,
1215 const int access_flags, const int create_options, __u16 *netfid,
1216 int *pOplock, FILE_ALL_INFO *pfile_info,
1217 const struct nls_table *nls_codepage, int remap)
1219 int rc = -EACCES;
1220 OPEN_REQ *pSMB = NULL;
1221 OPEN_RSP *pSMBr = NULL;
1222 int bytes_returned;
1223 int name_len;
1224 __u16 count;
1226 openRetry:
1227 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1228 (void **) &pSMBr);
1229 if (rc)
1230 return rc;
1232 pSMB->AndXCommand = 0xFF; /* none */
1234 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1235 count = 1; /* account for one byte pad to word boundary */
1236 name_len =
1237 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1238 fileName, PATH_MAX, nls_codepage, remap);
1239 name_len++; /* trailing null */
1240 name_len *= 2;
1241 pSMB->NameLength = cpu_to_le16(name_len);
1242 } else { /* BB improve check for buffer overruns BB */
1243 count = 0; /* no pad */
1244 name_len = strnlen(fileName, PATH_MAX);
1245 name_len++; /* trailing null */
1246 pSMB->NameLength = cpu_to_le16(name_len);
1247 strncpy(pSMB->fileName, fileName, name_len);
1249 if (*pOplock & REQ_OPLOCK)
1250 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1251 else if (*pOplock & REQ_BATCHOPLOCK)
1252 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1253 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1254 pSMB->AllocationSize = 0;
1255 /* set file as system file if special file such
1256 as fifo and server expecting SFU style and
1257 no Unix extensions */
1258 if (create_options & CREATE_OPTION_SPECIAL)
1259 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1260 else
1261 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1263 /* XP does not handle ATTR_POSIX_SEMANTICS */
1264 /* but it helps speed up case sensitive checks for other
1265 servers such as Samba */
1266 if (tcon->ses->capabilities & CAP_UNIX)
1267 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1269 if (create_options & CREATE_OPTION_READONLY)
1270 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1272 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1273 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1274 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1275 /* BB Expirement with various impersonation levels and verify */
1276 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1277 pSMB->SecurityFlags =
1278 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1280 count += name_len;
1281 pSMB->hdr.smb_buf_length += count;
1283 pSMB->ByteCount = cpu_to_le16(count);
1284 /* long_op set to 1 to allow for oplock break timeouts */
1285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1286 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1287 cifs_stats_inc(&tcon->num_opens);
1288 if (rc) {
1289 cFYI(1, ("Error in Open = %d", rc));
1290 } else {
1291 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1292 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1293 /* Let caller know file was created so we can set the mode. */
1294 /* Do we care about the CreateAction in any other cases? */
1295 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1296 *pOplock |= CIFS_CREATE_ACTION;
1297 if (pfile_info) {
1298 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1299 36 /* CreationTime to Attributes */);
1300 /* the file_info buf is endian converted by caller */
1301 pfile_info->AllocationSize = pSMBr->AllocationSize;
1302 pfile_info->EndOfFile = pSMBr->EndOfFile;
1303 pfile_info->NumberOfLinks = cpu_to_le32(1);
1304 pfile_info->DeletePending = 0;
1308 cifs_buf_release(pSMB);
1309 if (rc == -EAGAIN)
1310 goto openRetry;
1311 return rc;
1315 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1316 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1317 char **buf, int *pbuf_type)
1319 int rc = -EACCES;
1320 READ_REQ *pSMB = NULL;
1321 READ_RSP *pSMBr = NULL;
1322 char *pReadData = NULL;
1323 int wct;
1324 int resp_buf_type = 0;
1325 struct kvec iov[1];
1327 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1328 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1329 wct = 12;
1330 else {
1331 wct = 10; /* old style read */
1332 if ((lseek >> 32) > 0) {
1333 /* can not handle this big offset for old */
1334 return -EIO;
1338 *nbytes = 0;
1339 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1340 if (rc)
1341 return rc;
1343 /* tcon and ses pointer are checked in smb_init */
1344 if (tcon->ses->server == NULL)
1345 return -ECONNABORTED;
1347 pSMB->AndXCommand = 0xFF; /* none */
1348 pSMB->Fid = netfid;
1349 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1350 if (wct == 12)
1351 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1353 pSMB->Remaining = 0;
1354 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1355 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1356 if (wct == 12)
1357 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1358 else {
1359 /* old style read */
1360 struct smb_com_readx_req *pSMBW =
1361 (struct smb_com_readx_req *)pSMB;
1362 pSMBW->ByteCount = 0;
1365 iov[0].iov_base = (char *)pSMB;
1366 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1367 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1368 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1369 cifs_stats_inc(&tcon->num_reads);
1370 pSMBr = (READ_RSP *)iov[0].iov_base;
1371 if (rc) {
1372 cERROR(1, ("Send error in read = %d", rc));
1373 } else {
1374 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1375 data_length = data_length << 16;
1376 data_length += le16_to_cpu(pSMBr->DataLength);
1377 *nbytes = data_length;
1379 /*check that DataLength would not go beyond end of SMB */
1380 if ((data_length > CIFSMaxBufSize)
1381 || (data_length > count)) {
1382 cFYI(1, ("bad length %d for count %d",
1383 data_length, count));
1384 rc = -EIO;
1385 *nbytes = 0;
1386 } else {
1387 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1388 le16_to_cpu(pSMBr->DataOffset);
1389 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1390 cERROR(1,("Faulting on read rc = %d",rc));
1391 rc = -EFAULT;
1392 }*/ /* can not use copy_to_user when using page cache*/
1393 if (*buf)
1394 memcpy(*buf, pReadData, data_length);
1398 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1399 if (*buf) {
1400 if (resp_buf_type == CIFS_SMALL_BUFFER)
1401 cifs_small_buf_release(iov[0].iov_base);
1402 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1403 cifs_buf_release(iov[0].iov_base);
1404 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1405 /* return buffer to caller to free */
1406 *buf = iov[0].iov_base;
1407 if (resp_buf_type == CIFS_SMALL_BUFFER)
1408 *pbuf_type = CIFS_SMALL_BUFFER;
1409 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1410 *pbuf_type = CIFS_LARGE_BUFFER;
1411 } /* else no valid buffer on return - leave as null */
1413 /* Note: On -EAGAIN error only caller can retry on handle based calls
1414 since file handle passed in no longer valid */
1415 return rc;
1420 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1421 const int netfid, const unsigned int count,
1422 const __u64 offset, unsigned int *nbytes, const char *buf,
1423 const char __user *ubuf, const int long_op)
1425 int rc = -EACCES;
1426 WRITE_REQ *pSMB = NULL;
1427 WRITE_RSP *pSMBr = NULL;
1428 int bytes_returned, wct;
1429 __u32 bytes_sent;
1430 __u16 byte_count;
1432 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
1433 if (tcon->ses == NULL)
1434 return -ECONNABORTED;
1436 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1437 wct = 14;
1438 else {
1439 wct = 12;
1440 if ((offset >> 32) > 0) {
1441 /* can not handle big offset for old srv */
1442 return -EIO;
1446 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1447 (void **) &pSMBr);
1448 if (rc)
1449 return rc;
1450 /* tcon and ses pointer are checked in smb_init */
1451 if (tcon->ses->server == NULL)
1452 return -ECONNABORTED;
1454 pSMB->AndXCommand = 0xFF; /* none */
1455 pSMB->Fid = netfid;
1456 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1457 if (wct == 14)
1458 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1460 pSMB->Reserved = 0xFFFFFFFF;
1461 pSMB->WriteMode = 0;
1462 pSMB->Remaining = 0;
1464 /* Can increase buffer size if buffer is big enough in some cases ie we
1465 can send more if LARGE_WRITE_X capability returned by the server and if
1466 our buffer is big enough or if we convert to iovecs on socket writes
1467 and eliminate the copy to the CIFS buffer */
1468 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1469 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1470 } else {
1471 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1472 & ~0xFF;
1475 if (bytes_sent > count)
1476 bytes_sent = count;
1477 pSMB->DataOffset =
1478 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1479 if (buf)
1480 memcpy(pSMB->Data, buf, bytes_sent);
1481 else if (ubuf) {
1482 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1483 cifs_buf_release(pSMB);
1484 return -EFAULT;
1486 } else if (count != 0) {
1487 /* No buffer */
1488 cifs_buf_release(pSMB);
1489 return -EINVAL;
1490 } /* else setting file size with write of zero bytes */
1491 if (wct == 14)
1492 byte_count = bytes_sent + 1; /* pad */
1493 else /* wct == 12 */
1494 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1496 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1497 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1498 pSMB->hdr.smb_buf_length += byte_count;
1500 if (wct == 14)
1501 pSMB->ByteCount = cpu_to_le16(byte_count);
1502 else { /* old style write has byte count 4 bytes earlier
1503 so 4 bytes pad */
1504 struct smb_com_writex_req *pSMBW =
1505 (struct smb_com_writex_req *)pSMB;
1506 pSMBW->ByteCount = cpu_to_le16(byte_count);
1509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1510 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1511 cifs_stats_inc(&tcon->num_writes);
1512 if (rc) {
1513 cFYI(1, ("Send error in write = %d", rc));
1514 *nbytes = 0;
1515 } else {
1516 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1517 *nbytes = (*nbytes) << 16;
1518 *nbytes += le16_to_cpu(pSMBr->Count);
1521 cifs_buf_release(pSMB);
1523 /* Note: On -EAGAIN error only caller can retry on handle based calls
1524 since file handle passed in no longer valid */
1526 return rc;
1530 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1531 const int netfid, const unsigned int count,
1532 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1533 int n_vec, const int long_op)
1535 int rc = -EACCES;
1536 WRITE_REQ *pSMB = NULL;
1537 int wct;
1538 int smb_hdr_len;
1539 int resp_buf_type = 0;
1541 *nbytes = 0;
1543 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1545 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1546 wct = 14;
1547 } else {
1548 wct = 12;
1549 if ((offset >> 32) > 0) {
1550 /* can not handle big offset for old srv */
1551 return -EIO;
1554 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1555 if (rc)
1556 return rc;
1557 /* tcon and ses pointer are checked in smb_init */
1558 if (tcon->ses->server == NULL)
1559 return -ECONNABORTED;
1561 pSMB->AndXCommand = 0xFF; /* none */
1562 pSMB->Fid = netfid;
1563 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1564 if (wct == 14)
1565 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1566 pSMB->Reserved = 0xFFFFFFFF;
1567 pSMB->WriteMode = 0;
1568 pSMB->Remaining = 0;
1570 pSMB->DataOffset =
1571 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1573 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1574 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1575 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1576 if (wct == 14)
1577 pSMB->hdr.smb_buf_length += count+1;
1578 else /* wct == 12 */
1579 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1580 if (wct == 14)
1581 pSMB->ByteCount = cpu_to_le16(count + 1);
1582 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1583 struct smb_com_writex_req *pSMBW =
1584 (struct smb_com_writex_req *)pSMB;
1585 pSMBW->ByteCount = cpu_to_le16(count + 5);
1587 iov[0].iov_base = pSMB;
1588 if (wct == 14)
1589 iov[0].iov_len = smb_hdr_len + 4;
1590 else /* wct == 12 pad bigger by four bytes */
1591 iov[0].iov_len = smb_hdr_len + 8;
1594 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1595 long_op);
1596 cifs_stats_inc(&tcon->num_writes);
1597 if (rc) {
1598 cFYI(1, ("Send error Write2 = %d", rc));
1599 } else if (resp_buf_type == 0) {
1600 /* presumably this can not happen, but best to be safe */
1601 rc = -EIO;
1602 } else {
1603 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1604 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1605 *nbytes = (*nbytes) << 16;
1606 *nbytes += le16_to_cpu(pSMBr->Count);
1609 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1610 if (resp_buf_type == CIFS_SMALL_BUFFER)
1611 cifs_small_buf_release(iov[0].iov_base);
1612 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1613 cifs_buf_release(iov[0].iov_base);
1615 /* Note: On -EAGAIN error only caller can retry on handle based calls
1616 since file handle passed in no longer valid */
1618 return rc;
1623 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1624 const __u16 smb_file_id, const __u64 len,
1625 const __u64 offset, const __u32 numUnlock,
1626 const __u32 numLock, const __u8 lockType, const bool waitFlag)
1628 int rc = 0;
1629 LOCK_REQ *pSMB = NULL;
1630 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1631 int bytes_returned;
1632 int timeout = 0;
1633 __u16 count;
1635 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1636 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1638 if (rc)
1639 return rc;
1641 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1642 timeout = CIFS_ASYNC_OP; /* no response expected */
1643 pSMB->Timeout = 0;
1644 } else if (waitFlag) {
1645 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1646 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1647 } else {
1648 pSMB->Timeout = 0;
1651 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1652 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1653 pSMB->LockType = lockType;
1654 pSMB->AndXCommand = 0xFF; /* none */
1655 pSMB->Fid = smb_file_id; /* netfid stays le */
1657 if ((numLock != 0) || (numUnlock != 0)) {
1658 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1659 /* BB where to store pid high? */
1660 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1661 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1662 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1663 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1664 count = sizeof(LOCKING_ANDX_RANGE);
1665 } else {
1666 /* oplock break */
1667 count = 0;
1669 pSMB->hdr.smb_buf_length += count;
1670 pSMB->ByteCount = cpu_to_le16(count);
1672 if (waitFlag) {
1673 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1674 (struct smb_hdr *) pSMB, &bytes_returned);
1675 cifs_small_buf_release(pSMB);
1676 } else {
1677 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1678 timeout);
1679 /* SMB buffer freed by function above */
1681 cifs_stats_inc(&tcon->num_locks);
1682 if (rc)
1683 cFYI(1, ("Send error in Lock = %d", rc));
1685 /* Note: On -EAGAIN error only caller can retry on handle based calls
1686 since file handle passed in no longer valid */
1687 return rc;
1691 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1692 const __u16 smb_file_id, const int get_flag, const __u64 len,
1693 struct file_lock *pLockData, const __u16 lock_type,
1694 const bool waitFlag)
1696 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1697 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1698 struct cifs_posix_lock *parm_data;
1699 int rc = 0;
1700 int timeout = 0;
1701 int bytes_returned = 0;
1702 int resp_buf_type = 0;
1703 __u16 params, param_offset, offset, byte_count, count;
1704 struct kvec iov[1];
1706 cFYI(1, ("Posix Lock"));
1708 if (pLockData == NULL)
1709 return -EINVAL;
1711 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1713 if (rc)
1714 return rc;
1716 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1718 params = 6;
1719 pSMB->MaxSetupCount = 0;
1720 pSMB->Reserved = 0;
1721 pSMB->Flags = 0;
1722 pSMB->Reserved2 = 0;
1723 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1724 offset = param_offset + params;
1726 count = sizeof(struct cifs_posix_lock);
1727 pSMB->MaxParameterCount = cpu_to_le16(2);
1728 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1729 pSMB->SetupCount = 1;
1730 pSMB->Reserved3 = 0;
1731 if (get_flag)
1732 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1733 else
1734 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1735 byte_count = 3 /* pad */ + params + count;
1736 pSMB->DataCount = cpu_to_le16(count);
1737 pSMB->ParameterCount = cpu_to_le16(params);
1738 pSMB->TotalDataCount = pSMB->DataCount;
1739 pSMB->TotalParameterCount = pSMB->ParameterCount;
1740 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1741 parm_data = (struct cifs_posix_lock *)
1742 (((char *) &pSMB->hdr.Protocol) + offset);
1744 parm_data->lock_type = cpu_to_le16(lock_type);
1745 if (waitFlag) {
1746 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1747 parm_data->lock_flags = cpu_to_le16(1);
1748 pSMB->Timeout = cpu_to_le32(-1);
1749 } else
1750 pSMB->Timeout = 0;
1752 parm_data->pid = cpu_to_le32(current->tgid);
1753 parm_data->start = cpu_to_le64(pLockData->fl_start);
1754 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1756 pSMB->DataOffset = cpu_to_le16(offset);
1757 pSMB->Fid = smb_file_id;
1758 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1759 pSMB->Reserved4 = 0;
1760 pSMB->hdr.smb_buf_length += byte_count;
1761 pSMB->ByteCount = cpu_to_le16(byte_count);
1762 if (waitFlag) {
1763 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1764 (struct smb_hdr *) pSMBr, &bytes_returned);
1765 } else {
1766 iov[0].iov_base = (char *)pSMB;
1767 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1768 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1769 &resp_buf_type, timeout);
1770 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1771 not try to free it twice below on exit */
1772 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1775 if (rc) {
1776 cFYI(1, ("Send error in Posix Lock = %d", rc));
1777 } else if (get_flag) {
1778 /* lock structure can be returned on get */
1779 __u16 data_offset;
1780 __u16 data_count;
1781 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1783 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1784 rc = -EIO; /* bad smb */
1785 goto plk_err_exit;
1787 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1788 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1789 if (data_count < sizeof(struct cifs_posix_lock)) {
1790 rc = -EIO;
1791 goto plk_err_exit;
1793 parm_data = (struct cifs_posix_lock *)
1794 ((char *)&pSMBr->hdr.Protocol + data_offset);
1795 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1796 pLockData->fl_type = F_UNLCK;
1799 plk_err_exit:
1800 if (pSMB)
1801 cifs_small_buf_release(pSMB);
1803 if (resp_buf_type == CIFS_SMALL_BUFFER)
1804 cifs_small_buf_release(iov[0].iov_base);
1805 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1806 cifs_buf_release(iov[0].iov_base);
1808 /* Note: On -EAGAIN error only caller can retry on handle based calls
1809 since file handle passed in no longer valid */
1811 return rc;
1816 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1818 int rc = 0;
1819 CLOSE_REQ *pSMB = NULL;
1820 cFYI(1, ("In CIFSSMBClose"));
1822 /* do not retry on dead session on close */
1823 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1824 if (rc == -EAGAIN)
1825 return 0;
1826 if (rc)
1827 return rc;
1829 pSMB->FileID = (__u16) smb_file_id;
1830 pSMB->LastWriteTime = 0xFFFFFFFF;
1831 pSMB->ByteCount = 0;
1832 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1833 cifs_stats_inc(&tcon->num_closes);
1834 if (rc) {
1835 if (rc != -EINTR) {
1836 /* EINTR is expected when user ctl-c to kill app */
1837 cERROR(1, ("Send error in Close = %d", rc));
1841 /* Since session is dead, file will be closed on server already */
1842 if (rc == -EAGAIN)
1843 rc = 0;
1845 return rc;
1849 CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1851 int rc = 0;
1852 FLUSH_REQ *pSMB = NULL;
1853 cFYI(1, ("In CIFSSMBFlush"));
1855 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1856 if (rc)
1857 return rc;
1859 pSMB->FileID = (__u16) smb_file_id;
1860 pSMB->ByteCount = 0;
1861 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1862 cifs_stats_inc(&tcon->num_flushes);
1863 if (rc)
1864 cERROR(1, ("Send error in Flush = %d", rc));
1866 return rc;
1870 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1871 const char *fromName, const char *toName,
1872 const struct nls_table *nls_codepage, int remap)
1874 int rc = 0;
1875 RENAME_REQ *pSMB = NULL;
1876 RENAME_RSP *pSMBr = NULL;
1877 int bytes_returned;
1878 int name_len, name_len2;
1879 __u16 count;
1881 cFYI(1, ("In CIFSSMBRename"));
1882 renameRetry:
1883 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1884 (void **) &pSMBr);
1885 if (rc)
1886 return rc;
1888 pSMB->BufferFormat = 0x04;
1889 pSMB->SearchAttributes =
1890 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1891 ATTR_DIRECTORY);
1893 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1894 name_len =
1895 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1896 PATH_MAX, nls_codepage, remap);
1897 name_len++; /* trailing null */
1898 name_len *= 2;
1899 pSMB->OldFileName[name_len] = 0x04; /* pad */
1900 /* protocol requires ASCII signature byte on Unicode string */
1901 pSMB->OldFileName[name_len + 1] = 0x00;
1902 name_len2 =
1903 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1904 toName, PATH_MAX, nls_codepage, remap);
1905 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1906 name_len2 *= 2; /* convert to bytes */
1907 } else { /* BB improve the check for buffer overruns BB */
1908 name_len = strnlen(fromName, PATH_MAX);
1909 name_len++; /* trailing null */
1910 strncpy(pSMB->OldFileName, fromName, name_len);
1911 name_len2 = strnlen(toName, PATH_MAX);
1912 name_len2++; /* trailing null */
1913 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1914 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1915 name_len2++; /* trailing null */
1916 name_len2++; /* signature byte */
1919 count = 1 /* 1st signature byte */ + name_len + name_len2;
1920 pSMB->hdr.smb_buf_length += count;
1921 pSMB->ByteCount = cpu_to_le16(count);
1923 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1925 cifs_stats_inc(&tcon->num_renames);
1926 if (rc)
1927 cFYI(1, ("Send error in rename = %d", rc));
1929 cifs_buf_release(pSMB);
1931 if (rc == -EAGAIN)
1932 goto renameRetry;
1934 return rc;
1937 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1938 int netfid, const char *target_name,
1939 const struct nls_table *nls_codepage, int remap)
1941 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1942 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1943 struct set_file_rename *rename_info;
1944 char *data_offset;
1945 char dummy_string[30];
1946 int rc = 0;
1947 int bytes_returned = 0;
1948 int len_of_str;
1949 __u16 params, param_offset, offset, count, byte_count;
1951 cFYI(1, ("Rename to File by handle"));
1952 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1953 (void **) &pSMBr);
1954 if (rc)
1955 return rc;
1957 params = 6;
1958 pSMB->MaxSetupCount = 0;
1959 pSMB->Reserved = 0;
1960 pSMB->Flags = 0;
1961 pSMB->Timeout = 0;
1962 pSMB->Reserved2 = 0;
1963 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1964 offset = param_offset + params;
1966 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1967 rename_info = (struct set_file_rename *) data_offset;
1968 pSMB->MaxParameterCount = cpu_to_le16(2);
1969 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1970 pSMB->SetupCount = 1;
1971 pSMB->Reserved3 = 0;
1972 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1973 byte_count = 3 /* pad */ + params;
1974 pSMB->ParameterCount = cpu_to_le16(params);
1975 pSMB->TotalParameterCount = pSMB->ParameterCount;
1976 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1977 pSMB->DataOffset = cpu_to_le16(offset);
1978 /* construct random name ".cifs_tmp<inodenum><mid>" */
1979 rename_info->overwrite = cpu_to_le32(1);
1980 rename_info->root_fid = 0;
1981 /* unicode only call */
1982 if (target_name == NULL) {
1983 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
1984 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1985 dummy_string, 24, nls_codepage, remap);
1986 } else {
1987 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1988 target_name, PATH_MAX, nls_codepage,
1989 remap);
1991 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1992 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
1993 byte_count += count;
1994 pSMB->DataCount = cpu_to_le16(count);
1995 pSMB->TotalDataCount = pSMB->DataCount;
1996 pSMB->Fid = netfid;
1997 pSMB->InformationLevel =
1998 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1999 pSMB->Reserved4 = 0;
2000 pSMB->hdr.smb_buf_length += byte_count;
2001 pSMB->ByteCount = cpu_to_le16(byte_count);
2002 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2004 cifs_stats_inc(&pTcon->num_t2renames);
2005 if (rc)
2006 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2008 cifs_buf_release(pSMB);
2010 /* Note: On -EAGAIN error only caller can retry on handle based calls
2011 since file handle passed in no longer valid */
2013 return rc;
2017 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2018 const __u16 target_tid, const char *toName, const int flags,
2019 const struct nls_table *nls_codepage, int remap)
2021 int rc = 0;
2022 COPY_REQ *pSMB = NULL;
2023 COPY_RSP *pSMBr = NULL;
2024 int bytes_returned;
2025 int name_len, name_len2;
2026 __u16 count;
2028 cFYI(1, ("In CIFSSMBCopy"));
2029 copyRetry:
2030 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2031 (void **) &pSMBr);
2032 if (rc)
2033 return rc;
2035 pSMB->BufferFormat = 0x04;
2036 pSMB->Tid2 = target_tid;
2038 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2040 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2041 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2042 fromName, PATH_MAX, nls_codepage,
2043 remap);
2044 name_len++; /* trailing null */
2045 name_len *= 2;
2046 pSMB->OldFileName[name_len] = 0x04; /* pad */
2047 /* protocol requires ASCII signature byte on Unicode string */
2048 pSMB->OldFileName[name_len + 1] = 0x00;
2049 name_len2 =
2050 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2051 toName, PATH_MAX, nls_codepage, remap);
2052 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2053 name_len2 *= 2; /* convert to bytes */
2054 } else { /* BB improve the check for buffer overruns BB */
2055 name_len = strnlen(fromName, PATH_MAX);
2056 name_len++; /* trailing null */
2057 strncpy(pSMB->OldFileName, fromName, name_len);
2058 name_len2 = strnlen(toName, PATH_MAX);
2059 name_len2++; /* trailing null */
2060 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2061 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2062 name_len2++; /* trailing null */
2063 name_len2++; /* signature byte */
2066 count = 1 /* 1st signature byte */ + name_len + name_len2;
2067 pSMB->hdr.smb_buf_length += count;
2068 pSMB->ByteCount = cpu_to_le16(count);
2070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2072 if (rc) {
2073 cFYI(1, ("Send error in copy = %d with %d files copied",
2074 rc, le16_to_cpu(pSMBr->CopyCount)));
2076 cifs_buf_release(pSMB);
2078 if (rc == -EAGAIN)
2079 goto copyRetry;
2081 return rc;
2085 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2086 const char *fromName, const char *toName,
2087 const struct nls_table *nls_codepage)
2089 TRANSACTION2_SPI_REQ *pSMB = NULL;
2090 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2091 char *data_offset;
2092 int name_len;
2093 int name_len_target;
2094 int rc = 0;
2095 int bytes_returned = 0;
2096 __u16 params, param_offset, offset, byte_count;
2098 cFYI(1, ("In Symlink Unix style"));
2099 createSymLinkRetry:
2100 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2101 (void **) &pSMBr);
2102 if (rc)
2103 return rc;
2105 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2106 name_len =
2107 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2108 /* find define for this maxpathcomponent */
2109 , nls_codepage);
2110 name_len++; /* trailing null */
2111 name_len *= 2;
2113 } else { /* BB improve the check for buffer overruns BB */
2114 name_len = strnlen(fromName, PATH_MAX);
2115 name_len++; /* trailing null */
2116 strncpy(pSMB->FileName, fromName, name_len);
2118 params = 6 + name_len;
2119 pSMB->MaxSetupCount = 0;
2120 pSMB->Reserved = 0;
2121 pSMB->Flags = 0;
2122 pSMB->Timeout = 0;
2123 pSMB->Reserved2 = 0;
2124 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2125 InformationLevel) - 4;
2126 offset = param_offset + params;
2128 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2129 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2130 name_len_target =
2131 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2132 /* find define for this maxpathcomponent */
2133 , nls_codepage);
2134 name_len_target++; /* trailing null */
2135 name_len_target *= 2;
2136 } else { /* BB improve the check for buffer overruns BB */
2137 name_len_target = strnlen(toName, PATH_MAX);
2138 name_len_target++; /* trailing null */
2139 strncpy(data_offset, toName, name_len_target);
2142 pSMB->MaxParameterCount = cpu_to_le16(2);
2143 /* BB find exact max on data count below from sess */
2144 pSMB->MaxDataCount = cpu_to_le16(1000);
2145 pSMB->SetupCount = 1;
2146 pSMB->Reserved3 = 0;
2147 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2148 byte_count = 3 /* pad */ + params + name_len_target;
2149 pSMB->DataCount = cpu_to_le16(name_len_target);
2150 pSMB->ParameterCount = cpu_to_le16(params);
2151 pSMB->TotalDataCount = pSMB->DataCount;
2152 pSMB->TotalParameterCount = pSMB->ParameterCount;
2153 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2154 pSMB->DataOffset = cpu_to_le16(offset);
2155 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2156 pSMB->Reserved4 = 0;
2157 pSMB->hdr.smb_buf_length += byte_count;
2158 pSMB->ByteCount = cpu_to_le16(byte_count);
2159 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2160 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2161 cifs_stats_inc(&tcon->num_symlinks);
2162 if (rc)
2163 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2165 cifs_buf_release(pSMB);
2167 if (rc == -EAGAIN)
2168 goto createSymLinkRetry;
2170 return rc;
2174 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2175 const char *fromName, const char *toName,
2176 const struct nls_table *nls_codepage, int remap)
2178 TRANSACTION2_SPI_REQ *pSMB = NULL;
2179 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2180 char *data_offset;
2181 int name_len;
2182 int name_len_target;
2183 int rc = 0;
2184 int bytes_returned = 0;
2185 __u16 params, param_offset, offset, byte_count;
2187 cFYI(1, ("In Create Hard link Unix style"));
2188 createHardLinkRetry:
2189 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2190 (void **) &pSMBr);
2191 if (rc)
2192 return rc;
2194 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2195 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2196 PATH_MAX, nls_codepage, remap);
2197 name_len++; /* trailing null */
2198 name_len *= 2;
2200 } else { /* BB improve the check for buffer overruns BB */
2201 name_len = strnlen(toName, PATH_MAX);
2202 name_len++; /* trailing null */
2203 strncpy(pSMB->FileName, toName, name_len);
2205 params = 6 + name_len;
2206 pSMB->MaxSetupCount = 0;
2207 pSMB->Reserved = 0;
2208 pSMB->Flags = 0;
2209 pSMB->Timeout = 0;
2210 pSMB->Reserved2 = 0;
2211 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2212 InformationLevel) - 4;
2213 offset = param_offset + params;
2215 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2216 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2217 name_len_target =
2218 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2219 nls_codepage, remap);
2220 name_len_target++; /* trailing null */
2221 name_len_target *= 2;
2222 } else { /* BB improve the check for buffer overruns BB */
2223 name_len_target = strnlen(fromName, PATH_MAX);
2224 name_len_target++; /* trailing null */
2225 strncpy(data_offset, fromName, name_len_target);
2228 pSMB->MaxParameterCount = cpu_to_le16(2);
2229 /* BB find exact max on data count below from sess*/
2230 pSMB->MaxDataCount = cpu_to_le16(1000);
2231 pSMB->SetupCount = 1;
2232 pSMB->Reserved3 = 0;
2233 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2234 byte_count = 3 /* pad */ + params + name_len_target;
2235 pSMB->ParameterCount = cpu_to_le16(params);
2236 pSMB->TotalParameterCount = pSMB->ParameterCount;
2237 pSMB->DataCount = cpu_to_le16(name_len_target);
2238 pSMB->TotalDataCount = pSMB->DataCount;
2239 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2240 pSMB->DataOffset = cpu_to_le16(offset);
2241 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2242 pSMB->Reserved4 = 0;
2243 pSMB->hdr.smb_buf_length += byte_count;
2244 pSMB->ByteCount = cpu_to_le16(byte_count);
2245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2246 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2247 cifs_stats_inc(&tcon->num_hardlinks);
2248 if (rc)
2249 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2251 cifs_buf_release(pSMB);
2252 if (rc == -EAGAIN)
2253 goto createHardLinkRetry;
2255 return rc;
2259 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2260 const char *fromName, const char *toName,
2261 const struct nls_table *nls_codepage, int remap)
2263 int rc = 0;
2264 NT_RENAME_REQ *pSMB = NULL;
2265 RENAME_RSP *pSMBr = NULL;
2266 int bytes_returned;
2267 int name_len, name_len2;
2268 __u16 count;
2270 cFYI(1, ("In CIFSCreateHardLink"));
2271 winCreateHardLinkRetry:
2273 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2274 (void **) &pSMBr);
2275 if (rc)
2276 return rc;
2278 pSMB->SearchAttributes =
2279 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2280 ATTR_DIRECTORY);
2281 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2282 pSMB->ClusterCount = 0;
2284 pSMB->BufferFormat = 0x04;
2286 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2287 name_len =
2288 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2289 PATH_MAX, nls_codepage, remap);
2290 name_len++; /* trailing null */
2291 name_len *= 2;
2293 /* protocol specifies ASCII buffer format (0x04) for unicode */
2294 pSMB->OldFileName[name_len] = 0x04;
2295 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2296 name_len2 =
2297 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2298 toName, PATH_MAX, nls_codepage, remap);
2299 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2300 name_len2 *= 2; /* convert to bytes */
2301 } else { /* BB improve the check for buffer overruns BB */
2302 name_len = strnlen(fromName, PATH_MAX);
2303 name_len++; /* trailing null */
2304 strncpy(pSMB->OldFileName, fromName, name_len);
2305 name_len2 = strnlen(toName, PATH_MAX);
2306 name_len2++; /* trailing null */
2307 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2308 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2309 name_len2++; /* trailing null */
2310 name_len2++; /* signature byte */
2313 count = 1 /* string type byte */ + name_len + name_len2;
2314 pSMB->hdr.smb_buf_length += count;
2315 pSMB->ByteCount = cpu_to_le16(count);
2317 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2318 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2319 cifs_stats_inc(&tcon->num_hardlinks);
2320 if (rc)
2321 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2323 cifs_buf_release(pSMB);
2324 if (rc == -EAGAIN)
2325 goto winCreateHardLinkRetry;
2327 return rc;
2331 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2332 const unsigned char *searchName, char **symlinkinfo,
2333 const struct nls_table *nls_codepage)
2335 /* SMB_QUERY_FILE_UNIX_LINK */
2336 TRANSACTION2_QPI_REQ *pSMB = NULL;
2337 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2338 int rc = 0;
2339 int bytes_returned;
2340 int name_len;
2341 __u16 params, byte_count;
2342 char *data_start;
2344 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2346 querySymLinkRetry:
2347 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2348 (void **) &pSMBr);
2349 if (rc)
2350 return rc;
2352 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2353 name_len =
2354 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2355 PATH_MAX, nls_codepage);
2356 name_len++; /* trailing null */
2357 name_len *= 2;
2358 } else { /* BB improve the check for buffer overruns BB */
2359 name_len = strnlen(searchName, PATH_MAX);
2360 name_len++; /* trailing null */
2361 strncpy(pSMB->FileName, searchName, name_len);
2364 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2365 pSMB->TotalDataCount = 0;
2366 pSMB->MaxParameterCount = cpu_to_le16(2);
2367 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
2368 pSMB->MaxSetupCount = 0;
2369 pSMB->Reserved = 0;
2370 pSMB->Flags = 0;
2371 pSMB->Timeout = 0;
2372 pSMB->Reserved2 = 0;
2373 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2374 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2375 pSMB->DataCount = 0;
2376 pSMB->DataOffset = 0;
2377 pSMB->SetupCount = 1;
2378 pSMB->Reserved3 = 0;
2379 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2380 byte_count = params + 1 /* pad */ ;
2381 pSMB->TotalParameterCount = cpu_to_le16(params);
2382 pSMB->ParameterCount = pSMB->TotalParameterCount;
2383 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2384 pSMB->Reserved4 = 0;
2385 pSMB->hdr.smb_buf_length += byte_count;
2386 pSMB->ByteCount = cpu_to_le16(byte_count);
2388 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2389 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2390 if (rc) {
2391 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2392 } else {
2393 /* decode response */
2395 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2396 /* BB also check enough total bytes returned */
2397 if (rc || (pSMBr->ByteCount < 2))
2398 rc = -EIO;
2399 else {
2400 bool is_unicode;
2401 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2403 data_start = ((char *) &pSMBr->hdr.Protocol) +
2404 le16_to_cpu(pSMBr->t2.DataOffset);
2406 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2407 is_unicode = true;
2408 else
2409 is_unicode = false;
2411 /* BB FIXME investigate remapping reserved chars here */
2412 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
2413 is_unicode, nls_codepage);
2414 if (!*symlinkinfo)
2415 rc = -ENOMEM;
2418 cifs_buf_release(pSMB);
2419 if (rc == -EAGAIN)
2420 goto querySymLinkRetry;
2421 return rc;
2424 #ifdef CONFIG_CIFS_EXPERIMENTAL
2425 /* Initialize NT TRANSACT SMB into small smb request buffer.
2426 This assumes that all NT TRANSACTS that we init here have
2427 total parm and data under about 400 bytes (to fit in small cifs
2428 buffer size), which is the case so far, it easily fits. NB:
2429 Setup words themselves and ByteCount
2430 MaxSetupCount (size of returned setup area) and
2431 MaxParameterCount (returned parms size) must be set by caller */
2432 static int
2433 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2434 const int parm_len, struct cifsTconInfo *tcon,
2435 void **ret_buf)
2437 int rc;
2438 __u32 temp_offset;
2439 struct smb_com_ntransact_req *pSMB;
2441 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2442 (void **)&pSMB);
2443 if (rc)
2444 return rc;
2445 *ret_buf = (void *)pSMB;
2446 pSMB->Reserved = 0;
2447 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2448 pSMB->TotalDataCount = 0;
2449 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2450 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2451 pSMB->ParameterCount = pSMB->TotalParameterCount;
2452 pSMB->DataCount = pSMB->TotalDataCount;
2453 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2454 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2455 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2456 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2457 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2458 pSMB->SubCommand = cpu_to_le16(sub_command);
2459 return 0;
2462 static int
2463 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2464 __u32 *pparmlen, __u32 *pdatalen)
2466 char *end_of_smb;
2467 __u32 data_count, data_offset, parm_count, parm_offset;
2468 struct smb_com_ntransact_rsp *pSMBr;
2470 *pdatalen = 0;
2471 *pparmlen = 0;
2473 if (buf == NULL)
2474 return -EINVAL;
2476 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2478 /* ByteCount was converted from little endian in SendReceive */
2479 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2480 (char *)&pSMBr->ByteCount;
2482 data_offset = le32_to_cpu(pSMBr->DataOffset);
2483 data_count = le32_to_cpu(pSMBr->DataCount);
2484 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2485 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2487 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2488 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2490 /* should we also check that parm and data areas do not overlap? */
2491 if (*ppparm > end_of_smb) {
2492 cFYI(1, ("parms start after end of smb"));
2493 return -EINVAL;
2494 } else if (parm_count + *ppparm > end_of_smb) {
2495 cFYI(1, ("parm end after end of smb"));
2496 return -EINVAL;
2497 } else if (*ppdata > end_of_smb) {
2498 cFYI(1, ("data starts after end of smb"));
2499 return -EINVAL;
2500 } else if (data_count + *ppdata > end_of_smb) {
2501 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2502 *ppdata, data_count, (data_count + *ppdata),
2503 end_of_smb, pSMBr));
2504 return -EINVAL;
2505 } else if (parm_count + data_count > pSMBr->ByteCount) {
2506 cFYI(1, ("parm count and data count larger than SMB"));
2507 return -EINVAL;
2509 *pdatalen = data_count;
2510 *pparmlen = parm_count;
2511 return 0;
2515 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2516 const unsigned char *searchName,
2517 char *symlinkinfo, const int buflen, __u16 fid,
2518 const struct nls_table *nls_codepage)
2520 int rc = 0;
2521 int bytes_returned;
2522 struct smb_com_transaction_ioctl_req *pSMB;
2523 struct smb_com_transaction_ioctl_rsp *pSMBr;
2525 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2526 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2527 (void **) &pSMBr);
2528 if (rc)
2529 return rc;
2531 pSMB->TotalParameterCount = 0 ;
2532 pSMB->TotalDataCount = 0;
2533 pSMB->MaxParameterCount = cpu_to_le32(2);
2534 /* BB find exact data count max from sess structure BB */
2535 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2536 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2537 pSMB->MaxSetupCount = 4;
2538 pSMB->Reserved = 0;
2539 pSMB->ParameterOffset = 0;
2540 pSMB->DataCount = 0;
2541 pSMB->DataOffset = 0;
2542 pSMB->SetupCount = 4;
2543 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2544 pSMB->ParameterCount = pSMB->TotalParameterCount;
2545 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2546 pSMB->IsFsctl = 1; /* FSCTL */
2547 pSMB->IsRootFlag = 0;
2548 pSMB->Fid = fid; /* file handle always le */
2549 pSMB->ByteCount = 0;
2551 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2552 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2553 if (rc) {
2554 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2555 } else { /* decode response */
2556 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2557 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2558 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
2559 /* BB also check enough total bytes returned */
2560 rc = -EIO; /* bad smb */
2561 goto qreparse_out;
2563 if (data_count && (data_count < 2048)) {
2564 char *end_of_smb = 2 /* sizeof byte count */ +
2565 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
2567 struct reparse_data *reparse_buf =
2568 (struct reparse_data *)
2569 ((char *)&pSMBr->hdr.Protocol
2570 + data_offset);
2571 if ((char *)reparse_buf >= end_of_smb) {
2572 rc = -EIO;
2573 goto qreparse_out;
2575 if ((reparse_buf->LinkNamesBuf +
2576 reparse_buf->TargetNameOffset +
2577 reparse_buf->TargetNameLen) > end_of_smb) {
2578 cFYI(1, ("reparse buf beyond SMB"));
2579 rc = -EIO;
2580 goto qreparse_out;
2583 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2584 cifs_from_ucs2(symlinkinfo, (__le16 *)
2585 (reparse_buf->LinkNamesBuf +
2586 reparse_buf->TargetNameOffset),
2587 buflen,
2588 reparse_buf->TargetNameLen,
2589 nls_codepage, 0);
2590 } else { /* ASCII names */
2591 strncpy(symlinkinfo,
2592 reparse_buf->LinkNamesBuf +
2593 reparse_buf->TargetNameOffset,
2594 min_t(const int, buflen,
2595 reparse_buf->TargetNameLen));
2597 } else {
2598 rc = -EIO;
2599 cFYI(1, ("Invalid return data count on "
2600 "get reparse info ioctl"));
2602 symlinkinfo[buflen] = 0; /* just in case so the caller
2603 does not go off the end of the buffer */
2604 cFYI(1, ("readlink result - %s", symlinkinfo));
2607 qreparse_out:
2608 cifs_buf_release(pSMB);
2610 /* Note: On -EAGAIN error only caller can retry on handle based calls
2611 since file handle passed in no longer valid */
2613 return rc;
2615 #endif /* CIFS_EXPERIMENTAL */
2617 #ifdef CONFIG_CIFS_POSIX
2619 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2620 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2621 struct cifs_posix_ace *cifs_ace)
2623 /* u8 cifs fields do not need le conversion */
2624 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2625 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2626 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2627 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2629 return;
2632 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2633 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2634 const int acl_type, const int size_of_data_area)
2636 int size = 0;
2637 int i;
2638 __u16 count;
2639 struct cifs_posix_ace *pACE;
2640 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2641 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2643 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2644 return -EOPNOTSUPP;
2646 if (acl_type & ACL_TYPE_ACCESS) {
2647 count = le16_to_cpu(cifs_acl->access_entry_count);
2648 pACE = &cifs_acl->ace_array[0];
2649 size = sizeof(struct cifs_posix_acl);
2650 size += sizeof(struct cifs_posix_ace) * count;
2651 /* check if we would go beyond end of SMB */
2652 if (size_of_data_area < size) {
2653 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2654 size_of_data_area, size));
2655 return -EINVAL;
2657 } else if (acl_type & ACL_TYPE_DEFAULT) {
2658 count = le16_to_cpu(cifs_acl->access_entry_count);
2659 size = sizeof(struct cifs_posix_acl);
2660 size += sizeof(struct cifs_posix_ace) * count;
2661 /* skip past access ACEs to get to default ACEs */
2662 pACE = &cifs_acl->ace_array[count];
2663 count = le16_to_cpu(cifs_acl->default_entry_count);
2664 size += sizeof(struct cifs_posix_ace) * count;
2665 /* check if we would go beyond end of SMB */
2666 if (size_of_data_area < size)
2667 return -EINVAL;
2668 } else {
2669 /* illegal type */
2670 return -EINVAL;
2673 size = posix_acl_xattr_size(count);
2674 if ((buflen == 0) || (local_acl == NULL)) {
2675 /* used to query ACL EA size */
2676 } else if (size > buflen) {
2677 return -ERANGE;
2678 } else /* buffer big enough */ {
2679 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2680 for (i = 0; i < count ; i++) {
2681 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2682 pACE++;
2685 return size;
2688 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2689 const posix_acl_xattr_entry *local_ace)
2691 __u16 rc = 0; /* 0 = ACL converted ok */
2693 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2694 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2695 /* BB is there a better way to handle the large uid? */
2696 if (local_ace->e_id == cpu_to_le32(-1)) {
2697 /* Probably no need to le convert -1 on any arch but can not hurt */
2698 cifs_ace->cifs_uid = cpu_to_le64(-1);
2699 } else
2700 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2701 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2702 return rc;
2705 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2706 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2707 const int buflen, const int acl_type)
2709 __u16 rc = 0;
2710 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2711 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2712 int count;
2713 int i;
2715 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2716 return 0;
2718 count = posix_acl_xattr_count((size_t)buflen);
2719 cFYI(1, ("setting acl with %d entries from buf of length %d and "
2720 "version of %d",
2721 count, buflen, le32_to_cpu(local_acl->a_version)));
2722 if (le32_to_cpu(local_acl->a_version) != 2) {
2723 cFYI(1, ("unknown POSIX ACL version %d",
2724 le32_to_cpu(local_acl->a_version)));
2725 return 0;
2727 cifs_acl->version = cpu_to_le16(1);
2728 if (acl_type == ACL_TYPE_ACCESS)
2729 cifs_acl->access_entry_count = cpu_to_le16(count);
2730 else if (acl_type == ACL_TYPE_DEFAULT)
2731 cifs_acl->default_entry_count = cpu_to_le16(count);
2732 else {
2733 cFYI(1, ("unknown ACL type %d", acl_type));
2734 return 0;
2736 for (i = 0; i < count; i++) {
2737 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2738 &local_acl->a_entries[i]);
2739 if (rc != 0) {
2740 /* ACE not converted */
2741 break;
2744 if (rc == 0) {
2745 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2746 rc += sizeof(struct cifs_posix_acl);
2747 /* BB add check to make sure ACL does not overflow SMB */
2749 return rc;
2753 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2754 const unsigned char *searchName,
2755 char *acl_inf, const int buflen, const int acl_type,
2756 const struct nls_table *nls_codepage, int remap)
2758 /* SMB_QUERY_POSIX_ACL */
2759 TRANSACTION2_QPI_REQ *pSMB = NULL;
2760 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2761 int rc = 0;
2762 int bytes_returned;
2763 int name_len;
2764 __u16 params, byte_count;
2766 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2768 queryAclRetry:
2769 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2770 (void **) &pSMBr);
2771 if (rc)
2772 return rc;
2774 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2775 name_len =
2776 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2777 PATH_MAX, nls_codepage, remap);
2778 name_len++; /* trailing null */
2779 name_len *= 2;
2780 pSMB->FileName[name_len] = 0;
2781 pSMB->FileName[name_len+1] = 0;
2782 } else { /* BB improve the check for buffer overruns BB */
2783 name_len = strnlen(searchName, PATH_MAX);
2784 name_len++; /* trailing null */
2785 strncpy(pSMB->FileName, searchName, name_len);
2788 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2789 pSMB->TotalDataCount = 0;
2790 pSMB->MaxParameterCount = cpu_to_le16(2);
2791 /* BB find exact max data count below from sess structure BB */
2792 pSMB->MaxDataCount = cpu_to_le16(4000);
2793 pSMB->MaxSetupCount = 0;
2794 pSMB->Reserved = 0;
2795 pSMB->Flags = 0;
2796 pSMB->Timeout = 0;
2797 pSMB->Reserved2 = 0;
2798 pSMB->ParameterOffset = cpu_to_le16(
2799 offsetof(struct smb_com_transaction2_qpi_req,
2800 InformationLevel) - 4);
2801 pSMB->DataCount = 0;
2802 pSMB->DataOffset = 0;
2803 pSMB->SetupCount = 1;
2804 pSMB->Reserved3 = 0;
2805 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2806 byte_count = params + 1 /* pad */ ;
2807 pSMB->TotalParameterCount = cpu_to_le16(params);
2808 pSMB->ParameterCount = pSMB->TotalParameterCount;
2809 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2810 pSMB->Reserved4 = 0;
2811 pSMB->hdr.smb_buf_length += byte_count;
2812 pSMB->ByteCount = cpu_to_le16(byte_count);
2814 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2815 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2816 cifs_stats_inc(&tcon->num_acl_get);
2817 if (rc) {
2818 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2819 } else {
2820 /* decode response */
2822 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2823 if (rc || (pSMBr->ByteCount < 2))
2824 /* BB also check enough total bytes returned */
2825 rc = -EIO; /* bad smb */
2826 else {
2827 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2828 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2829 rc = cifs_copy_posix_acl(acl_inf,
2830 (char *)&pSMBr->hdr.Protocol+data_offset,
2831 buflen, acl_type, count);
2834 cifs_buf_release(pSMB);
2835 if (rc == -EAGAIN)
2836 goto queryAclRetry;
2837 return rc;
2841 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2842 const unsigned char *fileName,
2843 const char *local_acl, const int buflen,
2844 const int acl_type,
2845 const struct nls_table *nls_codepage, int remap)
2847 struct smb_com_transaction2_spi_req *pSMB = NULL;
2848 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2849 char *parm_data;
2850 int name_len;
2851 int rc = 0;
2852 int bytes_returned = 0;
2853 __u16 params, byte_count, data_count, param_offset, offset;
2855 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2856 setAclRetry:
2857 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2858 (void **) &pSMBr);
2859 if (rc)
2860 return rc;
2861 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2862 name_len =
2863 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2864 PATH_MAX, nls_codepage, remap);
2865 name_len++; /* trailing null */
2866 name_len *= 2;
2867 } else { /* BB improve the check for buffer overruns BB */
2868 name_len = strnlen(fileName, PATH_MAX);
2869 name_len++; /* trailing null */
2870 strncpy(pSMB->FileName, fileName, name_len);
2872 params = 6 + name_len;
2873 pSMB->MaxParameterCount = cpu_to_le16(2);
2874 /* BB find max SMB size from sess */
2875 pSMB->MaxDataCount = cpu_to_le16(1000);
2876 pSMB->MaxSetupCount = 0;
2877 pSMB->Reserved = 0;
2878 pSMB->Flags = 0;
2879 pSMB->Timeout = 0;
2880 pSMB->Reserved2 = 0;
2881 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2882 InformationLevel) - 4;
2883 offset = param_offset + params;
2884 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2885 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2887 /* convert to on the wire format for POSIX ACL */
2888 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2890 if (data_count == 0) {
2891 rc = -EOPNOTSUPP;
2892 goto setACLerrorExit;
2894 pSMB->DataOffset = cpu_to_le16(offset);
2895 pSMB->SetupCount = 1;
2896 pSMB->Reserved3 = 0;
2897 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2898 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2899 byte_count = 3 /* pad */ + params + data_count;
2900 pSMB->DataCount = cpu_to_le16(data_count);
2901 pSMB->TotalDataCount = pSMB->DataCount;
2902 pSMB->ParameterCount = cpu_to_le16(params);
2903 pSMB->TotalParameterCount = pSMB->ParameterCount;
2904 pSMB->Reserved4 = 0;
2905 pSMB->hdr.smb_buf_length += byte_count;
2906 pSMB->ByteCount = cpu_to_le16(byte_count);
2907 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2908 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2909 if (rc)
2910 cFYI(1, ("Set POSIX ACL returned %d", rc));
2912 setACLerrorExit:
2913 cifs_buf_release(pSMB);
2914 if (rc == -EAGAIN)
2915 goto setAclRetry;
2916 return rc;
2919 /* BB fix tabs in this function FIXME BB */
2921 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2922 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2924 int rc = 0;
2925 struct smb_t2_qfi_req *pSMB = NULL;
2926 struct smb_t2_qfi_rsp *pSMBr = NULL;
2927 int bytes_returned;
2928 __u16 params, byte_count;
2930 cFYI(1, ("In GetExtAttr"));
2931 if (tcon == NULL)
2932 return -ENODEV;
2934 GetExtAttrRetry:
2935 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2936 (void **) &pSMBr);
2937 if (rc)
2938 return rc;
2940 params = 2 /* level */ + 2 /* fid */;
2941 pSMB->t2.TotalDataCount = 0;
2942 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2943 /* BB find exact max data count below from sess structure BB */
2944 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2945 pSMB->t2.MaxSetupCount = 0;
2946 pSMB->t2.Reserved = 0;
2947 pSMB->t2.Flags = 0;
2948 pSMB->t2.Timeout = 0;
2949 pSMB->t2.Reserved2 = 0;
2950 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2951 Fid) - 4);
2952 pSMB->t2.DataCount = 0;
2953 pSMB->t2.DataOffset = 0;
2954 pSMB->t2.SetupCount = 1;
2955 pSMB->t2.Reserved3 = 0;
2956 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2957 byte_count = params + 1 /* pad */ ;
2958 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2959 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2960 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2961 pSMB->Pad = 0;
2962 pSMB->Fid = netfid;
2963 pSMB->hdr.smb_buf_length += byte_count;
2964 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2966 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2967 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2968 if (rc) {
2969 cFYI(1, ("error %d in GetExtAttr", rc));
2970 } else {
2971 /* decode response */
2972 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2973 if (rc || (pSMBr->ByteCount < 2))
2974 /* BB also check enough total bytes returned */
2975 /* If rc should we check for EOPNOSUPP and
2976 disable the srvino flag? or in caller? */
2977 rc = -EIO; /* bad smb */
2978 else {
2979 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2980 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2981 struct file_chattr_info *pfinfo;
2982 /* BB Do we need a cast or hash here ? */
2983 if (count != 16) {
2984 cFYI(1, ("Illegal size ret in GetExtAttr"));
2985 rc = -EIO;
2986 goto GetExtAttrOut;
2988 pfinfo = (struct file_chattr_info *)
2989 (data_offset + (char *) &pSMBr->hdr.Protocol);
2990 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2991 *pMask = le64_to_cpu(pfinfo->mask);
2994 GetExtAttrOut:
2995 cifs_buf_release(pSMB);
2996 if (rc == -EAGAIN)
2997 goto GetExtAttrRetry;
2998 return rc;
3001 #endif /* CONFIG_POSIX */
3003 #ifdef CONFIG_CIFS_EXPERIMENTAL
3004 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3006 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3007 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3009 int rc = 0;
3010 int buf_type = 0;
3011 QUERY_SEC_DESC_REQ *pSMB;
3012 struct kvec iov[1];
3014 cFYI(1, ("GetCifsACL"));
3016 *pbuflen = 0;
3017 *acl_inf = NULL;
3019 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3020 8 /* parm len */, tcon, (void **) &pSMB);
3021 if (rc)
3022 return rc;
3024 pSMB->MaxParameterCount = cpu_to_le32(4);
3025 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3026 pSMB->MaxSetupCount = 0;
3027 pSMB->Fid = fid; /* file handle always le */
3028 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3029 CIFS_ACL_DACL);
3030 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3031 pSMB->hdr.smb_buf_length += 11;
3032 iov[0].iov_base = (char *)pSMB;
3033 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3035 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3036 CIFS_STD_OP);
3037 cifs_stats_inc(&tcon->num_acl_get);
3038 if (rc) {
3039 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3040 } else { /* decode response */
3041 __le32 *parm;
3042 __u32 parm_len;
3043 __u32 acl_len;
3044 struct smb_com_ntransact_rsp *pSMBr;
3045 char *pdata;
3047 /* validate_nttransact */
3048 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3049 &pdata, &parm_len, pbuflen);
3050 if (rc)
3051 goto qsec_out;
3052 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3054 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3056 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3057 rc = -EIO; /* bad smb */
3058 *pbuflen = 0;
3059 goto qsec_out;
3062 /* BB check that data area is minimum length and as big as acl_len */
3064 acl_len = le32_to_cpu(*parm);
3065 if (acl_len != *pbuflen) {
3066 cERROR(1, ("acl length %d does not match %d",
3067 acl_len, *pbuflen));
3068 if (*pbuflen > acl_len)
3069 *pbuflen = acl_len;
3072 /* check if buffer is big enough for the acl
3073 header followed by the smallest SID */
3074 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3075 (*pbuflen >= 64 * 1024)) {
3076 cERROR(1, ("bad acl length %d", *pbuflen));
3077 rc = -EINVAL;
3078 *pbuflen = 0;
3079 } else {
3080 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3081 if (*acl_inf == NULL) {
3082 *pbuflen = 0;
3083 rc = -ENOMEM;
3085 memcpy(*acl_inf, pdata, *pbuflen);
3088 qsec_out:
3089 if (buf_type == CIFS_SMALL_BUFFER)
3090 cifs_small_buf_release(iov[0].iov_base);
3091 else if (buf_type == CIFS_LARGE_BUFFER)
3092 cifs_buf_release(iov[0].iov_base);
3093 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3094 return rc;
3098 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3099 struct cifs_ntsd *pntsd, __u32 acllen)
3101 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3102 int rc = 0;
3103 int bytes_returned = 0;
3104 SET_SEC_DESC_REQ *pSMB = NULL;
3105 NTRANSACT_RSP *pSMBr = NULL;
3107 setCifsAclRetry:
3108 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3109 (void **) &pSMBr);
3110 if (rc)
3111 return (rc);
3113 pSMB->MaxSetupCount = 0;
3114 pSMB->Reserved = 0;
3116 param_count = 8;
3117 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3118 data_count = acllen;
3119 data_offset = param_offset + param_count;
3120 byte_count = 3 /* pad */ + param_count;
3122 pSMB->DataCount = cpu_to_le32(data_count);
3123 pSMB->TotalDataCount = pSMB->DataCount;
3124 pSMB->MaxParameterCount = cpu_to_le32(4);
3125 pSMB->MaxDataCount = cpu_to_le32(16384);
3126 pSMB->ParameterCount = cpu_to_le32(param_count);
3127 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3128 pSMB->TotalParameterCount = pSMB->ParameterCount;
3129 pSMB->DataOffset = cpu_to_le32(data_offset);
3130 pSMB->SetupCount = 0;
3131 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3132 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3134 pSMB->Fid = fid; /* file handle always le */
3135 pSMB->Reserved2 = 0;
3136 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3138 if (pntsd && acllen) {
3139 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3140 (char *) pntsd,
3141 acllen);
3142 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3144 } else
3145 pSMB->hdr.smb_buf_length += byte_count;
3147 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3148 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3150 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3151 if (rc)
3152 cFYI(1, ("Set CIFS ACL returned %d", rc));
3153 cifs_buf_release(pSMB);
3155 if (rc == -EAGAIN)
3156 goto setCifsAclRetry;
3158 return (rc);
3161 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3163 /* Legacy Query Path Information call for lookup to old servers such
3164 as Win9x/WinME */
3165 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3166 const unsigned char *searchName,
3167 FILE_ALL_INFO *pFinfo,
3168 const struct nls_table *nls_codepage, int remap)
3170 QUERY_INFORMATION_REQ *pSMB;
3171 QUERY_INFORMATION_RSP *pSMBr;
3172 int rc = 0;
3173 int bytes_returned;
3174 int name_len;
3176 cFYI(1, ("In SMBQPath path %s", searchName));
3177 QInfRetry:
3178 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3179 (void **) &pSMBr);
3180 if (rc)
3181 return rc;
3183 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3184 name_len =
3185 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3186 PATH_MAX, nls_codepage, remap);
3187 name_len++; /* trailing null */
3188 name_len *= 2;
3189 } else {
3190 name_len = strnlen(searchName, PATH_MAX);
3191 name_len++; /* trailing null */
3192 strncpy(pSMB->FileName, searchName, name_len);
3194 pSMB->BufferFormat = 0x04;
3195 name_len++; /* account for buffer type byte */
3196 pSMB->hdr.smb_buf_length += (__u16) name_len;
3197 pSMB->ByteCount = cpu_to_le16(name_len);
3199 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3200 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3201 if (rc) {
3202 cFYI(1, ("Send error in QueryInfo = %d", rc));
3203 } else if (pFinfo) {
3204 struct timespec ts;
3205 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3207 /* decode response */
3208 /* BB FIXME - add time zone adjustment BB */
3209 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3210 ts.tv_nsec = 0;
3211 ts.tv_sec = time;
3212 /* decode time fields */
3213 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3214 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3215 pFinfo->LastAccessTime = 0;
3216 pFinfo->AllocationSize =
3217 cpu_to_le64(le32_to_cpu(pSMBr->size));
3218 pFinfo->EndOfFile = pFinfo->AllocationSize;
3219 pFinfo->Attributes =
3220 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3221 } else
3222 rc = -EIO; /* bad buffer passed in */
3224 cifs_buf_release(pSMB);
3226 if (rc == -EAGAIN)
3227 goto QInfRetry;
3229 return rc;
3236 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3237 const unsigned char *searchName,
3238 FILE_ALL_INFO *pFindData,
3239 int legacy /* old style infolevel */,
3240 const struct nls_table *nls_codepage, int remap)
3242 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3243 TRANSACTION2_QPI_REQ *pSMB = NULL;
3244 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3245 int rc = 0;
3246 int bytes_returned;
3247 int name_len;
3248 __u16 params, byte_count;
3250 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3251 QPathInfoRetry:
3252 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3253 (void **) &pSMBr);
3254 if (rc)
3255 return rc;
3257 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3258 name_len =
3259 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3260 PATH_MAX, nls_codepage, remap);
3261 name_len++; /* trailing null */
3262 name_len *= 2;
3263 } else { /* BB improve the check for buffer overruns BB */
3264 name_len = strnlen(searchName, PATH_MAX);
3265 name_len++; /* trailing null */
3266 strncpy(pSMB->FileName, searchName, name_len);
3269 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3270 pSMB->TotalDataCount = 0;
3271 pSMB->MaxParameterCount = cpu_to_le16(2);
3272 /* BB find exact max SMB PDU from sess structure BB */
3273 pSMB->MaxDataCount = cpu_to_le16(4000);
3274 pSMB->MaxSetupCount = 0;
3275 pSMB->Reserved = 0;
3276 pSMB->Flags = 0;
3277 pSMB->Timeout = 0;
3278 pSMB->Reserved2 = 0;
3279 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3280 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3281 pSMB->DataCount = 0;
3282 pSMB->DataOffset = 0;
3283 pSMB->SetupCount = 1;
3284 pSMB->Reserved3 = 0;
3285 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3286 byte_count = params + 1 /* pad */ ;
3287 pSMB->TotalParameterCount = cpu_to_le16(params);
3288 pSMB->ParameterCount = pSMB->TotalParameterCount;
3289 if (legacy)
3290 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3291 else
3292 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3293 pSMB->Reserved4 = 0;
3294 pSMB->hdr.smb_buf_length += byte_count;
3295 pSMB->ByteCount = cpu_to_le16(byte_count);
3297 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3298 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3299 if (rc) {
3300 cFYI(1, ("Send error in QPathInfo = %d", rc));
3301 } else { /* decode response */
3302 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3304 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3305 rc = -EIO;
3306 else if (!legacy && (pSMBr->ByteCount < 40))
3307 rc = -EIO; /* bad smb */
3308 else if (legacy && (pSMBr->ByteCount < 24))
3309 rc = -EIO; /* 24 or 26 expected but we do not read
3310 last field */
3311 else if (pFindData) {
3312 int size;
3313 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3315 /* On legacy responses we do not read the last field,
3316 EAsize, fortunately since it varies by subdialect and
3317 also note it differs on Set vs. Get, ie two bytes or 4
3318 bytes depending but we don't care here */
3319 if (legacy)
3320 size = sizeof(FILE_INFO_STANDARD);
3321 else
3322 size = sizeof(FILE_ALL_INFO);
3323 memcpy((char *) pFindData,
3324 (char *) &pSMBr->hdr.Protocol +
3325 data_offset, size);
3326 } else
3327 rc = -ENOMEM;
3329 cifs_buf_release(pSMB);
3330 if (rc == -EAGAIN)
3331 goto QPathInfoRetry;
3333 return rc;
3337 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3338 const unsigned char *searchName,
3339 FILE_UNIX_BASIC_INFO *pFindData,
3340 const struct nls_table *nls_codepage, int remap)
3342 /* SMB_QUERY_FILE_UNIX_BASIC */
3343 TRANSACTION2_QPI_REQ *pSMB = NULL;
3344 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3345 int rc = 0;
3346 int bytes_returned = 0;
3347 int name_len;
3348 __u16 params, byte_count;
3350 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3351 UnixQPathInfoRetry:
3352 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3353 (void **) &pSMBr);
3354 if (rc)
3355 return rc;
3357 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3358 name_len =
3359 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3360 PATH_MAX, nls_codepage, remap);
3361 name_len++; /* trailing null */
3362 name_len *= 2;
3363 } else { /* BB improve the check for buffer overruns BB */
3364 name_len = strnlen(searchName, PATH_MAX);
3365 name_len++; /* trailing null */
3366 strncpy(pSMB->FileName, searchName, name_len);
3369 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3370 pSMB->TotalDataCount = 0;
3371 pSMB->MaxParameterCount = cpu_to_le16(2);
3372 /* BB find exact max SMB PDU from sess structure BB */
3373 pSMB->MaxDataCount = cpu_to_le16(4000);
3374 pSMB->MaxSetupCount = 0;
3375 pSMB->Reserved = 0;
3376 pSMB->Flags = 0;
3377 pSMB->Timeout = 0;
3378 pSMB->Reserved2 = 0;
3379 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3380 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3381 pSMB->DataCount = 0;
3382 pSMB->DataOffset = 0;
3383 pSMB->SetupCount = 1;
3384 pSMB->Reserved3 = 0;
3385 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3386 byte_count = params + 1 /* pad */ ;
3387 pSMB->TotalParameterCount = cpu_to_le16(params);
3388 pSMB->ParameterCount = pSMB->TotalParameterCount;
3389 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3390 pSMB->Reserved4 = 0;
3391 pSMB->hdr.smb_buf_length += byte_count;
3392 pSMB->ByteCount = cpu_to_le16(byte_count);
3394 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3395 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3396 if (rc) {
3397 cFYI(1, ("Send error in QPathInfo = %d", rc));
3398 } else { /* decode response */
3399 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3401 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3402 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3403 "Unix Extensions can be disabled on mount "
3404 "by specifying the nosfu mount option."));
3405 rc = -EIO; /* bad smb */
3406 } else {
3407 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3408 memcpy((char *) pFindData,
3409 (char *) &pSMBr->hdr.Protocol +
3410 data_offset,
3411 sizeof(FILE_UNIX_BASIC_INFO));
3414 cifs_buf_release(pSMB);
3415 if (rc == -EAGAIN)
3416 goto UnixQPathInfoRetry;
3418 return rc;
3421 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3423 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3424 const char *searchName,
3425 const struct nls_table *nls_codepage,
3426 __u16 *pnetfid,
3427 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3429 /* level 257 SMB_ */
3430 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3431 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3432 T2_FFIRST_RSP_PARMS *parms;
3433 int rc = 0;
3434 int bytes_returned = 0;
3435 int name_len;
3436 __u16 params, byte_count;
3438 cFYI(1, ("In FindFirst for %s", searchName));
3440 findFirstRetry:
3441 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3442 (void **) &pSMBr);
3443 if (rc)
3444 return rc;
3446 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3447 name_len =
3448 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3449 PATH_MAX, nls_codepage, remap);
3450 /* We can not add the asterik earlier in case
3451 it got remapped to 0xF03A as if it were part of the
3452 directory name instead of a wildcard */
3453 name_len *= 2;
3454 pSMB->FileName[name_len] = dirsep;
3455 pSMB->FileName[name_len+1] = 0;
3456 pSMB->FileName[name_len+2] = '*';
3457 pSMB->FileName[name_len+3] = 0;
3458 name_len += 4; /* now the trailing null */
3459 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3460 pSMB->FileName[name_len+1] = 0;
3461 name_len += 2;
3462 } else { /* BB add check for overrun of SMB buf BB */
3463 name_len = strnlen(searchName, PATH_MAX);
3464 /* BB fix here and in unicode clause above ie
3465 if (name_len > buffersize-header)
3466 free buffer exit; BB */
3467 strncpy(pSMB->FileName, searchName, name_len);
3468 pSMB->FileName[name_len] = dirsep;
3469 pSMB->FileName[name_len+1] = '*';
3470 pSMB->FileName[name_len+2] = 0;
3471 name_len += 3;
3474 params = 12 + name_len /* includes null */ ;
3475 pSMB->TotalDataCount = 0; /* no EAs */
3476 pSMB->MaxParameterCount = cpu_to_le16(10);
3477 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3478 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3479 pSMB->MaxSetupCount = 0;
3480 pSMB->Reserved = 0;
3481 pSMB->Flags = 0;
3482 pSMB->Timeout = 0;
3483 pSMB->Reserved2 = 0;
3484 byte_count = params + 1 /* pad */ ;
3485 pSMB->TotalParameterCount = cpu_to_le16(params);
3486 pSMB->ParameterCount = pSMB->TotalParameterCount;
3487 pSMB->ParameterOffset = cpu_to_le16(
3488 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3489 - 4);
3490 pSMB->DataCount = 0;
3491 pSMB->DataOffset = 0;
3492 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3493 pSMB->Reserved3 = 0;
3494 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3495 pSMB->SearchAttributes =
3496 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3497 ATTR_DIRECTORY);
3498 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3499 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3500 CIFS_SEARCH_RETURN_RESUME);
3501 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3503 /* BB what should we set StorageType to? Does it matter? BB */
3504 pSMB->SearchStorageType = 0;
3505 pSMB->hdr.smb_buf_length += byte_count;
3506 pSMB->ByteCount = cpu_to_le16(byte_count);
3508 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3509 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3510 cifs_stats_inc(&tcon->num_ffirst);
3512 if (rc) {/* BB add logic to retry regular search if Unix search
3513 rejected unexpectedly by server */
3514 /* BB Add code to handle unsupported level rc */
3515 cFYI(1, ("Error in FindFirst = %d", rc));
3517 cifs_buf_release(pSMB);
3519 /* BB eventually could optimize out free and realloc of buf */
3520 /* for this case */
3521 if (rc == -EAGAIN)
3522 goto findFirstRetry;
3523 } else { /* decode response */
3524 /* BB remember to free buffer if error BB */
3525 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3526 if (rc == 0) {
3527 unsigned int lnoff;
3529 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3530 psrch_inf->unicode = true;
3531 else
3532 psrch_inf->unicode = false;
3534 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3535 psrch_inf->smallBuf = 0;
3536 psrch_inf->srch_entries_start =
3537 (char *) &pSMBr->hdr.Protocol +
3538 le16_to_cpu(pSMBr->t2.DataOffset);
3539 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3540 le16_to_cpu(pSMBr->t2.ParameterOffset));
3542 if (parms->EndofSearch)
3543 psrch_inf->endOfSearch = true;
3544 else
3545 psrch_inf->endOfSearch = false;
3547 psrch_inf->entries_in_buffer =
3548 le16_to_cpu(parms->SearchCount);
3549 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3550 psrch_inf->entries_in_buffer;
3551 lnoff = le16_to_cpu(parms->LastNameOffset);
3552 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3553 lnoff) {
3554 cERROR(1, ("ignoring corrupt resume name"));
3555 psrch_inf->last_entry = NULL;
3556 return rc;
3559 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3560 lnoff;
3562 *pnetfid = parms->SearchHandle;
3563 } else {
3564 cifs_buf_release(pSMB);
3568 return rc;
3571 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3572 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3574 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3575 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3576 T2_FNEXT_RSP_PARMS *parms;
3577 char *response_data;
3578 int rc = 0;
3579 int bytes_returned, name_len;
3580 __u16 params, byte_count;
3582 cFYI(1, ("In FindNext"));
3584 if (psrch_inf->endOfSearch)
3585 return -ENOENT;
3587 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3588 (void **) &pSMBr);
3589 if (rc)
3590 return rc;
3592 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3593 byte_count = 0;
3594 pSMB->TotalDataCount = 0; /* no EAs */
3595 pSMB->MaxParameterCount = cpu_to_le16(8);
3596 pSMB->MaxDataCount =
3597 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3598 0xFFFFFF00);
3599 pSMB->MaxSetupCount = 0;
3600 pSMB->Reserved = 0;
3601 pSMB->Flags = 0;
3602 pSMB->Timeout = 0;
3603 pSMB->Reserved2 = 0;
3604 pSMB->ParameterOffset = cpu_to_le16(
3605 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3606 pSMB->DataCount = 0;
3607 pSMB->DataOffset = 0;
3608 pSMB->SetupCount = 1;
3609 pSMB->Reserved3 = 0;
3610 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3611 pSMB->SearchHandle = searchHandle; /* always kept as le */
3612 pSMB->SearchCount =
3613 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3614 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3615 pSMB->ResumeKey = psrch_inf->resume_key;
3616 pSMB->SearchFlags =
3617 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3619 name_len = psrch_inf->resume_name_len;
3620 params += name_len;
3621 if (name_len < PATH_MAX) {
3622 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3623 byte_count += name_len;
3624 /* 14 byte parm len above enough for 2 byte null terminator */
3625 pSMB->ResumeFileName[name_len] = 0;
3626 pSMB->ResumeFileName[name_len+1] = 0;
3627 } else {
3628 rc = -EINVAL;
3629 goto FNext2_err_exit;
3631 byte_count = params + 1 /* pad */ ;
3632 pSMB->TotalParameterCount = cpu_to_le16(params);
3633 pSMB->ParameterCount = pSMB->TotalParameterCount;
3634 pSMB->hdr.smb_buf_length += byte_count;
3635 pSMB->ByteCount = cpu_to_le16(byte_count);
3637 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3638 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3639 cifs_stats_inc(&tcon->num_fnext);
3640 if (rc) {
3641 if (rc == -EBADF) {
3642 psrch_inf->endOfSearch = true;
3643 cifs_buf_release(pSMB);
3644 rc = 0; /* search probably was closed at end of search*/
3645 } else
3646 cFYI(1, ("FindNext returned = %d", rc));
3647 } else { /* decode response */
3648 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3650 if (rc == 0) {
3651 unsigned int lnoff;
3653 /* BB fixme add lock for file (srch_info) struct here */
3654 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3655 psrch_inf->unicode = true;
3656 else
3657 psrch_inf->unicode = false;
3658 response_data = (char *) &pSMBr->hdr.Protocol +
3659 le16_to_cpu(pSMBr->t2.ParameterOffset);
3660 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3661 response_data = (char *)&pSMBr->hdr.Protocol +
3662 le16_to_cpu(pSMBr->t2.DataOffset);
3663 if (psrch_inf->smallBuf)
3664 cifs_small_buf_release(
3665 psrch_inf->ntwrk_buf_start);
3666 else
3667 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3668 psrch_inf->srch_entries_start = response_data;
3669 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3670 psrch_inf->smallBuf = 0;
3671 if (parms->EndofSearch)
3672 psrch_inf->endOfSearch = true;
3673 else
3674 psrch_inf->endOfSearch = false;
3675 psrch_inf->entries_in_buffer =
3676 le16_to_cpu(parms->SearchCount);
3677 psrch_inf->index_of_last_entry +=
3678 psrch_inf->entries_in_buffer;
3679 lnoff = le16_to_cpu(parms->LastNameOffset);
3680 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3681 lnoff) {
3682 cERROR(1, ("ignoring corrupt resume name"));
3683 psrch_inf->last_entry = NULL;
3684 return rc;
3685 } else
3686 psrch_inf->last_entry =
3687 psrch_inf->srch_entries_start + lnoff;
3689 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3690 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3692 /* BB fixme add unlock here */
3697 /* BB On error, should we leave previous search buf (and count and
3698 last entry fields) intact or free the previous one? */
3700 /* Note: On -EAGAIN error only caller can retry on handle based calls
3701 since file handle passed in no longer valid */
3702 FNext2_err_exit:
3703 if (rc != 0)
3704 cifs_buf_release(pSMB);
3705 return rc;
3709 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3710 const __u16 searchHandle)
3712 int rc = 0;
3713 FINDCLOSE_REQ *pSMB = NULL;
3715 cFYI(1, ("In CIFSSMBFindClose"));
3716 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3718 /* no sense returning error if session restarted
3719 as file handle has been closed */
3720 if (rc == -EAGAIN)
3721 return 0;
3722 if (rc)
3723 return rc;
3725 pSMB->FileID = searchHandle;
3726 pSMB->ByteCount = 0;
3727 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3728 if (rc)
3729 cERROR(1, ("Send error in FindClose = %d", rc));
3731 cifs_stats_inc(&tcon->num_fclose);
3733 /* Since session is dead, search handle closed on server already */
3734 if (rc == -EAGAIN)
3735 rc = 0;
3737 return rc;
3741 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3742 const unsigned char *searchName,
3743 __u64 *inode_number,
3744 const struct nls_table *nls_codepage, int remap)
3746 int rc = 0;
3747 TRANSACTION2_QPI_REQ *pSMB = NULL;
3748 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3749 int name_len, bytes_returned;
3750 __u16 params, byte_count;
3752 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3753 if (tcon == NULL)
3754 return -ENODEV;
3756 GetInodeNumberRetry:
3757 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3758 (void **) &pSMBr);
3759 if (rc)
3760 return rc;
3762 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3763 name_len =
3764 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3765 PATH_MAX, nls_codepage, remap);
3766 name_len++; /* trailing null */
3767 name_len *= 2;
3768 } else { /* BB improve the check for buffer overruns BB */
3769 name_len = strnlen(searchName, PATH_MAX);
3770 name_len++; /* trailing null */
3771 strncpy(pSMB->FileName, searchName, name_len);
3774 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3775 pSMB->TotalDataCount = 0;
3776 pSMB->MaxParameterCount = cpu_to_le16(2);
3777 /* BB find exact max data count below from sess structure BB */
3778 pSMB->MaxDataCount = cpu_to_le16(4000);
3779 pSMB->MaxSetupCount = 0;
3780 pSMB->Reserved = 0;
3781 pSMB->Flags = 0;
3782 pSMB->Timeout = 0;
3783 pSMB->Reserved2 = 0;
3784 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3785 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3786 pSMB->DataCount = 0;
3787 pSMB->DataOffset = 0;
3788 pSMB->SetupCount = 1;
3789 pSMB->Reserved3 = 0;
3790 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3791 byte_count = params + 1 /* pad */ ;
3792 pSMB->TotalParameterCount = cpu_to_le16(params);
3793 pSMB->ParameterCount = pSMB->TotalParameterCount;
3794 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3795 pSMB->Reserved4 = 0;
3796 pSMB->hdr.smb_buf_length += byte_count;
3797 pSMB->ByteCount = cpu_to_le16(byte_count);
3799 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3800 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3801 if (rc) {
3802 cFYI(1, ("error %d in QueryInternalInfo", rc));
3803 } else {
3804 /* decode response */
3805 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3806 if (rc || (pSMBr->ByteCount < 2))
3807 /* BB also check enough total bytes returned */
3808 /* If rc should we check for EOPNOSUPP and
3809 disable the srvino flag? or in caller? */
3810 rc = -EIO; /* bad smb */
3811 else {
3812 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3813 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3814 struct file_internal_info *pfinfo;
3815 /* BB Do we need a cast or hash here ? */
3816 if (count < 8) {
3817 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3818 rc = -EIO;
3819 goto GetInodeNumOut;
3821 pfinfo = (struct file_internal_info *)
3822 (data_offset + (char *) &pSMBr->hdr.Protocol);
3823 *inode_number = le64_to_cpu(pfinfo->UniqueId);
3826 GetInodeNumOut:
3827 cifs_buf_release(pSMB);
3828 if (rc == -EAGAIN)
3829 goto GetInodeNumberRetry;
3830 return rc;
3833 /* parses DFS refferal V3 structure
3834 * caller is responsible for freeing target_nodes
3835 * returns:
3836 * on success - 0
3837 * on failure - errno
3839 static int
3840 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
3841 unsigned int *num_of_nodes,
3842 struct dfs_info3_param **target_nodes,
3843 const struct nls_table *nls_codepage, int remap,
3844 const char *searchName)
3846 int i, rc = 0;
3847 char *data_end;
3848 bool is_unicode;
3849 struct dfs_referral_level_3 *ref;
3851 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3852 is_unicode = true;
3853 else
3854 is_unicode = false;
3855 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3857 if (*num_of_nodes < 1) {
3858 cERROR(1, ("num_referrals: must be at least > 0,"
3859 "but we get num_referrals = %d\n", *num_of_nodes));
3860 rc = -EINVAL;
3861 goto parse_DFS_referrals_exit;
3864 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
3865 if (ref->VersionNumber != cpu_to_le16(3)) {
3866 cERROR(1, ("Referrals of V%d version are not supported,"
3867 "should be V3", le16_to_cpu(ref->VersionNumber)));
3868 rc = -EINVAL;
3869 goto parse_DFS_referrals_exit;
3872 /* get the upper boundary of the resp buffer */
3873 data_end = (char *)(&(pSMBr->PathConsumed)) +
3874 le16_to_cpu(pSMBr->t2.DataCount);
3876 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3877 *num_of_nodes,
3878 le32_to_cpu(pSMBr->DFSFlags)));
3880 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3881 *num_of_nodes, GFP_KERNEL);
3882 if (*target_nodes == NULL) {
3883 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3884 rc = -ENOMEM;
3885 goto parse_DFS_referrals_exit;
3888 /* collect neccessary data from referrals */
3889 for (i = 0; i < *num_of_nodes; i++) {
3890 char *temp;
3891 int max_len;
3892 struct dfs_info3_param *node = (*target_nodes)+i;
3894 node->flags = le32_to_cpu(pSMBr->DFSFlags);
3895 if (is_unicode) {
3896 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3897 GFP_KERNEL);
3898 if (tmp == NULL) {
3899 rc = -ENOMEM;
3900 goto parse_DFS_referrals_exit;
3902 cifsConvertToUCS((__le16 *) tmp, searchName,
3903 PATH_MAX, nls_codepage, remap);
3904 node->path_consumed = cifs_ucs2_bytes(tmp,
3905 le16_to_cpu(pSMBr->PathConsumed),
3906 nls_codepage);
3907 kfree(tmp);
3908 } else
3909 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3911 node->server_type = le16_to_cpu(ref->ServerType);
3912 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3914 /* copy DfsPath */
3915 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3916 max_len = data_end - temp;
3917 node->path_name = cifs_strndup_from_ucs(temp, max_len,
3918 is_unicode, nls_codepage);
3919 if (!node->path_name) {
3920 rc = -ENOMEM;
3921 goto parse_DFS_referrals_exit;
3924 /* copy link target UNC */
3925 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3926 max_len = data_end - temp;
3927 node->node_name = cifs_strndup_from_ucs(temp, max_len,
3928 is_unicode, nls_codepage);
3929 if (!node->node_name)
3930 rc = -ENOMEM;
3933 parse_DFS_referrals_exit:
3934 if (rc) {
3935 free_dfs_info_array(*target_nodes, *num_of_nodes);
3936 *target_nodes = NULL;
3937 *num_of_nodes = 0;
3939 return rc;
3943 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3944 const unsigned char *searchName,
3945 struct dfs_info3_param **target_nodes,
3946 unsigned int *num_of_nodes,
3947 const struct nls_table *nls_codepage, int remap)
3949 /* TRANS2_GET_DFS_REFERRAL */
3950 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3951 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3952 int rc = 0;
3953 int bytes_returned;
3954 int name_len;
3955 __u16 params, byte_count;
3956 *num_of_nodes = 0;
3957 *target_nodes = NULL;
3959 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3960 if (ses == NULL)
3961 return -ENODEV;
3962 getDFSRetry:
3963 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3964 (void **) &pSMBr);
3965 if (rc)
3966 return rc;
3968 /* server pointer checked in called function,
3969 but should never be null here anyway */
3970 pSMB->hdr.Mid = GetNextMid(ses->server);
3971 pSMB->hdr.Tid = ses->ipc_tid;
3972 pSMB->hdr.Uid = ses->Suid;
3973 if (ses->capabilities & CAP_STATUS32)
3974 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3975 if (ses->capabilities & CAP_DFS)
3976 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3978 if (ses->capabilities & CAP_UNICODE) {
3979 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3980 name_len =
3981 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3982 searchName, PATH_MAX, nls_codepage, remap);
3983 name_len++; /* trailing null */
3984 name_len *= 2;
3985 } else { /* BB improve the check for buffer overruns BB */
3986 name_len = strnlen(searchName, PATH_MAX);
3987 name_len++; /* trailing null */
3988 strncpy(pSMB->RequestFileName, searchName, name_len);
3991 if (ses->server) {
3992 if (ses->server->secMode &
3993 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3994 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3997 pSMB->hdr.Uid = ses->Suid;
3999 params = 2 /* level */ + name_len /*includes null */ ;
4000 pSMB->TotalDataCount = 0;
4001 pSMB->DataCount = 0;
4002 pSMB->DataOffset = 0;
4003 pSMB->MaxParameterCount = 0;
4004 /* BB find exact max SMB PDU from sess structure BB */
4005 pSMB->MaxDataCount = cpu_to_le16(4000);
4006 pSMB->MaxSetupCount = 0;
4007 pSMB->Reserved = 0;
4008 pSMB->Flags = 0;
4009 pSMB->Timeout = 0;
4010 pSMB->Reserved2 = 0;
4011 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4012 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4013 pSMB->SetupCount = 1;
4014 pSMB->Reserved3 = 0;
4015 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4016 byte_count = params + 3 /* pad */ ;
4017 pSMB->ParameterCount = cpu_to_le16(params);
4018 pSMB->TotalParameterCount = pSMB->ParameterCount;
4019 pSMB->MaxReferralLevel = cpu_to_le16(3);
4020 pSMB->hdr.smb_buf_length += byte_count;
4021 pSMB->ByteCount = cpu_to_le16(byte_count);
4023 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4024 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4025 if (rc) {
4026 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
4027 goto GetDFSRefExit;
4029 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4031 /* BB Also check if enough total bytes returned? */
4032 if (rc || (pSMBr->ByteCount < 17)) {
4033 rc = -EIO; /* bad smb */
4034 goto GetDFSRefExit;
4037 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4038 pSMBr->ByteCount,
4039 le16_to_cpu(pSMBr->t2.DataOffset)));
4041 /* parse returned result into more usable form */
4042 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4043 target_nodes, nls_codepage, remap,
4044 searchName);
4046 GetDFSRefExit:
4047 cifs_buf_release(pSMB);
4049 if (rc == -EAGAIN)
4050 goto getDFSRetry;
4052 return rc;
4055 /* Query File System Info such as free space to old servers such as Win 9x */
4057 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4059 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4060 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4061 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4062 FILE_SYSTEM_ALLOC_INFO *response_data;
4063 int rc = 0;
4064 int bytes_returned = 0;
4065 __u16 params, byte_count;
4067 cFYI(1, ("OldQFSInfo"));
4068 oldQFSInfoRetry:
4069 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4070 (void **) &pSMBr);
4071 if (rc)
4072 return rc;
4074 params = 2; /* level */
4075 pSMB->TotalDataCount = 0;
4076 pSMB->MaxParameterCount = cpu_to_le16(2);
4077 pSMB->MaxDataCount = cpu_to_le16(1000);
4078 pSMB->MaxSetupCount = 0;
4079 pSMB->Reserved = 0;
4080 pSMB->Flags = 0;
4081 pSMB->Timeout = 0;
4082 pSMB->Reserved2 = 0;
4083 byte_count = params + 1 /* pad */ ;
4084 pSMB->TotalParameterCount = cpu_to_le16(params);
4085 pSMB->ParameterCount = pSMB->TotalParameterCount;
4086 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4087 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4088 pSMB->DataCount = 0;
4089 pSMB->DataOffset = 0;
4090 pSMB->SetupCount = 1;
4091 pSMB->Reserved3 = 0;
4092 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4093 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4094 pSMB->hdr.smb_buf_length += byte_count;
4095 pSMB->ByteCount = cpu_to_le16(byte_count);
4097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4099 if (rc) {
4100 cFYI(1, ("Send error in QFSInfo = %d", rc));
4101 } else { /* decode response */
4102 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4104 if (rc || (pSMBr->ByteCount < 18))
4105 rc = -EIO; /* bad smb */
4106 else {
4107 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4108 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4109 pSMBr->ByteCount, data_offset));
4111 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4112 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4113 FSData->f_bsize =
4114 le16_to_cpu(response_data->BytesPerSector) *
4115 le32_to_cpu(response_data->
4116 SectorsPerAllocationUnit);
4117 FSData->f_blocks =
4118 le32_to_cpu(response_data->TotalAllocationUnits);
4119 FSData->f_bfree = FSData->f_bavail =
4120 le32_to_cpu(response_data->FreeAllocationUnits);
4121 cFYI(1,
4122 ("Blocks: %lld Free: %lld Block size %ld",
4123 (unsigned long long)FSData->f_blocks,
4124 (unsigned long long)FSData->f_bfree,
4125 FSData->f_bsize));
4128 cifs_buf_release(pSMB);
4130 if (rc == -EAGAIN)
4131 goto oldQFSInfoRetry;
4133 return rc;
4137 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4139 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4140 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4141 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4142 FILE_SYSTEM_INFO *response_data;
4143 int rc = 0;
4144 int bytes_returned = 0;
4145 __u16 params, byte_count;
4147 cFYI(1, ("In QFSInfo"));
4148 QFSInfoRetry:
4149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4150 (void **) &pSMBr);
4151 if (rc)
4152 return rc;
4154 params = 2; /* level */
4155 pSMB->TotalDataCount = 0;
4156 pSMB->MaxParameterCount = cpu_to_le16(2);
4157 pSMB->MaxDataCount = cpu_to_le16(1000);
4158 pSMB->MaxSetupCount = 0;
4159 pSMB->Reserved = 0;
4160 pSMB->Flags = 0;
4161 pSMB->Timeout = 0;
4162 pSMB->Reserved2 = 0;
4163 byte_count = params + 1 /* pad */ ;
4164 pSMB->TotalParameterCount = cpu_to_le16(params);
4165 pSMB->ParameterCount = pSMB->TotalParameterCount;
4166 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4167 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4168 pSMB->DataCount = 0;
4169 pSMB->DataOffset = 0;
4170 pSMB->SetupCount = 1;
4171 pSMB->Reserved3 = 0;
4172 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4173 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4174 pSMB->hdr.smb_buf_length += byte_count;
4175 pSMB->ByteCount = cpu_to_le16(byte_count);
4177 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4178 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4179 if (rc) {
4180 cFYI(1, ("Send error in QFSInfo = %d", rc));
4181 } else { /* decode response */
4182 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4184 if (rc || (pSMBr->ByteCount < 24))
4185 rc = -EIO; /* bad smb */
4186 else {
4187 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4189 response_data =
4190 (FILE_SYSTEM_INFO
4191 *) (((char *) &pSMBr->hdr.Protocol) +
4192 data_offset);
4193 FSData->f_bsize =
4194 le32_to_cpu(response_data->BytesPerSector) *
4195 le32_to_cpu(response_data->
4196 SectorsPerAllocationUnit);
4197 FSData->f_blocks =
4198 le64_to_cpu(response_data->TotalAllocationUnits);
4199 FSData->f_bfree = FSData->f_bavail =
4200 le64_to_cpu(response_data->FreeAllocationUnits);
4201 cFYI(1,
4202 ("Blocks: %lld Free: %lld Block size %ld",
4203 (unsigned long long)FSData->f_blocks,
4204 (unsigned long long)FSData->f_bfree,
4205 FSData->f_bsize));
4208 cifs_buf_release(pSMB);
4210 if (rc == -EAGAIN)
4211 goto QFSInfoRetry;
4213 return rc;
4217 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4219 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4220 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4221 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4222 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4223 int rc = 0;
4224 int bytes_returned = 0;
4225 __u16 params, byte_count;
4227 cFYI(1, ("In QFSAttributeInfo"));
4228 QFSAttributeRetry:
4229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4230 (void **) &pSMBr);
4231 if (rc)
4232 return rc;
4234 params = 2; /* level */
4235 pSMB->TotalDataCount = 0;
4236 pSMB->MaxParameterCount = cpu_to_le16(2);
4237 /* BB find exact max SMB PDU from sess structure BB */
4238 pSMB->MaxDataCount = cpu_to_le16(1000);
4239 pSMB->MaxSetupCount = 0;
4240 pSMB->Reserved = 0;
4241 pSMB->Flags = 0;
4242 pSMB->Timeout = 0;
4243 pSMB->Reserved2 = 0;
4244 byte_count = params + 1 /* pad */ ;
4245 pSMB->TotalParameterCount = cpu_to_le16(params);
4246 pSMB->ParameterCount = pSMB->TotalParameterCount;
4247 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4248 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4249 pSMB->DataCount = 0;
4250 pSMB->DataOffset = 0;
4251 pSMB->SetupCount = 1;
4252 pSMB->Reserved3 = 0;
4253 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4254 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4255 pSMB->hdr.smb_buf_length += byte_count;
4256 pSMB->ByteCount = cpu_to_le16(byte_count);
4258 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4259 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4260 if (rc) {
4261 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4262 } else { /* decode response */
4263 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4265 if (rc || (pSMBr->ByteCount < 13)) {
4266 /* BB also check if enough bytes returned */
4267 rc = -EIO; /* bad smb */
4268 } else {
4269 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4270 response_data =
4271 (FILE_SYSTEM_ATTRIBUTE_INFO
4272 *) (((char *) &pSMBr->hdr.Protocol) +
4273 data_offset);
4274 memcpy(&tcon->fsAttrInfo, response_data,
4275 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4278 cifs_buf_release(pSMB);
4280 if (rc == -EAGAIN)
4281 goto QFSAttributeRetry;
4283 return rc;
4287 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4289 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4290 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4291 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4292 FILE_SYSTEM_DEVICE_INFO *response_data;
4293 int rc = 0;
4294 int bytes_returned = 0;
4295 __u16 params, byte_count;
4297 cFYI(1, ("In QFSDeviceInfo"));
4298 QFSDeviceRetry:
4299 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4300 (void **) &pSMBr);
4301 if (rc)
4302 return rc;
4304 params = 2; /* level */
4305 pSMB->TotalDataCount = 0;
4306 pSMB->MaxParameterCount = cpu_to_le16(2);
4307 /* BB find exact max SMB PDU from sess structure BB */
4308 pSMB->MaxDataCount = cpu_to_le16(1000);
4309 pSMB->MaxSetupCount = 0;
4310 pSMB->Reserved = 0;
4311 pSMB->Flags = 0;
4312 pSMB->Timeout = 0;
4313 pSMB->Reserved2 = 0;
4314 byte_count = params + 1 /* pad */ ;
4315 pSMB->TotalParameterCount = cpu_to_le16(params);
4316 pSMB->ParameterCount = pSMB->TotalParameterCount;
4317 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4318 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4320 pSMB->DataCount = 0;
4321 pSMB->DataOffset = 0;
4322 pSMB->SetupCount = 1;
4323 pSMB->Reserved3 = 0;
4324 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4325 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4326 pSMB->hdr.smb_buf_length += byte_count;
4327 pSMB->ByteCount = cpu_to_le16(byte_count);
4329 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4330 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4331 if (rc) {
4332 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4333 } else { /* decode response */
4334 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4336 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4337 rc = -EIO; /* bad smb */
4338 else {
4339 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4340 response_data =
4341 (FILE_SYSTEM_DEVICE_INFO *)
4342 (((char *) &pSMBr->hdr.Protocol) +
4343 data_offset);
4344 memcpy(&tcon->fsDevInfo, response_data,
4345 sizeof(FILE_SYSTEM_DEVICE_INFO));
4348 cifs_buf_release(pSMB);
4350 if (rc == -EAGAIN)
4351 goto QFSDeviceRetry;
4353 return rc;
4357 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4359 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4360 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4361 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4362 FILE_SYSTEM_UNIX_INFO *response_data;
4363 int rc = 0;
4364 int bytes_returned = 0;
4365 __u16 params, byte_count;
4367 cFYI(1, ("In QFSUnixInfo"));
4368 QFSUnixRetry:
4369 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4370 (void **) &pSMBr);
4371 if (rc)
4372 return rc;
4374 params = 2; /* level */
4375 pSMB->TotalDataCount = 0;
4376 pSMB->DataCount = 0;
4377 pSMB->DataOffset = 0;
4378 pSMB->MaxParameterCount = cpu_to_le16(2);
4379 /* BB find exact max SMB PDU from sess structure BB */
4380 pSMB->MaxDataCount = cpu_to_le16(100);
4381 pSMB->MaxSetupCount = 0;
4382 pSMB->Reserved = 0;
4383 pSMB->Flags = 0;
4384 pSMB->Timeout = 0;
4385 pSMB->Reserved2 = 0;
4386 byte_count = params + 1 /* pad */ ;
4387 pSMB->ParameterCount = cpu_to_le16(params);
4388 pSMB->TotalParameterCount = pSMB->ParameterCount;
4389 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4390 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4391 pSMB->SetupCount = 1;
4392 pSMB->Reserved3 = 0;
4393 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4394 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4395 pSMB->hdr.smb_buf_length += byte_count;
4396 pSMB->ByteCount = cpu_to_le16(byte_count);
4398 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4399 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4400 if (rc) {
4401 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4402 } else { /* decode response */
4403 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4405 if (rc || (pSMBr->ByteCount < 13)) {
4406 rc = -EIO; /* bad smb */
4407 } else {
4408 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4409 response_data =
4410 (FILE_SYSTEM_UNIX_INFO
4411 *) (((char *) &pSMBr->hdr.Protocol) +
4412 data_offset);
4413 memcpy(&tcon->fsUnixInfo, response_data,
4414 sizeof(FILE_SYSTEM_UNIX_INFO));
4417 cifs_buf_release(pSMB);
4419 if (rc == -EAGAIN)
4420 goto QFSUnixRetry;
4423 return rc;
4427 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4429 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4430 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4431 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4432 int rc = 0;
4433 int bytes_returned = 0;
4434 __u16 params, param_offset, offset, byte_count;
4436 cFYI(1, ("In SETFSUnixInfo"));
4437 SETFSUnixRetry:
4438 /* BB switch to small buf init to save memory */
4439 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4440 (void **) &pSMBr);
4441 if (rc)
4442 return rc;
4444 params = 4; /* 2 bytes zero followed by info level. */
4445 pSMB->MaxSetupCount = 0;
4446 pSMB->Reserved = 0;
4447 pSMB->Flags = 0;
4448 pSMB->Timeout = 0;
4449 pSMB->Reserved2 = 0;
4450 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4451 - 4;
4452 offset = param_offset + params;
4454 pSMB->MaxParameterCount = cpu_to_le16(4);
4455 /* BB find exact max SMB PDU from sess structure BB */
4456 pSMB->MaxDataCount = cpu_to_le16(100);
4457 pSMB->SetupCount = 1;
4458 pSMB->Reserved3 = 0;
4459 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4460 byte_count = 1 /* pad */ + params + 12;
4462 pSMB->DataCount = cpu_to_le16(12);
4463 pSMB->ParameterCount = cpu_to_le16(params);
4464 pSMB->TotalDataCount = pSMB->DataCount;
4465 pSMB->TotalParameterCount = pSMB->ParameterCount;
4466 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4467 pSMB->DataOffset = cpu_to_le16(offset);
4469 /* Params. */
4470 pSMB->FileNum = 0;
4471 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4473 /* Data. */
4474 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4475 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4476 pSMB->ClientUnixCap = cpu_to_le64(cap);
4478 pSMB->hdr.smb_buf_length += byte_count;
4479 pSMB->ByteCount = cpu_to_le16(byte_count);
4481 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4482 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4483 if (rc) {
4484 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4485 } else { /* decode response */
4486 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4487 if (rc)
4488 rc = -EIO; /* bad smb */
4490 cifs_buf_release(pSMB);
4492 if (rc == -EAGAIN)
4493 goto SETFSUnixRetry;
4495 return rc;
4501 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4502 struct kstatfs *FSData)
4504 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4505 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4506 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4507 FILE_SYSTEM_POSIX_INFO *response_data;
4508 int rc = 0;
4509 int bytes_returned = 0;
4510 __u16 params, byte_count;
4512 cFYI(1, ("In QFSPosixInfo"));
4513 QFSPosixRetry:
4514 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4515 (void **) &pSMBr);
4516 if (rc)
4517 return rc;
4519 params = 2; /* level */
4520 pSMB->TotalDataCount = 0;
4521 pSMB->DataCount = 0;
4522 pSMB->DataOffset = 0;
4523 pSMB->MaxParameterCount = cpu_to_le16(2);
4524 /* BB find exact max SMB PDU from sess structure BB */
4525 pSMB->MaxDataCount = cpu_to_le16(100);
4526 pSMB->MaxSetupCount = 0;
4527 pSMB->Reserved = 0;
4528 pSMB->Flags = 0;
4529 pSMB->Timeout = 0;
4530 pSMB->Reserved2 = 0;
4531 byte_count = params + 1 /* pad */ ;
4532 pSMB->ParameterCount = cpu_to_le16(params);
4533 pSMB->TotalParameterCount = pSMB->ParameterCount;
4534 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4535 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4536 pSMB->SetupCount = 1;
4537 pSMB->Reserved3 = 0;
4538 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4539 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4540 pSMB->hdr.smb_buf_length += byte_count;
4541 pSMB->ByteCount = cpu_to_le16(byte_count);
4543 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4544 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4545 if (rc) {
4546 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4547 } else { /* decode response */
4548 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4550 if (rc || (pSMBr->ByteCount < 13)) {
4551 rc = -EIO; /* bad smb */
4552 } else {
4553 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4554 response_data =
4555 (FILE_SYSTEM_POSIX_INFO
4556 *) (((char *) &pSMBr->hdr.Protocol) +
4557 data_offset);
4558 FSData->f_bsize =
4559 le32_to_cpu(response_data->BlockSize);
4560 FSData->f_blocks =
4561 le64_to_cpu(response_data->TotalBlocks);
4562 FSData->f_bfree =
4563 le64_to_cpu(response_data->BlocksAvail);
4564 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4565 FSData->f_bavail = FSData->f_bfree;
4566 } else {
4567 FSData->f_bavail =
4568 le64_to_cpu(response_data->UserBlocksAvail);
4570 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4571 FSData->f_files =
4572 le64_to_cpu(response_data->TotalFileNodes);
4573 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4574 FSData->f_ffree =
4575 le64_to_cpu(response_data->FreeFileNodes);
4578 cifs_buf_release(pSMB);
4580 if (rc == -EAGAIN)
4581 goto QFSPosixRetry;
4583 return rc;
4587 /* We can not use write of zero bytes trick to
4588 set file size due to need for large file support. Also note that
4589 this SetPathInfo is preferred to SetFileInfo based method in next
4590 routine which is only needed to work around a sharing violation bug
4591 in Samba which this routine can run into */
4594 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4595 __u64 size, bool SetAllocation,
4596 const struct nls_table *nls_codepage, int remap)
4598 struct smb_com_transaction2_spi_req *pSMB = NULL;
4599 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4600 struct file_end_of_file_info *parm_data;
4601 int name_len;
4602 int rc = 0;
4603 int bytes_returned = 0;
4604 __u16 params, byte_count, data_count, param_offset, offset;
4606 cFYI(1, ("In SetEOF"));
4607 SetEOFRetry:
4608 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4609 (void **) &pSMBr);
4610 if (rc)
4611 return rc;
4613 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4614 name_len =
4615 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4616 PATH_MAX, nls_codepage, remap);
4617 name_len++; /* trailing null */
4618 name_len *= 2;
4619 } else { /* BB improve the check for buffer overruns BB */
4620 name_len = strnlen(fileName, PATH_MAX);
4621 name_len++; /* trailing null */
4622 strncpy(pSMB->FileName, fileName, name_len);
4624 params = 6 + name_len;
4625 data_count = sizeof(struct file_end_of_file_info);
4626 pSMB->MaxParameterCount = cpu_to_le16(2);
4627 pSMB->MaxDataCount = cpu_to_le16(4100);
4628 pSMB->MaxSetupCount = 0;
4629 pSMB->Reserved = 0;
4630 pSMB->Flags = 0;
4631 pSMB->Timeout = 0;
4632 pSMB->Reserved2 = 0;
4633 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4634 InformationLevel) - 4;
4635 offset = param_offset + params;
4636 if (SetAllocation) {
4637 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4638 pSMB->InformationLevel =
4639 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4640 else
4641 pSMB->InformationLevel =
4642 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4643 } else /* Set File Size */ {
4644 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4645 pSMB->InformationLevel =
4646 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4647 else
4648 pSMB->InformationLevel =
4649 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4652 parm_data =
4653 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4654 offset);
4655 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4656 pSMB->DataOffset = cpu_to_le16(offset);
4657 pSMB->SetupCount = 1;
4658 pSMB->Reserved3 = 0;
4659 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4660 byte_count = 3 /* pad */ + params + data_count;
4661 pSMB->DataCount = cpu_to_le16(data_count);
4662 pSMB->TotalDataCount = pSMB->DataCount;
4663 pSMB->ParameterCount = cpu_to_le16(params);
4664 pSMB->TotalParameterCount = pSMB->ParameterCount;
4665 pSMB->Reserved4 = 0;
4666 pSMB->hdr.smb_buf_length += byte_count;
4667 parm_data->FileSize = cpu_to_le64(size);
4668 pSMB->ByteCount = cpu_to_le16(byte_count);
4669 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4670 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4671 if (rc)
4672 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4674 cifs_buf_release(pSMB);
4676 if (rc == -EAGAIN)
4677 goto SetEOFRetry;
4679 return rc;
4683 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4684 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4686 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4687 char *data_offset;
4688 struct file_end_of_file_info *parm_data;
4689 int rc = 0;
4690 __u16 params, param_offset, offset, byte_count, count;
4692 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4693 (long long)size));
4694 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4696 if (rc)
4697 return rc;
4699 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4700 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4702 params = 6;
4703 pSMB->MaxSetupCount = 0;
4704 pSMB->Reserved = 0;
4705 pSMB->Flags = 0;
4706 pSMB->Timeout = 0;
4707 pSMB->Reserved2 = 0;
4708 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4709 offset = param_offset + params;
4711 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4713 count = sizeof(struct file_end_of_file_info);
4714 pSMB->MaxParameterCount = cpu_to_le16(2);
4715 /* BB find exact max SMB PDU from sess structure BB */
4716 pSMB->MaxDataCount = cpu_to_le16(1000);
4717 pSMB->SetupCount = 1;
4718 pSMB->Reserved3 = 0;
4719 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4720 byte_count = 3 /* pad */ + params + count;
4721 pSMB->DataCount = cpu_to_le16(count);
4722 pSMB->ParameterCount = cpu_to_le16(params);
4723 pSMB->TotalDataCount = pSMB->DataCount;
4724 pSMB->TotalParameterCount = pSMB->ParameterCount;
4725 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4726 parm_data =
4727 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4728 + offset);
4729 pSMB->DataOffset = cpu_to_le16(offset);
4730 parm_data->FileSize = cpu_to_le64(size);
4731 pSMB->Fid = fid;
4732 if (SetAllocation) {
4733 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4734 pSMB->InformationLevel =
4735 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4736 else
4737 pSMB->InformationLevel =
4738 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4739 } else /* Set File Size */ {
4740 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4741 pSMB->InformationLevel =
4742 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4743 else
4744 pSMB->InformationLevel =
4745 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4747 pSMB->Reserved4 = 0;
4748 pSMB->hdr.smb_buf_length += byte_count;
4749 pSMB->ByteCount = cpu_to_le16(byte_count);
4750 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4751 if (rc) {
4752 cFYI(1,
4753 ("Send error in SetFileInfo (SetFileSize) = %d",
4754 rc));
4757 /* Note: On -EAGAIN error only caller can retry on handle based calls
4758 since file handle passed in no longer valid */
4760 return rc;
4763 /* Some legacy servers such as NT4 require that the file times be set on
4764 an open handle, rather than by pathname - this is awkward due to
4765 potential access conflicts on the open, but it is unavoidable for these
4766 old servers since the only other choice is to go from 100 nanosecond DCE
4767 time and resort to the original setpathinfo level which takes the ancient
4768 DOS time format with 2 second granularity */
4770 CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4771 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4773 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4774 char *data_offset;
4775 int rc = 0;
4776 __u16 params, param_offset, offset, byte_count, count;
4778 cFYI(1, ("Set Times (via SetFileInfo)"));
4779 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4781 if (rc)
4782 return rc;
4784 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4785 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4787 params = 6;
4788 pSMB->MaxSetupCount = 0;
4789 pSMB->Reserved = 0;
4790 pSMB->Flags = 0;
4791 pSMB->Timeout = 0;
4792 pSMB->Reserved2 = 0;
4793 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4794 offset = param_offset + params;
4796 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4798 count = sizeof(FILE_BASIC_INFO);
4799 pSMB->MaxParameterCount = cpu_to_le16(2);
4800 /* BB find max SMB PDU from sess */
4801 pSMB->MaxDataCount = cpu_to_le16(1000);
4802 pSMB->SetupCount = 1;
4803 pSMB->Reserved3 = 0;
4804 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4805 byte_count = 3 /* pad */ + params + count;
4806 pSMB->DataCount = cpu_to_le16(count);
4807 pSMB->ParameterCount = cpu_to_le16(params);
4808 pSMB->TotalDataCount = pSMB->DataCount;
4809 pSMB->TotalParameterCount = pSMB->ParameterCount;
4810 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4811 pSMB->DataOffset = cpu_to_le16(offset);
4812 pSMB->Fid = fid;
4813 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4814 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4815 else
4816 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4817 pSMB->Reserved4 = 0;
4818 pSMB->hdr.smb_buf_length += byte_count;
4819 pSMB->ByteCount = cpu_to_le16(byte_count);
4820 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4821 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4822 if (rc)
4823 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4825 /* Note: On -EAGAIN error only caller can retry on handle based calls
4826 since file handle passed in no longer valid */
4828 return rc;
4832 CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4833 bool delete_file, __u16 fid, __u32 pid_of_opener)
4835 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4836 char *data_offset;
4837 int rc = 0;
4838 __u16 params, param_offset, offset, byte_count, count;
4840 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4841 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4843 if (rc)
4844 return rc;
4846 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4847 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4849 params = 6;
4850 pSMB->MaxSetupCount = 0;
4851 pSMB->Reserved = 0;
4852 pSMB->Flags = 0;
4853 pSMB->Timeout = 0;
4854 pSMB->Reserved2 = 0;
4855 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4856 offset = param_offset + params;
4858 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4860 count = 1;
4861 pSMB->MaxParameterCount = cpu_to_le16(2);
4862 /* BB find max SMB PDU from sess */
4863 pSMB->MaxDataCount = cpu_to_le16(1000);
4864 pSMB->SetupCount = 1;
4865 pSMB->Reserved3 = 0;
4866 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4867 byte_count = 3 /* pad */ + params + count;
4868 pSMB->DataCount = cpu_to_le16(count);
4869 pSMB->ParameterCount = cpu_to_le16(params);
4870 pSMB->TotalDataCount = pSMB->DataCount;
4871 pSMB->TotalParameterCount = pSMB->ParameterCount;
4872 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4873 pSMB->DataOffset = cpu_to_le16(offset);
4874 pSMB->Fid = fid;
4875 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4876 pSMB->Reserved4 = 0;
4877 pSMB->hdr.smb_buf_length += byte_count;
4878 pSMB->ByteCount = cpu_to_le16(byte_count);
4879 *data_offset = delete_file ? 1 : 0;
4880 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4881 if (rc)
4882 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4884 return rc;
4888 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4889 const char *fileName, const FILE_BASIC_INFO *data,
4890 const struct nls_table *nls_codepage, int remap)
4892 TRANSACTION2_SPI_REQ *pSMB = NULL;
4893 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4894 int name_len;
4895 int rc = 0;
4896 int bytes_returned = 0;
4897 char *data_offset;
4898 __u16 params, param_offset, offset, byte_count, count;
4900 cFYI(1, ("In SetTimes"));
4902 SetTimesRetry:
4903 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4904 (void **) &pSMBr);
4905 if (rc)
4906 return rc;
4908 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4909 name_len =
4910 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4911 PATH_MAX, nls_codepage, remap);
4912 name_len++; /* trailing null */
4913 name_len *= 2;
4914 } else { /* BB improve the check for buffer overruns BB */
4915 name_len = strnlen(fileName, PATH_MAX);
4916 name_len++; /* trailing null */
4917 strncpy(pSMB->FileName, fileName, name_len);
4920 params = 6 + name_len;
4921 count = sizeof(FILE_BASIC_INFO);
4922 pSMB->MaxParameterCount = cpu_to_le16(2);
4923 /* BB find max SMB PDU from sess structure BB */
4924 pSMB->MaxDataCount = cpu_to_le16(1000);
4925 pSMB->MaxSetupCount = 0;
4926 pSMB->Reserved = 0;
4927 pSMB->Flags = 0;
4928 pSMB->Timeout = 0;
4929 pSMB->Reserved2 = 0;
4930 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4931 InformationLevel) - 4;
4932 offset = param_offset + params;
4933 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4934 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4935 pSMB->DataOffset = cpu_to_le16(offset);
4936 pSMB->SetupCount = 1;
4937 pSMB->Reserved3 = 0;
4938 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4939 byte_count = 3 /* pad */ + params + count;
4941 pSMB->DataCount = cpu_to_le16(count);
4942 pSMB->ParameterCount = cpu_to_le16(params);
4943 pSMB->TotalDataCount = pSMB->DataCount;
4944 pSMB->TotalParameterCount = pSMB->ParameterCount;
4945 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4946 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4947 else
4948 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4949 pSMB->Reserved4 = 0;
4950 pSMB->hdr.smb_buf_length += byte_count;
4951 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4952 pSMB->ByteCount = cpu_to_le16(byte_count);
4953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4955 if (rc)
4956 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4958 cifs_buf_release(pSMB);
4960 if (rc == -EAGAIN)
4961 goto SetTimesRetry;
4963 return rc;
4966 /* Can not be used to set time stamps yet (due to old DOS time format) */
4967 /* Can be used to set attributes */
4968 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4969 handling it anyway and NT4 was what we thought it would be needed for
4970 Do not delete it until we prove whether needed for Win9x though */
4972 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4973 __u16 dos_attrs, const struct nls_table *nls_codepage)
4975 SETATTR_REQ *pSMB = NULL;
4976 SETATTR_RSP *pSMBr = NULL;
4977 int rc = 0;
4978 int bytes_returned;
4979 int name_len;
4981 cFYI(1, ("In SetAttrLegacy"));
4983 SetAttrLgcyRetry:
4984 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4985 (void **) &pSMBr);
4986 if (rc)
4987 return rc;
4989 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4990 name_len =
4991 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4992 PATH_MAX, nls_codepage);
4993 name_len++; /* trailing null */
4994 name_len *= 2;
4995 } else { /* BB improve the check for buffer overruns BB */
4996 name_len = strnlen(fileName, PATH_MAX);
4997 name_len++; /* trailing null */
4998 strncpy(pSMB->fileName, fileName, name_len);
5000 pSMB->attr = cpu_to_le16(dos_attrs);
5001 pSMB->BufferFormat = 0x04;
5002 pSMB->hdr.smb_buf_length += name_len + 1;
5003 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5004 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5005 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5006 if (rc)
5007 cFYI(1, ("Error in LegacySetAttr = %d", rc));
5009 cifs_buf_release(pSMB);
5011 if (rc == -EAGAIN)
5012 goto SetAttrLgcyRetry;
5014 return rc;
5016 #endif /* temporarily unneeded SetAttr legacy function */
5018 static void
5019 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5020 const struct cifs_unix_set_info_args *args)
5022 u64 mode = args->mode;
5025 * Samba server ignores set of file size to zero due to bugs in some
5026 * older clients, but we should be precise - we use SetFileSize to
5027 * set file size and do not want to truncate file size to zero
5028 * accidently as happened on one Samba server beta by putting
5029 * zero instead of -1 here
5031 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5032 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5033 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5034 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5035 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5036 data_offset->Uid = cpu_to_le64(args->uid);
5037 data_offset->Gid = cpu_to_le64(args->gid);
5038 /* better to leave device as zero when it is */
5039 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5040 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5041 data_offset->Permissions = cpu_to_le64(mode);
5043 if (S_ISREG(mode))
5044 data_offset->Type = cpu_to_le32(UNIX_FILE);
5045 else if (S_ISDIR(mode))
5046 data_offset->Type = cpu_to_le32(UNIX_DIR);
5047 else if (S_ISLNK(mode))
5048 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5049 else if (S_ISCHR(mode))
5050 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5051 else if (S_ISBLK(mode))
5052 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5053 else if (S_ISFIFO(mode))
5054 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5055 else if (S_ISSOCK(mode))
5056 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5060 CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5061 const struct cifs_unix_set_info_args *args,
5062 u16 fid, u32 pid_of_opener)
5064 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5065 FILE_UNIX_BASIC_INFO *data_offset;
5066 int rc = 0;
5067 u16 params, param_offset, offset, byte_count, count;
5069 cFYI(1, ("Set Unix Info (via SetFileInfo)"));
5070 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5072 if (rc)
5073 return rc;
5075 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5076 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5078 params = 6;
5079 pSMB->MaxSetupCount = 0;
5080 pSMB->Reserved = 0;
5081 pSMB->Flags = 0;
5082 pSMB->Timeout = 0;
5083 pSMB->Reserved2 = 0;
5084 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5085 offset = param_offset + params;
5087 data_offset = (FILE_UNIX_BASIC_INFO *)
5088 ((char *)(&pSMB->hdr.Protocol) + offset);
5089 count = sizeof(FILE_UNIX_BASIC_INFO);
5091 pSMB->MaxParameterCount = cpu_to_le16(2);
5092 /* BB find max SMB PDU from sess */
5093 pSMB->MaxDataCount = cpu_to_le16(1000);
5094 pSMB->SetupCount = 1;
5095 pSMB->Reserved3 = 0;
5096 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5097 byte_count = 3 /* pad */ + params + count;
5098 pSMB->DataCount = cpu_to_le16(count);
5099 pSMB->ParameterCount = cpu_to_le16(params);
5100 pSMB->TotalDataCount = pSMB->DataCount;
5101 pSMB->TotalParameterCount = pSMB->ParameterCount;
5102 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5103 pSMB->DataOffset = cpu_to_le16(offset);
5104 pSMB->Fid = fid;
5105 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5106 pSMB->Reserved4 = 0;
5107 pSMB->hdr.smb_buf_length += byte_count;
5108 pSMB->ByteCount = cpu_to_le16(byte_count);
5110 cifs_fill_unix_set_info(data_offset, args);
5112 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5113 if (rc)
5114 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
5116 /* Note: On -EAGAIN error only caller can retry on handle based calls
5117 since file handle passed in no longer valid */
5119 return rc;
5123 CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5124 const struct cifs_unix_set_info_args *args,
5125 const struct nls_table *nls_codepage, int remap)
5127 TRANSACTION2_SPI_REQ *pSMB = NULL;
5128 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5129 int name_len;
5130 int rc = 0;
5131 int bytes_returned = 0;
5132 FILE_UNIX_BASIC_INFO *data_offset;
5133 __u16 params, param_offset, offset, count, byte_count;
5135 cFYI(1, ("In SetUID/GID/Mode"));
5136 setPermsRetry:
5137 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5138 (void **) &pSMBr);
5139 if (rc)
5140 return rc;
5142 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5143 name_len =
5144 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5145 PATH_MAX, nls_codepage, remap);
5146 name_len++; /* trailing null */
5147 name_len *= 2;
5148 } else { /* BB improve the check for buffer overruns BB */
5149 name_len = strnlen(fileName, PATH_MAX);
5150 name_len++; /* trailing null */
5151 strncpy(pSMB->FileName, fileName, name_len);
5154 params = 6 + name_len;
5155 count = sizeof(FILE_UNIX_BASIC_INFO);
5156 pSMB->MaxParameterCount = cpu_to_le16(2);
5157 /* BB find max SMB PDU from sess structure BB */
5158 pSMB->MaxDataCount = cpu_to_le16(1000);
5159 pSMB->MaxSetupCount = 0;
5160 pSMB->Reserved = 0;
5161 pSMB->Flags = 0;
5162 pSMB->Timeout = 0;
5163 pSMB->Reserved2 = 0;
5164 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5165 InformationLevel) - 4;
5166 offset = param_offset + params;
5167 data_offset =
5168 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5169 offset);
5170 memset(data_offset, 0, count);
5171 pSMB->DataOffset = cpu_to_le16(offset);
5172 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5173 pSMB->SetupCount = 1;
5174 pSMB->Reserved3 = 0;
5175 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5176 byte_count = 3 /* pad */ + params + count;
5177 pSMB->ParameterCount = cpu_to_le16(params);
5178 pSMB->DataCount = cpu_to_le16(count);
5179 pSMB->TotalParameterCount = pSMB->ParameterCount;
5180 pSMB->TotalDataCount = pSMB->DataCount;
5181 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5182 pSMB->Reserved4 = 0;
5183 pSMB->hdr.smb_buf_length += byte_count;
5185 cifs_fill_unix_set_info(data_offset, args);
5187 pSMB->ByteCount = cpu_to_le16(byte_count);
5188 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5189 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5190 if (rc)
5191 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5193 cifs_buf_release(pSMB);
5194 if (rc == -EAGAIN)
5195 goto setPermsRetry;
5196 return rc;
5199 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5200 const int notify_subdirs, const __u16 netfid,
5201 __u32 filter, struct file *pfile, int multishot,
5202 const struct nls_table *nls_codepage)
5204 int rc = 0;
5205 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5206 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5207 struct dir_notify_req *dnotify_req;
5208 int bytes_returned;
5210 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5211 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5212 (void **) &pSMBr);
5213 if (rc)
5214 return rc;
5216 pSMB->TotalParameterCount = 0 ;
5217 pSMB->TotalDataCount = 0;
5218 pSMB->MaxParameterCount = cpu_to_le32(2);
5219 /* BB find exact data count max from sess structure BB */
5220 pSMB->MaxDataCount = 0; /* same in little endian or be */
5221 /* BB VERIFY verify which is correct for above BB */
5222 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5223 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5225 pSMB->MaxSetupCount = 4;
5226 pSMB->Reserved = 0;
5227 pSMB->ParameterOffset = 0;
5228 pSMB->DataCount = 0;
5229 pSMB->DataOffset = 0;
5230 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5231 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5232 pSMB->ParameterCount = pSMB->TotalParameterCount;
5233 if (notify_subdirs)
5234 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5235 pSMB->Reserved2 = 0;
5236 pSMB->CompletionFilter = cpu_to_le32(filter);
5237 pSMB->Fid = netfid; /* file handle always le */
5238 pSMB->ByteCount = 0;
5240 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5241 (struct smb_hdr *)pSMBr, &bytes_returned,
5242 CIFS_ASYNC_OP);
5243 if (rc) {
5244 cFYI(1, ("Error in Notify = %d", rc));
5245 } else {
5246 /* Add file to outstanding requests */
5247 /* BB change to kmem cache alloc */
5248 dnotify_req = kmalloc(
5249 sizeof(struct dir_notify_req),
5250 GFP_KERNEL);
5251 if (dnotify_req) {
5252 dnotify_req->Pid = pSMB->hdr.Pid;
5253 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5254 dnotify_req->Mid = pSMB->hdr.Mid;
5255 dnotify_req->Tid = pSMB->hdr.Tid;
5256 dnotify_req->Uid = pSMB->hdr.Uid;
5257 dnotify_req->netfid = netfid;
5258 dnotify_req->pfile = pfile;
5259 dnotify_req->filter = filter;
5260 dnotify_req->multishot = multishot;
5261 spin_lock(&GlobalMid_Lock);
5262 list_add_tail(&dnotify_req->lhead,
5263 &GlobalDnotifyReqList);
5264 spin_unlock(&GlobalMid_Lock);
5265 } else
5266 rc = -ENOMEM;
5268 cifs_buf_release(pSMB);
5269 return rc;
5271 #ifdef CONFIG_CIFS_XATTR
5272 ssize_t
5273 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5274 const unsigned char *searchName,
5275 char *EAData, size_t buf_size,
5276 const struct nls_table *nls_codepage, int remap)
5278 /* BB assumes one setup word */
5279 TRANSACTION2_QPI_REQ *pSMB = NULL;
5280 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5281 int rc = 0;
5282 int bytes_returned;
5283 int name_len;
5284 struct fea *temp_fea;
5285 char *temp_ptr;
5286 __u16 params, byte_count;
5288 cFYI(1, ("In Query All EAs path %s", searchName));
5289 QAllEAsRetry:
5290 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5291 (void **) &pSMBr);
5292 if (rc)
5293 return rc;
5295 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5296 name_len =
5297 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5298 PATH_MAX, nls_codepage, remap);
5299 name_len++; /* trailing null */
5300 name_len *= 2;
5301 } else { /* BB improve the check for buffer overruns BB */
5302 name_len = strnlen(searchName, PATH_MAX);
5303 name_len++; /* trailing null */
5304 strncpy(pSMB->FileName, searchName, name_len);
5307 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5308 pSMB->TotalDataCount = 0;
5309 pSMB->MaxParameterCount = cpu_to_le16(2);
5310 /* BB find exact max SMB PDU from sess structure BB */
5311 pSMB->MaxDataCount = cpu_to_le16(4000);
5312 pSMB->MaxSetupCount = 0;
5313 pSMB->Reserved = 0;
5314 pSMB->Flags = 0;
5315 pSMB->Timeout = 0;
5316 pSMB->Reserved2 = 0;
5317 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5318 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5319 pSMB->DataCount = 0;
5320 pSMB->DataOffset = 0;
5321 pSMB->SetupCount = 1;
5322 pSMB->Reserved3 = 0;
5323 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5324 byte_count = params + 1 /* pad */ ;
5325 pSMB->TotalParameterCount = cpu_to_le16(params);
5326 pSMB->ParameterCount = pSMB->TotalParameterCount;
5327 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5328 pSMB->Reserved4 = 0;
5329 pSMB->hdr.smb_buf_length += byte_count;
5330 pSMB->ByteCount = cpu_to_le16(byte_count);
5332 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5333 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5334 if (rc) {
5335 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5336 } else { /* decode response */
5337 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5339 /* BB also check enough total bytes returned */
5340 /* BB we need to improve the validity checking
5341 of these trans2 responses */
5342 if (rc || (pSMBr->ByteCount < 4))
5343 rc = -EIO; /* bad smb */
5344 /* else if (pFindData){
5345 memcpy((char *) pFindData,
5346 (char *) &pSMBr->hdr.Protocol +
5347 data_offset, kl);
5348 }*/ else {
5349 /* check that length of list is not more than bcc */
5350 /* check that each entry does not go beyond length
5351 of list */
5352 /* check that each element of each entry does not
5353 go beyond end of list */
5354 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5355 struct fealist *ea_response_data;
5356 rc = 0;
5357 /* validate_trans2_offsets() */
5358 /* BB check if start of smb + data_offset > &bcc+ bcc */
5359 ea_response_data = (struct fealist *)
5360 (((char *) &pSMBr->hdr.Protocol) +
5361 data_offset);
5362 name_len = le32_to_cpu(ea_response_data->list_len);
5363 cFYI(1, ("ea length %d", name_len));
5364 if (name_len <= 8) {
5365 /* returned EA size zeroed at top of function */
5366 cFYI(1, ("empty EA list returned from server"));
5367 } else {
5368 /* account for ea list len */
5369 name_len -= 4;
5370 temp_fea = ea_response_data->list;
5371 temp_ptr = (char *)temp_fea;
5372 while (name_len > 0) {
5373 __u16 value_len;
5374 name_len -= 4;
5375 temp_ptr += 4;
5376 rc += temp_fea->name_len;
5377 /* account for prefix user. and trailing null */
5378 rc = rc + 5 + 1;
5379 if (rc < (int)buf_size) {
5380 memcpy(EAData, "user.", 5);
5381 EAData += 5;
5382 memcpy(EAData, temp_ptr,
5383 temp_fea->name_len);
5384 EAData += temp_fea->name_len;
5385 /* null terminate name */
5386 *EAData = 0;
5387 EAData = EAData + 1;
5388 } else if (buf_size == 0) {
5389 /* skip copy - calc size only */
5390 } else {
5391 /* stop before overrun buffer */
5392 rc = -ERANGE;
5393 break;
5395 name_len -= temp_fea->name_len;
5396 temp_ptr += temp_fea->name_len;
5397 /* account for trailing null */
5398 name_len--;
5399 temp_ptr++;
5400 value_len =
5401 le16_to_cpu(temp_fea->value_len);
5402 name_len -= value_len;
5403 temp_ptr += value_len;
5404 /* BB check that temp_ptr is still
5405 within the SMB BB*/
5407 /* no trailing null to account for
5408 in value len */
5409 /* go on to next EA */
5410 temp_fea = (struct fea *)temp_ptr;
5415 cifs_buf_release(pSMB);
5416 if (rc == -EAGAIN)
5417 goto QAllEAsRetry;
5419 return (ssize_t)rc;
5422 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5423 const unsigned char *searchName, const unsigned char *ea_name,
5424 unsigned char *ea_value, size_t buf_size,
5425 const struct nls_table *nls_codepage, int remap)
5427 TRANSACTION2_QPI_REQ *pSMB = NULL;
5428 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5429 int rc = 0;
5430 int bytes_returned;
5431 int name_len;
5432 struct fea *temp_fea;
5433 char *temp_ptr;
5434 __u16 params, byte_count;
5436 cFYI(1, ("In Query EA path %s", searchName));
5437 QEARetry:
5438 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5439 (void **) &pSMBr);
5440 if (rc)
5441 return rc;
5443 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5444 name_len =
5445 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5446 PATH_MAX, nls_codepage, remap);
5447 name_len++; /* trailing null */
5448 name_len *= 2;
5449 } else { /* BB improve the check for buffer overruns BB */
5450 name_len = strnlen(searchName, PATH_MAX);
5451 name_len++; /* trailing null */
5452 strncpy(pSMB->FileName, searchName, name_len);
5455 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5456 pSMB->TotalDataCount = 0;
5457 pSMB->MaxParameterCount = cpu_to_le16(2);
5458 /* BB find exact max SMB PDU from sess structure BB */
5459 pSMB->MaxDataCount = cpu_to_le16(4000);
5460 pSMB->MaxSetupCount = 0;
5461 pSMB->Reserved = 0;
5462 pSMB->Flags = 0;
5463 pSMB->Timeout = 0;
5464 pSMB->Reserved2 = 0;
5465 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5466 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5467 pSMB->DataCount = 0;
5468 pSMB->DataOffset = 0;
5469 pSMB->SetupCount = 1;
5470 pSMB->Reserved3 = 0;
5471 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5472 byte_count = params + 1 /* pad */ ;
5473 pSMB->TotalParameterCount = cpu_to_le16(params);
5474 pSMB->ParameterCount = pSMB->TotalParameterCount;
5475 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5476 pSMB->Reserved4 = 0;
5477 pSMB->hdr.smb_buf_length += byte_count;
5478 pSMB->ByteCount = cpu_to_le16(byte_count);
5480 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5481 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5482 if (rc) {
5483 cFYI(1, ("Send error in Query EA = %d", rc));
5484 } else { /* decode response */
5485 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5487 /* BB also check enough total bytes returned */
5488 /* BB we need to improve the validity checking
5489 of these trans2 responses */
5490 if (rc || (pSMBr->ByteCount < 4))
5491 rc = -EIO; /* bad smb */
5492 /* else if (pFindData){
5493 memcpy((char *) pFindData,
5494 (char *) &pSMBr->hdr.Protocol +
5495 data_offset, kl);
5496 }*/ else {
5497 /* check that length of list is not more than bcc */
5498 /* check that each entry does not go beyond length
5499 of list */
5500 /* check that each element of each entry does not
5501 go beyond end of list */
5502 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5503 struct fealist *ea_response_data;
5504 rc = -ENODATA;
5505 /* validate_trans2_offsets() */
5506 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5507 ea_response_data = (struct fealist *)
5508 (((char *) &pSMBr->hdr.Protocol) +
5509 data_offset);
5510 name_len = le32_to_cpu(ea_response_data->list_len);
5511 cFYI(1, ("ea length %d", name_len));
5512 if (name_len <= 8) {
5513 /* returned EA size zeroed at top of function */
5514 cFYI(1, ("empty EA list returned from server"));
5515 } else {
5516 /* account for ea list len */
5517 name_len -= 4;
5518 temp_fea = ea_response_data->list;
5519 temp_ptr = (char *)temp_fea;
5520 /* loop through checking if we have a matching
5521 name and then return the associated value */
5522 while (name_len > 0) {
5523 __u16 value_len;
5524 name_len -= 4;
5525 temp_ptr += 4;
5526 value_len =
5527 le16_to_cpu(temp_fea->value_len);
5528 /* BB validate that value_len falls within SMB,
5529 even though maximum for name_len is 255 */
5530 if (memcmp(temp_fea->name, ea_name,
5531 temp_fea->name_len) == 0) {
5532 /* found a match */
5533 rc = value_len;
5534 /* account for prefix user. and trailing null */
5535 if (rc <= (int)buf_size) {
5536 memcpy(ea_value,
5537 temp_fea->name+temp_fea->name_len+1,
5538 rc);
5539 /* ea values, unlike ea
5540 names, are not null
5541 terminated */
5542 } else if (buf_size == 0) {
5543 /* skip copy - calc size only */
5544 } else {
5545 /* stop before overrun buffer */
5546 rc = -ERANGE;
5548 break;
5550 name_len -= temp_fea->name_len;
5551 temp_ptr += temp_fea->name_len;
5552 /* account for trailing null */
5553 name_len--;
5554 temp_ptr++;
5555 name_len -= value_len;
5556 temp_ptr += value_len;
5557 /* No trailing null to account for in
5558 value_len. Go on to next EA */
5559 temp_fea = (struct fea *)temp_ptr;
5564 cifs_buf_release(pSMB);
5565 if (rc == -EAGAIN)
5566 goto QEARetry;
5568 return (ssize_t)rc;
5572 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5573 const char *ea_name, const void *ea_value,
5574 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5575 int remap)
5577 struct smb_com_transaction2_spi_req *pSMB = NULL;
5578 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5579 struct fealist *parm_data;
5580 int name_len;
5581 int rc = 0;
5582 int bytes_returned = 0;
5583 __u16 params, param_offset, byte_count, offset, count;
5585 cFYI(1, ("In SetEA"));
5586 SetEARetry:
5587 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5588 (void **) &pSMBr);
5589 if (rc)
5590 return rc;
5592 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5593 name_len =
5594 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5595 PATH_MAX, nls_codepage, remap);
5596 name_len++; /* trailing null */
5597 name_len *= 2;
5598 } else { /* BB improve the check for buffer overruns BB */
5599 name_len = strnlen(fileName, PATH_MAX);
5600 name_len++; /* trailing null */
5601 strncpy(pSMB->FileName, fileName, name_len);
5604 params = 6 + name_len;
5606 /* done calculating parms using name_len of file name,
5607 now use name_len to calculate length of ea name
5608 we are going to create in the inode xattrs */
5609 if (ea_name == NULL)
5610 name_len = 0;
5611 else
5612 name_len = strnlen(ea_name, 255);
5614 count = sizeof(*parm_data) + ea_value_len + name_len;
5615 pSMB->MaxParameterCount = cpu_to_le16(2);
5616 /* BB find max SMB PDU from sess */
5617 pSMB->MaxDataCount = cpu_to_le16(1000);
5618 pSMB->MaxSetupCount = 0;
5619 pSMB->Reserved = 0;
5620 pSMB->Flags = 0;
5621 pSMB->Timeout = 0;
5622 pSMB->Reserved2 = 0;
5623 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5624 InformationLevel) - 4;
5625 offset = param_offset + params;
5626 pSMB->InformationLevel =
5627 cpu_to_le16(SMB_SET_FILE_EA);
5629 parm_data =
5630 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5631 offset);
5632 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5633 pSMB->DataOffset = cpu_to_le16(offset);
5634 pSMB->SetupCount = 1;
5635 pSMB->Reserved3 = 0;
5636 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5637 byte_count = 3 /* pad */ + params + count;
5638 pSMB->DataCount = cpu_to_le16(count);
5639 parm_data->list_len = cpu_to_le32(count);
5640 parm_data->list[0].EA_flags = 0;
5641 /* we checked above that name len is less than 255 */
5642 parm_data->list[0].name_len = (__u8)name_len;
5643 /* EA names are always ASCII */
5644 if (ea_name)
5645 strncpy(parm_data->list[0].name, ea_name, name_len);
5646 parm_data->list[0].name[name_len] = 0;
5647 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5648 /* caller ensures that ea_value_len is less than 64K but
5649 we need to ensure that it fits within the smb */
5651 /*BB add length check to see if it would fit in
5652 negotiated SMB buffer size BB */
5653 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5654 if (ea_value_len)
5655 memcpy(parm_data->list[0].name+name_len+1,
5656 ea_value, ea_value_len);
5658 pSMB->TotalDataCount = pSMB->DataCount;
5659 pSMB->ParameterCount = cpu_to_le16(params);
5660 pSMB->TotalParameterCount = pSMB->ParameterCount;
5661 pSMB->Reserved4 = 0;
5662 pSMB->hdr.smb_buf_length += byte_count;
5663 pSMB->ByteCount = cpu_to_le16(byte_count);
5664 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5665 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5666 if (rc)
5667 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5669 cifs_buf_release(pSMB);
5671 if (rc == -EAGAIN)
5672 goto SetEARetry;
5674 return rc;
5677 #endif