atomic_t: Remove volatile from atomic_t definition
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / cifs / cifssmb.c
blob5d3f29fef53228eec75dccac45b2d58697d57775
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/slab.h>
34 #include <linux/posix_acl_xattr.h>
35 #include <asm/uaccess.h>
36 #include "cifspdu.h"
37 #include "cifsglob.h"
38 #include "cifsacl.h"
39 #include "cifsproto.h"
40 #include "cifs_unicode.h"
41 #include "cifs_debug.h"
43 #ifdef CONFIG_CIFS_POSIX
44 static struct {
45 int index;
46 char *name;
47 } protocols[] = {
48 #ifdef CONFIG_CIFS_WEAK_PW_HASH
49 {LANMAN_PROT, "\2LM1.2X002"},
50 {LANMAN2_PROT, "\2LANMAN2.1"},
51 #endif /* weak password hashing for legacy clients */
52 {CIFS_PROT, "\2NT LM 0.12"},
53 {POSIX_PROT, "\2POSIX 2"},
54 {BAD_PROT, "\2"}
56 #else
57 static struct {
58 int index;
59 char *name;
60 } protocols[] = {
61 #ifdef CONFIG_CIFS_WEAK_PW_HASH
62 {LANMAN_PROT, "\2LM1.2X002"},
63 {LANMAN2_PROT, "\2LANMAN2.1"},
64 #endif /* weak password hashing for legacy clients */
65 {CIFS_PROT, "\2NT LM 0.12"},
66 {BAD_PROT, "\2"}
68 #endif
70 /* define the number of elements in the cifs dialect array */
71 #ifdef CONFIG_CIFS_POSIX
72 #ifdef CONFIG_CIFS_WEAK_PW_HASH
73 #define CIFS_NUM_PROT 4
74 #else
75 #define CIFS_NUM_PROT 2
76 #endif /* CIFS_WEAK_PW_HASH */
77 #else /* not posix */
78 #ifdef CONFIG_CIFS_WEAK_PW_HASH
79 #define CIFS_NUM_PROT 3
80 #else
81 #define CIFS_NUM_PROT 1
82 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
83 #endif /* CIFS_POSIX */
85 /* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
87 static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
89 struct cifsFileInfo *open_file = NULL;
90 struct list_head *tmp;
91 struct list_head *tmp1;
93 /* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
96 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
97 open_file->invalidHandle = true;
98 open_file->oplock_break_cancelled = true;
100 write_unlock(&GlobalSMBSeslock);
101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
105 /* reconnect the socket, tcon, and smb session if needed */
106 static int
107 cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
109 int rc = 0;
110 struct cifsSesInfo *ses;
111 struct TCP_Server_Info *server;
112 struct nls_table *nls_codepage;
115 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
116 * tcp and smb session status done differently for those three - in the
117 * calling routine
119 if (!tcon)
120 return 0;
122 ses = tcon->ses;
123 server = ses->server;
126 * only tree disconnect, open, and write, (and ulogoff which does not
127 * have tcon) are allowed as we start force umount
129 if (tcon->tidStatus == CifsExiting) {
130 if (smb_command != SMB_COM_WRITE_ANDX &&
131 smb_command != SMB_COM_OPEN_ANDX &&
132 smb_command != SMB_COM_TREE_DISCONNECT) {
133 cFYI(1, ("can not send cmd %d while umounting",
134 smb_command));
135 return -ENODEV;
139 if (ses->status == CifsExiting)
140 return -EIO;
143 * Give demultiplex thread up to 10 seconds to reconnect, should be
144 * greater than cifs socket timeout which is 7 seconds
146 while (server->tcpStatus == CifsNeedReconnect) {
147 wait_event_interruptible_timeout(server->response_q,
148 (server->tcpStatus == CifsGood), 10 * HZ);
150 /* is TCP session is reestablished now ?*/
151 if (server->tcpStatus != CifsNeedReconnect)
152 break;
155 * on "soft" mounts we wait once. Hard mounts keep
156 * retrying until process is killed or server comes
157 * back on-line
159 if (!tcon->retry || ses->status == CifsExiting) {
160 cFYI(1, ("gave up waiting on reconnect in smb_init"));
161 return -EHOSTDOWN;
165 if (!ses->need_reconnect && !tcon->need_reconnect)
166 return 0;
168 nls_codepage = load_nls_default();
171 * need to prevent multiple threads trying to simultaneously
172 * reconnect the same SMB session
174 mutex_lock(&ses->session_mutex);
175 if (ses->need_reconnect)
176 rc = cifs_setup_session(0, ses, nls_codepage);
178 /* do we need to reconnect tcon? */
179 if (rc || !tcon->need_reconnect) {
180 mutex_unlock(&ses->session_mutex);
181 goto out;
184 mark_open_files_invalid(tcon);
185 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
186 mutex_unlock(&ses->session_mutex);
187 cFYI(1, ("reconnect tcon rc = %d", rc));
189 if (rc)
190 goto out;
193 * FIXME: check if wsize needs updated due to negotiated smb buffer
194 * size shrinking
196 atomic_inc(&tconInfoReconnectCount);
198 /* tell server Unix caps we support */
199 if (ses->capabilities & CAP_UNIX)
200 reset_cifs_unix_caps(0, tcon, NULL, NULL);
203 * Removed call to reopen open files here. It is safer (and faster) to
204 * reopen files one at a time as needed in read and write.
206 * FIXME: what about file locks? don't we need to reclaim them ASAP?
209 out:
211 * Check if handle based operation so we know whether we can continue
212 * or not without returning to caller to reset file handle
214 switch (smb_command) {
215 case SMB_COM_READ_ANDX:
216 case SMB_COM_WRITE_ANDX:
217 case SMB_COM_CLOSE:
218 case SMB_COM_FIND_CLOSE2:
219 case SMB_COM_LOCKING_ANDX:
220 rc = -EAGAIN;
223 unload_nls(nls_codepage);
224 return rc;
227 /* Allocate and return pointer to an SMB request buffer, and set basic
228 SMB information in the SMB header. If the return code is zero, this
229 function must have filled in request_buf pointer */
230 static int
231 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
232 void **request_buf)
234 int rc = 0;
236 rc = cifs_reconnect_tcon(tcon, smb_command);
237 if (rc)
238 return rc;
240 *request_buf = cifs_small_buf_get();
241 if (*request_buf == NULL) {
242 /* BB should we add a retry in here if not a writepage? */
243 return -ENOMEM;
246 header_assemble((struct smb_hdr *) *request_buf, smb_command,
247 tcon, wct);
249 if (tcon != NULL)
250 cifs_stats_inc(&tcon->num_smbs_sent);
252 return rc;
256 small_smb_init_no_tc(const int smb_command, const int wct,
257 struct cifsSesInfo *ses, void **request_buf)
259 int rc;
260 struct smb_hdr *buffer;
262 rc = small_smb_init(smb_command, wct, NULL, request_buf);
263 if (rc)
264 return rc;
266 buffer = (struct smb_hdr *)*request_buf;
267 buffer->Mid = GetNextMid(ses->server);
268 if (ses->capabilities & CAP_UNICODE)
269 buffer->Flags2 |= SMBFLG2_UNICODE;
270 if (ses->capabilities & CAP_STATUS32)
271 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
273 /* uid, tid can stay at zero as set in header assemble */
275 /* BB add support for turning on the signing when
276 this function is used after 1st of session setup requests */
278 return rc;
281 /* If the return code is zero, this function must fill in request_buf pointer */
282 static int
283 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
284 void **request_buf /* returned */ ,
285 void **response_buf /* returned */ )
287 int rc = 0;
289 rc = cifs_reconnect_tcon(tcon, smb_command);
290 if (rc)
291 return rc;
293 *request_buf = cifs_buf_get();
294 if (*request_buf == NULL) {
295 /* BB should we add a retry in here if not a writepage? */
296 return -ENOMEM;
298 /* Although the original thought was we needed the response buf for */
299 /* potential retries of smb operations it turns out we can determine */
300 /* from the mid flags when the request buffer can be resent without */
301 /* having to use a second distinct buffer for the response */
302 if (response_buf)
303 *response_buf = *request_buf;
305 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
306 wct);
308 if (tcon != NULL)
309 cifs_stats_inc(&tcon->num_smbs_sent);
311 return rc;
314 static int validate_t2(struct smb_t2_rsp *pSMB)
316 int rc = -EINVAL;
317 int total_size;
318 char *pBCC;
320 /* check for plausible wct, bcc and t2 data and parm sizes */
321 /* check for parm and data offset going beyond end of smb */
322 if (pSMB->hdr.WordCount >= 10) {
323 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
324 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
325 /* check that bcc is at least as big as parms + data */
326 /* check that bcc is less than negotiated smb buffer */
327 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
328 if (total_size < 512) {
329 total_size +=
330 le16_to_cpu(pSMB->t2_rsp.DataCount);
331 /* BCC le converted in SendReceive */
332 pBCC = (pSMB->hdr.WordCount * 2) +
333 sizeof(struct smb_hdr) +
334 (char *)pSMB;
335 if ((total_size <= (*(u16 *)pBCC)) &&
336 (total_size <
337 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
338 return 0;
343 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
344 sizeof(struct smb_t2_rsp) + 16);
345 return rc;
348 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
350 NEGOTIATE_REQ *pSMB;
351 NEGOTIATE_RSP *pSMBr;
352 int rc = 0;
353 int bytes_returned;
354 int i;
355 struct TCP_Server_Info *server;
356 u16 count;
357 unsigned int secFlags;
358 u16 dialect;
360 if (ses->server)
361 server = ses->server;
362 else {
363 rc = -EIO;
364 return rc;
366 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
367 (void **) &pSMB, (void **) &pSMBr);
368 if (rc)
369 return rc;
371 /* if any of auth flags (ie not sign or seal) are overriden use them */
372 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
373 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
374 else /* if override flags set only sign/seal OR them with global auth */
375 secFlags = extended_security | ses->overrideSecFlg;
377 cFYI(1, ("secFlags 0x%x", secFlags));
379 pSMB->hdr.Mid = GetNextMid(server);
380 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
382 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
383 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
384 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
385 cFYI(1, ("Kerberos only mechanism, enable extended security"));
386 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
388 #ifdef CONFIG_CIFS_EXPERIMENTAL
389 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
390 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
391 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
392 cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
393 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
395 #endif
397 count = 0;
398 for (i = 0; i < CIFS_NUM_PROT; i++) {
399 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
400 count += strlen(protocols[i].name) + 1;
401 /* null at end of source and target buffers anyway */
403 pSMB->hdr.smb_buf_length += count;
404 pSMB->ByteCount = cpu_to_le16(count);
406 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
408 if (rc != 0)
409 goto neg_err_exit;
411 dialect = le16_to_cpu(pSMBr->DialectIndex);
412 cFYI(1, ("Dialect: %d", dialect));
413 /* Check wct = 1 error case */
414 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
415 /* core returns wct = 1, but we do not ask for core - otherwise
416 small wct just comes when dialect index is -1 indicating we
417 could not negotiate a common dialect */
418 rc = -EOPNOTSUPP;
419 goto neg_err_exit;
420 #ifdef CONFIG_CIFS_WEAK_PW_HASH
421 } else if ((pSMBr->hdr.WordCount == 13)
422 && ((dialect == LANMAN_PROT)
423 || (dialect == LANMAN2_PROT))) {
424 __s16 tmp;
425 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
427 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
428 (secFlags & CIFSSEC_MAY_PLNTXT))
429 server->secType = LANMAN;
430 else {
431 cERROR(1, ("mount failed weak security disabled"
432 " in /proc/fs/cifs/SecurityFlags"));
433 rc = -EOPNOTSUPP;
434 goto neg_err_exit;
436 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
437 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
438 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
439 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
440 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
441 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
442 /* even though we do not use raw we might as well set this
443 accurately, in case we ever find a need for it */
444 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
445 server->max_rw = 0xFF00;
446 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
447 } else {
448 server->max_rw = 0;/* do not need to use raw anyway */
449 server->capabilities = CAP_MPX_MODE;
451 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
452 if (tmp == -1) {
453 /* OS/2 often does not set timezone therefore
454 * we must use server time to calc time zone.
455 * Could deviate slightly from the right zone.
456 * Smallest defined timezone difference is 15 minutes
457 * (i.e. Nepal). Rounding up/down is done to match
458 * this requirement.
460 int val, seconds, remain, result;
461 struct timespec ts, utc;
462 utc = CURRENT_TIME;
463 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
464 rsp->SrvTime.Time, 0);
465 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
466 (int)ts.tv_sec, (int)utc.tv_sec,
467 (int)(utc.tv_sec - ts.tv_sec)));
468 val = (int)(utc.tv_sec - ts.tv_sec);
469 seconds = abs(val);
470 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
471 remain = seconds % MIN_TZ_ADJ;
472 if (remain >= (MIN_TZ_ADJ / 2))
473 result += MIN_TZ_ADJ;
474 if (val < 0)
475 result = -result;
476 server->timeAdj = result;
477 } else {
478 server->timeAdj = (int)tmp;
479 server->timeAdj *= 60; /* also in seconds */
481 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
484 /* BB get server time for time conversions and add
485 code to use it and timezone since this is not UTC */
487 if (rsp->EncryptionKeyLength ==
488 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
489 memcpy(server->cryptKey, rsp->EncryptionKey,
490 CIFS_CRYPTO_KEY_SIZE);
491 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
492 rc = -EIO; /* need cryptkey unless plain text */
493 goto neg_err_exit;
496 cFYI(1, ("LANMAN negotiated"));
497 /* we will not end up setting signing flags - as no signing
498 was in LANMAN and server did not return the flags on */
499 goto signing_check;
500 #else /* weak security disabled */
501 } else if (pSMBr->hdr.WordCount == 13) {
502 cERROR(1, ("mount failed, cifs module not built "
503 "with CIFS_WEAK_PW_HASH support"));
504 rc = -EOPNOTSUPP;
505 #endif /* WEAK_PW_HASH */
506 goto neg_err_exit;
507 } else if (pSMBr->hdr.WordCount != 17) {
508 /* unknown wct */
509 rc = -EOPNOTSUPP;
510 goto neg_err_exit;
512 /* else wct == 17 NTLM */
513 server->secMode = pSMBr->SecurityMode;
514 if ((server->secMode & SECMODE_USER) == 0)
515 cFYI(1, ("share mode security"));
517 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
518 #ifdef CONFIG_CIFS_WEAK_PW_HASH
519 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
520 #endif /* CIFS_WEAK_PW_HASH */
521 cERROR(1, ("Server requests plain text password"
522 " but client support disabled"));
524 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
525 server->secType = NTLMv2;
526 else if (secFlags & CIFSSEC_MAY_NTLM)
527 server->secType = NTLM;
528 else if (secFlags & CIFSSEC_MAY_NTLMV2)
529 server->secType = NTLMv2;
530 else if (secFlags & CIFSSEC_MAY_KRB5)
531 server->secType = Kerberos;
532 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
533 server->secType = RawNTLMSSP;
534 else if (secFlags & CIFSSEC_MAY_LANMAN)
535 server->secType = LANMAN;
536 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
537 else if (secFlags & CIFSSEC_MAY_PLNTXT)
538 server->secType = ??
539 #endif */
540 else {
541 rc = -EOPNOTSUPP;
542 cERROR(1, ("Invalid security type"));
543 goto neg_err_exit;
545 /* else ... any others ...? */
547 /* one byte, so no need to convert this or EncryptionKeyLen from
548 little endian */
549 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
550 /* probably no need to store and check maxvcs */
551 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
552 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
553 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
554 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
555 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
556 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
557 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
558 server->timeAdj *= 60;
559 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
560 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
561 CIFS_CRYPTO_KEY_SIZE);
562 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
563 && (pSMBr->EncryptionKeyLength == 0)) {
564 /* decode security blob */
565 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
566 rc = -EIO; /* no crypt key only if plain text pwd */
567 goto neg_err_exit;
570 /* BB might be helpful to save off the domain of server here */
572 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
573 (server->capabilities & CAP_EXTENDED_SECURITY)) {
574 count = pSMBr->ByteCount;
575 if (count < 16) {
576 rc = -EIO;
577 goto neg_err_exit;
579 read_lock(&cifs_tcp_ses_lock);
580 if (server->srv_count > 1) {
581 read_unlock(&cifs_tcp_ses_lock);
582 if (memcmp(server->server_GUID,
583 pSMBr->u.extended_response.
584 GUID, 16) != 0) {
585 cFYI(1, ("server UID changed"));
586 memcpy(server->server_GUID,
587 pSMBr->u.extended_response.GUID,
588 16);
590 } else {
591 read_unlock(&cifs_tcp_ses_lock);
592 memcpy(server->server_GUID,
593 pSMBr->u.extended_response.GUID, 16);
596 if (count == 16) {
597 server->secType = RawNTLMSSP;
598 } else {
599 rc = decode_negTokenInit(pSMBr->u.extended_response.
600 SecurityBlob,
601 count - 16,
602 &server->secType);
603 if (rc == 1)
604 rc = 0;
605 else
606 rc = -EINVAL;
608 } else
609 server->capabilities &= ~CAP_EXTENDED_SECURITY;
611 #ifdef CONFIG_CIFS_WEAK_PW_HASH
612 signing_check:
613 #endif
614 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
615 /* MUST_SIGN already includes the MAY_SIGN FLAG
616 so if this is zero it means that signing is disabled */
617 cFYI(1, ("Signing disabled"));
618 if (server->secMode & SECMODE_SIGN_REQUIRED) {
619 cERROR(1, ("Server requires "
620 "packet signing to be enabled in "
621 "/proc/fs/cifs/SecurityFlags."));
622 rc = -EOPNOTSUPP;
624 server->secMode &=
625 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
626 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
627 /* signing required */
628 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
629 if ((server->secMode &
630 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
631 cERROR(1,
632 ("signing required but server lacks support"));
633 rc = -EOPNOTSUPP;
634 } else
635 server->secMode |= SECMODE_SIGN_REQUIRED;
636 } else {
637 /* signing optional ie CIFSSEC_MAY_SIGN */
638 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
639 server->secMode &=
640 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
643 neg_err_exit:
644 cifs_buf_release(pSMB);
646 cFYI(1, ("negprot rc %d", rc));
647 return rc;
651 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
653 struct smb_hdr *smb_buffer;
654 int rc = 0;
656 cFYI(1, ("In tree disconnect"));
658 /* BB: do we need to check this? These should never be NULL. */
659 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
660 return -EIO;
663 * No need to return error on this operation if tid invalidated and
664 * closed on server already e.g. due to tcp session crashing. Also,
665 * the tcon is no longer on the list, so no need to take lock before
666 * checking this.
668 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
669 return 0;
671 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
672 (void **)&smb_buffer);
673 if (rc)
674 return rc;
676 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
677 if (rc)
678 cFYI(1, ("Tree disconnect failed %d", rc));
680 /* No need to return error on this operation if tid invalidated and
681 closed on server already e.g. due to tcp session crashing */
682 if (rc == -EAGAIN)
683 rc = 0;
685 return rc;
689 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
691 LOGOFF_ANDX_REQ *pSMB;
692 int rc = 0;
694 cFYI(1, ("In SMBLogoff for session disconnect"));
697 * BB: do we need to check validity of ses and server? They should
698 * always be valid since we have an active reference. If not, that
699 * should probably be a BUG()
701 if (!ses || !ses->server)
702 return -EIO;
704 mutex_lock(&ses->session_mutex);
705 if (ses->need_reconnect)
706 goto session_already_dead; /* no need to send SMBlogoff if uid
707 already closed due to reconnect */
708 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
709 if (rc) {
710 mutex_unlock(&ses->session_mutex);
711 return rc;
714 pSMB->hdr.Mid = GetNextMid(ses->server);
716 if (ses->server->secMode &
717 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
718 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
720 pSMB->hdr.Uid = ses->Suid;
722 pSMB->AndXCommand = 0xFF;
723 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
724 session_already_dead:
725 mutex_unlock(&ses->session_mutex);
727 /* if session dead then we do not need to do ulogoff,
728 since server closed smb session, no sense reporting
729 error */
730 if (rc == -EAGAIN)
731 rc = 0;
732 return rc;
736 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
737 __u16 type, const struct nls_table *nls_codepage, int remap)
739 TRANSACTION2_SPI_REQ *pSMB = NULL;
740 TRANSACTION2_SPI_RSP *pSMBr = NULL;
741 struct unlink_psx_rq *pRqD;
742 int name_len;
743 int rc = 0;
744 int bytes_returned = 0;
745 __u16 params, param_offset, offset, byte_count;
747 cFYI(1, ("In POSIX delete"));
748 PsxDelete:
749 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
750 (void **) &pSMBr);
751 if (rc)
752 return rc;
754 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
755 name_len =
756 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
757 PATH_MAX, nls_codepage, remap);
758 name_len++; /* trailing null */
759 name_len *= 2;
760 } else { /* BB add path length overrun check */
761 name_len = strnlen(fileName, PATH_MAX);
762 name_len++; /* trailing null */
763 strncpy(pSMB->FileName, fileName, name_len);
766 params = 6 + name_len;
767 pSMB->MaxParameterCount = cpu_to_le16(2);
768 pSMB->MaxDataCount = 0; /* BB double check this with jra */
769 pSMB->MaxSetupCount = 0;
770 pSMB->Reserved = 0;
771 pSMB->Flags = 0;
772 pSMB->Timeout = 0;
773 pSMB->Reserved2 = 0;
774 param_offset = offsetof(struct smb_com_transaction2_spi_req,
775 InformationLevel) - 4;
776 offset = param_offset + params;
778 /* Setup pointer to Request Data (inode type) */
779 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
780 pRqD->type = cpu_to_le16(type);
781 pSMB->ParameterOffset = cpu_to_le16(param_offset);
782 pSMB->DataOffset = cpu_to_le16(offset);
783 pSMB->SetupCount = 1;
784 pSMB->Reserved3 = 0;
785 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
786 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
788 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
789 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
790 pSMB->ParameterCount = cpu_to_le16(params);
791 pSMB->TotalParameterCount = pSMB->ParameterCount;
792 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
793 pSMB->Reserved4 = 0;
794 pSMB->hdr.smb_buf_length += byte_count;
795 pSMB->ByteCount = cpu_to_le16(byte_count);
796 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
797 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
798 if (rc)
799 cFYI(1, ("Posix delete returned %d", rc));
800 cifs_buf_release(pSMB);
802 cifs_stats_inc(&tcon->num_deletes);
804 if (rc == -EAGAIN)
805 goto PsxDelete;
807 return rc;
811 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
812 const struct nls_table *nls_codepage, int remap)
814 DELETE_FILE_REQ *pSMB = NULL;
815 DELETE_FILE_RSP *pSMBr = NULL;
816 int rc = 0;
817 int bytes_returned;
818 int name_len;
820 DelFileRetry:
821 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
822 (void **) &pSMBr);
823 if (rc)
824 return rc;
826 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
827 name_len =
828 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
829 PATH_MAX, nls_codepage, remap);
830 name_len++; /* trailing null */
831 name_len *= 2;
832 } else { /* BB improve check for buffer overruns BB */
833 name_len = strnlen(fileName, PATH_MAX);
834 name_len++; /* trailing null */
835 strncpy(pSMB->fileName, fileName, name_len);
837 pSMB->SearchAttributes =
838 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
839 pSMB->BufferFormat = 0x04;
840 pSMB->hdr.smb_buf_length += name_len + 1;
841 pSMB->ByteCount = cpu_to_le16(name_len + 1);
842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
843 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
844 cifs_stats_inc(&tcon->num_deletes);
845 if (rc)
846 cFYI(1, ("Error in RMFile = %d", rc));
848 cifs_buf_release(pSMB);
849 if (rc == -EAGAIN)
850 goto DelFileRetry;
852 return rc;
856 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
857 const struct nls_table *nls_codepage, int remap)
859 DELETE_DIRECTORY_REQ *pSMB = NULL;
860 DELETE_DIRECTORY_RSP *pSMBr = NULL;
861 int rc = 0;
862 int bytes_returned;
863 int name_len;
865 cFYI(1, ("In CIFSSMBRmDir"));
866 RmDirRetry:
867 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
868 (void **) &pSMBr);
869 if (rc)
870 return rc;
872 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
873 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
874 PATH_MAX, nls_codepage, remap);
875 name_len++; /* trailing null */
876 name_len *= 2;
877 } else { /* BB improve check for buffer overruns BB */
878 name_len = strnlen(dirName, PATH_MAX);
879 name_len++; /* trailing null */
880 strncpy(pSMB->DirName, dirName, name_len);
883 pSMB->BufferFormat = 0x04;
884 pSMB->hdr.smb_buf_length += name_len + 1;
885 pSMB->ByteCount = cpu_to_le16(name_len + 1);
886 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
887 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
888 cifs_stats_inc(&tcon->num_rmdirs);
889 if (rc)
890 cFYI(1, ("Error in RMDir = %d", rc));
892 cifs_buf_release(pSMB);
893 if (rc == -EAGAIN)
894 goto RmDirRetry;
895 return rc;
899 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
900 const char *name, const struct nls_table *nls_codepage, int remap)
902 int rc = 0;
903 CREATE_DIRECTORY_REQ *pSMB = NULL;
904 CREATE_DIRECTORY_RSP *pSMBr = NULL;
905 int bytes_returned;
906 int name_len;
908 cFYI(1, ("In CIFSSMBMkDir"));
909 MkDirRetry:
910 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
911 (void **) &pSMBr);
912 if (rc)
913 return rc;
915 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
916 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
917 PATH_MAX, nls_codepage, remap);
918 name_len++; /* trailing null */
919 name_len *= 2;
920 } else { /* BB improve check for buffer overruns BB */
921 name_len = strnlen(name, PATH_MAX);
922 name_len++; /* trailing null */
923 strncpy(pSMB->DirName, name, name_len);
926 pSMB->BufferFormat = 0x04;
927 pSMB->hdr.smb_buf_length += name_len + 1;
928 pSMB->ByteCount = cpu_to_le16(name_len + 1);
929 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
930 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
931 cifs_stats_inc(&tcon->num_mkdirs);
932 if (rc)
933 cFYI(1, ("Error in Mkdir = %d", rc));
935 cifs_buf_release(pSMB);
936 if (rc == -EAGAIN)
937 goto MkDirRetry;
938 return rc;
942 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
943 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
944 __u32 *pOplock, const char *name,
945 const struct nls_table *nls_codepage, int remap)
947 TRANSACTION2_SPI_REQ *pSMB = NULL;
948 TRANSACTION2_SPI_RSP *pSMBr = NULL;
949 int name_len;
950 int rc = 0;
951 int bytes_returned = 0;
952 __u16 params, param_offset, offset, byte_count, count;
953 OPEN_PSX_REQ *pdata;
954 OPEN_PSX_RSP *psx_rsp;
956 cFYI(1, ("In POSIX Create"));
957 PsxCreat:
958 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
959 (void **) &pSMBr);
960 if (rc)
961 return rc;
963 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
964 name_len =
965 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
966 PATH_MAX, nls_codepage, remap);
967 name_len++; /* trailing null */
968 name_len *= 2;
969 } else { /* BB improve the check for buffer overruns BB */
970 name_len = strnlen(name, PATH_MAX);
971 name_len++; /* trailing null */
972 strncpy(pSMB->FileName, name, name_len);
975 params = 6 + name_len;
976 count = sizeof(OPEN_PSX_REQ);
977 pSMB->MaxParameterCount = cpu_to_le16(2);
978 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
979 pSMB->MaxSetupCount = 0;
980 pSMB->Reserved = 0;
981 pSMB->Flags = 0;
982 pSMB->Timeout = 0;
983 pSMB->Reserved2 = 0;
984 param_offset = offsetof(struct smb_com_transaction2_spi_req,
985 InformationLevel) - 4;
986 offset = param_offset + params;
987 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
988 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
989 pdata->Permissions = cpu_to_le64(mode);
990 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
991 pdata->OpenFlags = cpu_to_le32(*pOplock);
992 pSMB->ParameterOffset = cpu_to_le16(param_offset);
993 pSMB->DataOffset = cpu_to_le16(offset);
994 pSMB->SetupCount = 1;
995 pSMB->Reserved3 = 0;
996 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
997 byte_count = 3 /* pad */ + params + count;
999 pSMB->DataCount = cpu_to_le16(count);
1000 pSMB->ParameterCount = cpu_to_le16(params);
1001 pSMB->TotalDataCount = pSMB->DataCount;
1002 pSMB->TotalParameterCount = pSMB->ParameterCount;
1003 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1004 pSMB->Reserved4 = 0;
1005 pSMB->hdr.smb_buf_length += byte_count;
1006 pSMB->ByteCount = cpu_to_le16(byte_count);
1007 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1008 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1009 if (rc) {
1010 cFYI(1, ("Posix create returned %d", rc));
1011 goto psx_create_err;
1014 cFYI(1, ("copying inode info"));
1015 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1017 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1018 rc = -EIO; /* bad smb */
1019 goto psx_create_err;
1022 /* copy return information to pRetData */
1023 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1024 + le16_to_cpu(pSMBr->t2.DataOffset));
1026 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1027 if (netfid)
1028 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1029 /* Let caller know file was created so we can set the mode. */
1030 /* Do we care about the CreateAction in any other cases? */
1031 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1032 *pOplock |= CIFS_CREATE_ACTION;
1033 /* check to make sure response data is there */
1034 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1035 pRetData->Type = cpu_to_le32(-1); /* unknown */
1036 cFYI(DBG2, ("unknown type"));
1037 } else {
1038 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1039 + sizeof(FILE_UNIX_BASIC_INFO)) {
1040 cERROR(1, ("Open response data too small"));
1041 pRetData->Type = cpu_to_le32(-1);
1042 goto psx_create_err;
1044 memcpy((char *) pRetData,
1045 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1046 sizeof(FILE_UNIX_BASIC_INFO));
1049 psx_create_err:
1050 cifs_buf_release(pSMB);
1052 if (posix_flags & SMB_O_DIRECTORY)
1053 cifs_stats_inc(&tcon->num_posixmkdirs);
1054 else
1055 cifs_stats_inc(&tcon->num_posixopens);
1057 if (rc == -EAGAIN)
1058 goto PsxCreat;
1060 return rc;
1063 static __u16 convert_disposition(int disposition)
1065 __u16 ofun = 0;
1067 switch (disposition) {
1068 case FILE_SUPERSEDE:
1069 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1070 break;
1071 case FILE_OPEN:
1072 ofun = SMBOPEN_OAPPEND;
1073 break;
1074 case FILE_CREATE:
1075 ofun = SMBOPEN_OCREATE;
1076 break;
1077 case FILE_OPEN_IF:
1078 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1079 break;
1080 case FILE_OVERWRITE:
1081 ofun = SMBOPEN_OTRUNC;
1082 break;
1083 case FILE_OVERWRITE_IF:
1084 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1085 break;
1086 default:
1087 cFYI(1, ("unknown disposition %d", disposition));
1088 ofun = SMBOPEN_OAPPEND; /* regular open */
1090 return ofun;
1093 static int
1094 access_flags_to_smbopen_mode(const int access_flags)
1096 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1098 if (masked_flags == GENERIC_READ)
1099 return SMBOPEN_READ;
1100 else if (masked_flags == GENERIC_WRITE)
1101 return SMBOPEN_WRITE;
1103 /* just go for read/write */
1104 return SMBOPEN_READWRITE;
1108 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1109 const char *fileName, const int openDisposition,
1110 const int access_flags, const int create_options, __u16 *netfid,
1111 int *pOplock, FILE_ALL_INFO *pfile_info,
1112 const struct nls_table *nls_codepage, int remap)
1114 int rc = -EACCES;
1115 OPENX_REQ *pSMB = NULL;
1116 OPENX_RSP *pSMBr = NULL;
1117 int bytes_returned;
1118 int name_len;
1119 __u16 count;
1121 OldOpenRetry:
1122 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1123 (void **) &pSMBr);
1124 if (rc)
1125 return rc;
1127 pSMB->AndXCommand = 0xFF; /* none */
1129 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1130 count = 1; /* account for one byte pad to word boundary */
1131 name_len =
1132 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1133 fileName, PATH_MAX, nls_codepage, remap);
1134 name_len++; /* trailing null */
1135 name_len *= 2;
1136 } else { /* BB improve check for buffer overruns BB */
1137 count = 0; /* no pad */
1138 name_len = strnlen(fileName, PATH_MAX);
1139 name_len++; /* trailing null */
1140 strncpy(pSMB->fileName, fileName, name_len);
1142 if (*pOplock & REQ_OPLOCK)
1143 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1144 else if (*pOplock & REQ_BATCHOPLOCK)
1145 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1147 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1148 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1149 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1150 /* set file as system file if special file such
1151 as fifo and server expecting SFU style and
1152 no Unix extensions */
1154 if (create_options & CREATE_OPTION_SPECIAL)
1155 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1156 else /* BB FIXME BB */
1157 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1159 if (create_options & CREATE_OPTION_READONLY)
1160 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1162 /* BB FIXME BB */
1163 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1164 CREATE_OPTIONS_MASK); */
1165 /* BB FIXME END BB */
1167 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1168 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1169 count += name_len;
1170 pSMB->hdr.smb_buf_length += count;
1172 pSMB->ByteCount = cpu_to_le16(count);
1173 /* long_op set to 1 to allow for oplock break timeouts */
1174 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1175 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1176 cifs_stats_inc(&tcon->num_opens);
1177 if (rc) {
1178 cFYI(1, ("Error in Open = %d", rc));
1179 } else {
1180 /* BB verify if wct == 15 */
1182 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1184 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1185 /* Let caller know file was created so we can set the mode. */
1186 /* Do we care about the CreateAction in any other cases? */
1187 /* BB FIXME BB */
1188 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1189 *pOplock |= CIFS_CREATE_ACTION; */
1190 /* BB FIXME END */
1192 if (pfile_info) {
1193 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1194 pfile_info->LastAccessTime = 0; /* BB fixme */
1195 pfile_info->LastWriteTime = 0; /* BB fixme */
1196 pfile_info->ChangeTime = 0; /* BB fixme */
1197 pfile_info->Attributes =
1198 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1199 /* the file_info buf is endian converted by caller */
1200 pfile_info->AllocationSize =
1201 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1202 pfile_info->EndOfFile = pfile_info->AllocationSize;
1203 pfile_info->NumberOfLinks = cpu_to_le32(1);
1204 pfile_info->DeletePending = 0;
1208 cifs_buf_release(pSMB);
1209 if (rc == -EAGAIN)
1210 goto OldOpenRetry;
1211 return rc;
1215 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1216 const char *fileName, const int openDisposition,
1217 const int access_flags, const int create_options, __u16 *netfid,
1218 int *pOplock, FILE_ALL_INFO *pfile_info,
1219 const struct nls_table *nls_codepage, int remap)
1221 int rc = -EACCES;
1222 OPEN_REQ *pSMB = NULL;
1223 OPEN_RSP *pSMBr = NULL;
1224 int bytes_returned;
1225 int name_len;
1226 __u16 count;
1228 openRetry:
1229 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1230 (void **) &pSMBr);
1231 if (rc)
1232 return rc;
1234 pSMB->AndXCommand = 0xFF; /* none */
1236 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1237 count = 1; /* account for one byte pad to word boundary */
1238 name_len =
1239 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1240 fileName, PATH_MAX, nls_codepage, remap);
1241 name_len++; /* trailing null */
1242 name_len *= 2;
1243 pSMB->NameLength = cpu_to_le16(name_len);
1244 } else { /* BB improve check for buffer overruns BB */
1245 count = 0; /* no pad */
1246 name_len = strnlen(fileName, PATH_MAX);
1247 name_len++; /* trailing null */
1248 pSMB->NameLength = cpu_to_le16(name_len);
1249 strncpy(pSMB->fileName, fileName, name_len);
1251 if (*pOplock & REQ_OPLOCK)
1252 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1253 else if (*pOplock & REQ_BATCHOPLOCK)
1254 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1255 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1256 pSMB->AllocationSize = 0;
1257 /* set file as system file if special file such
1258 as fifo and server expecting SFU style and
1259 no Unix extensions */
1260 if (create_options & CREATE_OPTION_SPECIAL)
1261 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1262 else
1263 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1265 /* XP does not handle ATTR_POSIX_SEMANTICS */
1266 /* but it helps speed up case sensitive checks for other
1267 servers such as Samba */
1268 if (tcon->ses->capabilities & CAP_UNIX)
1269 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1271 if (create_options & CREATE_OPTION_READONLY)
1272 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1274 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1275 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1276 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1277 /* BB Expirement with various impersonation levels and verify */
1278 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1279 pSMB->SecurityFlags =
1280 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1282 count += name_len;
1283 pSMB->hdr.smb_buf_length += count;
1285 pSMB->ByteCount = cpu_to_le16(count);
1286 /* long_op set to 1 to allow for oplock break timeouts */
1287 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1288 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1289 cifs_stats_inc(&tcon->num_opens);
1290 if (rc) {
1291 cFYI(1, ("Error in Open = %d", rc));
1292 } else {
1293 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1294 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1295 /* Let caller know file was created so we can set the mode. */
1296 /* Do we care about the CreateAction in any other cases? */
1297 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1298 *pOplock |= CIFS_CREATE_ACTION;
1299 if (pfile_info) {
1300 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1301 36 /* CreationTime to Attributes */);
1302 /* the file_info buf is endian converted by caller */
1303 pfile_info->AllocationSize = pSMBr->AllocationSize;
1304 pfile_info->EndOfFile = pSMBr->EndOfFile;
1305 pfile_info->NumberOfLinks = cpu_to_le32(1);
1306 pfile_info->DeletePending = 0;
1310 cifs_buf_release(pSMB);
1311 if (rc == -EAGAIN)
1312 goto openRetry;
1313 return rc;
1317 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1318 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1319 char **buf, int *pbuf_type)
1321 int rc = -EACCES;
1322 READ_REQ *pSMB = NULL;
1323 READ_RSP *pSMBr = NULL;
1324 char *pReadData = NULL;
1325 int wct;
1326 int resp_buf_type = 0;
1327 struct kvec iov[1];
1329 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1330 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1331 wct = 12;
1332 else {
1333 wct = 10; /* old style read */
1334 if ((lseek >> 32) > 0) {
1335 /* can not handle this big offset for old */
1336 return -EIO;
1340 *nbytes = 0;
1341 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1342 if (rc)
1343 return rc;
1345 /* tcon and ses pointer are checked in smb_init */
1346 if (tcon->ses->server == NULL)
1347 return -ECONNABORTED;
1349 pSMB->AndXCommand = 0xFF; /* none */
1350 pSMB->Fid = netfid;
1351 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1352 if (wct == 12)
1353 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1355 pSMB->Remaining = 0;
1356 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1357 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1358 if (wct == 12)
1359 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1360 else {
1361 /* old style read */
1362 struct smb_com_readx_req *pSMBW =
1363 (struct smb_com_readx_req *)pSMB;
1364 pSMBW->ByteCount = 0;
1367 iov[0].iov_base = (char *)pSMB;
1368 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1369 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1370 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1371 cifs_stats_inc(&tcon->num_reads);
1372 pSMBr = (READ_RSP *)iov[0].iov_base;
1373 if (rc) {
1374 cERROR(1, ("Send error in read = %d", rc));
1375 } else {
1376 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1377 data_length = data_length << 16;
1378 data_length += le16_to_cpu(pSMBr->DataLength);
1379 *nbytes = data_length;
1381 /*check that DataLength would not go beyond end of SMB */
1382 if ((data_length > CIFSMaxBufSize)
1383 || (data_length > count)) {
1384 cFYI(1, ("bad length %d for count %d",
1385 data_length, count));
1386 rc = -EIO;
1387 *nbytes = 0;
1388 } else {
1389 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1390 le16_to_cpu(pSMBr->DataOffset);
1391 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1392 cERROR(1,("Faulting on read rc = %d",rc));
1393 rc = -EFAULT;
1394 }*/ /* can not use copy_to_user when using page cache*/
1395 if (*buf)
1396 memcpy(*buf, pReadData, data_length);
1400 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1401 if (*buf) {
1402 if (resp_buf_type == CIFS_SMALL_BUFFER)
1403 cifs_small_buf_release(iov[0].iov_base);
1404 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1405 cifs_buf_release(iov[0].iov_base);
1406 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1407 /* return buffer to caller to free */
1408 *buf = iov[0].iov_base;
1409 if (resp_buf_type == CIFS_SMALL_BUFFER)
1410 *pbuf_type = CIFS_SMALL_BUFFER;
1411 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1412 *pbuf_type = CIFS_LARGE_BUFFER;
1413 } /* else no valid buffer on return - leave as null */
1415 /* Note: On -EAGAIN error only caller can retry on handle based calls
1416 since file handle passed in no longer valid */
1417 return rc;
1422 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1423 const int netfid, const unsigned int count,
1424 const __u64 offset, unsigned int *nbytes, const char *buf,
1425 const char __user *ubuf, const int long_op)
1427 int rc = -EACCES;
1428 WRITE_REQ *pSMB = NULL;
1429 WRITE_RSP *pSMBr = NULL;
1430 int bytes_returned, wct;
1431 __u32 bytes_sent;
1432 __u16 byte_count;
1434 *nbytes = 0;
1436 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
1437 if (tcon->ses == NULL)
1438 return -ECONNABORTED;
1440 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1441 wct = 14;
1442 else {
1443 wct = 12;
1444 if ((offset >> 32) > 0) {
1445 /* can not handle big offset for old srv */
1446 return -EIO;
1450 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1451 (void **) &pSMBr);
1452 if (rc)
1453 return rc;
1454 /* tcon and ses pointer are checked in smb_init */
1455 if (tcon->ses->server == NULL)
1456 return -ECONNABORTED;
1458 pSMB->AndXCommand = 0xFF; /* none */
1459 pSMB->Fid = netfid;
1460 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1461 if (wct == 14)
1462 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1464 pSMB->Reserved = 0xFFFFFFFF;
1465 pSMB->WriteMode = 0;
1466 pSMB->Remaining = 0;
1468 /* Can increase buffer size if buffer is big enough in some cases ie we
1469 can send more if LARGE_WRITE_X capability returned by the server and if
1470 our buffer is big enough or if we convert to iovecs on socket writes
1471 and eliminate the copy to the CIFS buffer */
1472 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1473 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1474 } else {
1475 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1476 & ~0xFF;
1479 if (bytes_sent > count)
1480 bytes_sent = count;
1481 pSMB->DataOffset =
1482 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1483 if (buf)
1484 memcpy(pSMB->Data, buf, bytes_sent);
1485 else if (ubuf) {
1486 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1487 cifs_buf_release(pSMB);
1488 return -EFAULT;
1490 } else if (count != 0) {
1491 /* No buffer */
1492 cifs_buf_release(pSMB);
1493 return -EINVAL;
1494 } /* else setting file size with write of zero bytes */
1495 if (wct == 14)
1496 byte_count = bytes_sent + 1; /* pad */
1497 else /* wct == 12 */
1498 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1500 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1501 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1502 pSMB->hdr.smb_buf_length += byte_count;
1504 if (wct == 14)
1505 pSMB->ByteCount = cpu_to_le16(byte_count);
1506 else { /* old style write has byte count 4 bytes earlier
1507 so 4 bytes pad */
1508 struct smb_com_writex_req *pSMBW =
1509 (struct smb_com_writex_req *)pSMB;
1510 pSMBW->ByteCount = cpu_to_le16(byte_count);
1513 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1514 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1515 cifs_stats_inc(&tcon->num_writes);
1516 if (rc) {
1517 cFYI(1, ("Send error in write = %d", rc));
1518 } else {
1519 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1520 *nbytes = (*nbytes) << 16;
1521 *nbytes += le16_to_cpu(pSMBr->Count);
1524 * Mask off high 16 bits when bytes written as returned by the
1525 * server is greater than bytes requested by the client. Some
1526 * OS/2 servers are known to set incorrect CountHigh values.
1528 if (*nbytes > count)
1529 *nbytes &= 0xFFFF;
1532 cifs_buf_release(pSMB);
1534 /* Note: On -EAGAIN error only caller can retry on handle based calls
1535 since file handle passed in no longer valid */
1537 return rc;
1541 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1542 const int netfid, const unsigned int count,
1543 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1544 int n_vec, const int long_op)
1546 int rc = -EACCES;
1547 WRITE_REQ *pSMB = NULL;
1548 int wct;
1549 int smb_hdr_len;
1550 int resp_buf_type = 0;
1552 *nbytes = 0;
1554 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1556 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1557 wct = 14;
1558 } else {
1559 wct = 12;
1560 if ((offset >> 32) > 0) {
1561 /* can not handle big offset for old srv */
1562 return -EIO;
1565 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1566 if (rc)
1567 return rc;
1568 /* tcon and ses pointer are checked in smb_init */
1569 if (tcon->ses->server == NULL)
1570 return -ECONNABORTED;
1572 pSMB->AndXCommand = 0xFF; /* none */
1573 pSMB->Fid = netfid;
1574 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1575 if (wct == 14)
1576 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1577 pSMB->Reserved = 0xFFFFFFFF;
1578 pSMB->WriteMode = 0;
1579 pSMB->Remaining = 0;
1581 pSMB->DataOffset =
1582 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1584 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1585 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1586 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1587 if (wct == 14)
1588 pSMB->hdr.smb_buf_length += count+1;
1589 else /* wct == 12 */
1590 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1591 if (wct == 14)
1592 pSMB->ByteCount = cpu_to_le16(count + 1);
1593 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1594 struct smb_com_writex_req *pSMBW =
1595 (struct smb_com_writex_req *)pSMB;
1596 pSMBW->ByteCount = cpu_to_le16(count + 5);
1598 iov[0].iov_base = pSMB;
1599 if (wct == 14)
1600 iov[0].iov_len = smb_hdr_len + 4;
1601 else /* wct == 12 pad bigger by four bytes */
1602 iov[0].iov_len = smb_hdr_len + 8;
1605 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1606 long_op);
1607 cifs_stats_inc(&tcon->num_writes);
1608 if (rc) {
1609 cFYI(1, ("Send error Write2 = %d", rc));
1610 } else if (resp_buf_type == 0) {
1611 /* presumably this can not happen, but best to be safe */
1612 rc = -EIO;
1613 } else {
1614 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1615 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1616 *nbytes = (*nbytes) << 16;
1617 *nbytes += le16_to_cpu(pSMBr->Count);
1620 * Mask off high 16 bits when bytes written as returned by the
1621 * server is greater than bytes requested by the client. OS/2
1622 * servers are known to set incorrect CountHigh values.
1624 if (*nbytes > count)
1625 *nbytes &= 0xFFFF;
1628 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1629 if (resp_buf_type == CIFS_SMALL_BUFFER)
1630 cifs_small_buf_release(iov[0].iov_base);
1631 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1632 cifs_buf_release(iov[0].iov_base);
1634 /* Note: On -EAGAIN error only caller can retry on handle based calls
1635 since file handle passed in no longer valid */
1637 return rc;
1642 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1643 const __u16 smb_file_id, const __u64 len,
1644 const __u64 offset, const __u32 numUnlock,
1645 const __u32 numLock, const __u8 lockType, const bool waitFlag)
1647 int rc = 0;
1648 LOCK_REQ *pSMB = NULL;
1649 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1650 int bytes_returned;
1651 int timeout = 0;
1652 __u16 count;
1654 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1655 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1657 if (rc)
1658 return rc;
1660 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1661 timeout = CIFS_ASYNC_OP; /* no response expected */
1662 pSMB->Timeout = 0;
1663 } else if (waitFlag) {
1664 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1665 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1666 } else {
1667 pSMB->Timeout = 0;
1670 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1671 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1672 pSMB->LockType = lockType;
1673 pSMB->AndXCommand = 0xFF; /* none */
1674 pSMB->Fid = smb_file_id; /* netfid stays le */
1676 if ((numLock != 0) || (numUnlock != 0)) {
1677 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1678 /* BB where to store pid high? */
1679 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1680 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1681 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1682 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1683 count = sizeof(LOCKING_ANDX_RANGE);
1684 } else {
1685 /* oplock break */
1686 count = 0;
1688 pSMB->hdr.smb_buf_length += count;
1689 pSMB->ByteCount = cpu_to_le16(count);
1691 if (waitFlag) {
1692 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1693 (struct smb_hdr *) pSMB, &bytes_returned);
1694 cifs_small_buf_release(pSMB);
1695 } else {
1696 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1697 timeout);
1698 /* SMB buffer freed by function above */
1700 cifs_stats_inc(&tcon->num_locks);
1701 if (rc)
1702 cFYI(1, ("Send error in Lock = %d", rc));
1704 /* Note: On -EAGAIN error only caller can retry on handle based calls
1705 since file handle passed in no longer valid */
1706 return rc;
1710 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1711 const __u16 smb_file_id, const int get_flag, const __u64 len,
1712 struct file_lock *pLockData, const __u16 lock_type,
1713 const bool waitFlag)
1715 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1716 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1717 struct cifs_posix_lock *parm_data;
1718 int rc = 0;
1719 int timeout = 0;
1720 int bytes_returned = 0;
1721 int resp_buf_type = 0;
1722 __u16 params, param_offset, offset, byte_count, count;
1723 struct kvec iov[1];
1725 cFYI(1, ("Posix Lock"));
1727 if (pLockData == NULL)
1728 return -EINVAL;
1730 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1732 if (rc)
1733 return rc;
1735 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1737 params = 6;
1738 pSMB->MaxSetupCount = 0;
1739 pSMB->Reserved = 0;
1740 pSMB->Flags = 0;
1741 pSMB->Reserved2 = 0;
1742 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1743 offset = param_offset + params;
1745 count = sizeof(struct cifs_posix_lock);
1746 pSMB->MaxParameterCount = cpu_to_le16(2);
1747 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1748 pSMB->SetupCount = 1;
1749 pSMB->Reserved3 = 0;
1750 if (get_flag)
1751 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1752 else
1753 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1754 byte_count = 3 /* pad */ + params + count;
1755 pSMB->DataCount = cpu_to_le16(count);
1756 pSMB->ParameterCount = cpu_to_le16(params);
1757 pSMB->TotalDataCount = pSMB->DataCount;
1758 pSMB->TotalParameterCount = pSMB->ParameterCount;
1759 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1760 parm_data = (struct cifs_posix_lock *)
1761 (((char *) &pSMB->hdr.Protocol) + offset);
1763 parm_data->lock_type = cpu_to_le16(lock_type);
1764 if (waitFlag) {
1765 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1766 parm_data->lock_flags = cpu_to_le16(1);
1767 pSMB->Timeout = cpu_to_le32(-1);
1768 } else
1769 pSMB->Timeout = 0;
1771 parm_data->pid = cpu_to_le32(current->tgid);
1772 parm_data->start = cpu_to_le64(pLockData->fl_start);
1773 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1775 pSMB->DataOffset = cpu_to_le16(offset);
1776 pSMB->Fid = smb_file_id;
1777 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1778 pSMB->Reserved4 = 0;
1779 pSMB->hdr.smb_buf_length += byte_count;
1780 pSMB->ByteCount = cpu_to_le16(byte_count);
1781 if (waitFlag) {
1782 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1783 (struct smb_hdr *) pSMBr, &bytes_returned);
1784 } else {
1785 iov[0].iov_base = (char *)pSMB;
1786 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1787 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1788 &resp_buf_type, timeout);
1789 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1790 not try to free it twice below on exit */
1791 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1794 if (rc) {
1795 cFYI(1, ("Send error in Posix Lock = %d", rc));
1796 } else if (get_flag) {
1797 /* lock structure can be returned on get */
1798 __u16 data_offset;
1799 __u16 data_count;
1800 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1802 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1803 rc = -EIO; /* bad smb */
1804 goto plk_err_exit;
1806 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1807 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1808 if (data_count < sizeof(struct cifs_posix_lock)) {
1809 rc = -EIO;
1810 goto plk_err_exit;
1812 parm_data = (struct cifs_posix_lock *)
1813 ((char *)&pSMBr->hdr.Protocol + data_offset);
1814 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
1815 pLockData->fl_type = F_UNLCK;
1816 else {
1817 if (parm_data->lock_type ==
1818 __constant_cpu_to_le16(CIFS_RDLCK))
1819 pLockData->fl_type = F_RDLCK;
1820 else if (parm_data->lock_type ==
1821 __constant_cpu_to_le16(CIFS_WRLCK))
1822 pLockData->fl_type = F_WRLCK;
1824 pLockData->fl_start = parm_data->start;
1825 pLockData->fl_end = parm_data->start +
1826 parm_data->length - 1;
1827 pLockData->fl_pid = parm_data->pid;
1831 plk_err_exit:
1832 if (pSMB)
1833 cifs_small_buf_release(pSMB);
1835 if (resp_buf_type == CIFS_SMALL_BUFFER)
1836 cifs_small_buf_release(iov[0].iov_base);
1837 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1838 cifs_buf_release(iov[0].iov_base);
1840 /* Note: On -EAGAIN error only caller can retry on handle based calls
1841 since file handle passed in no longer valid */
1843 return rc;
1848 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1850 int rc = 0;
1851 CLOSE_REQ *pSMB = NULL;
1852 cFYI(1, ("In CIFSSMBClose"));
1854 /* do not retry on dead session on close */
1855 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1856 if (rc == -EAGAIN)
1857 return 0;
1858 if (rc)
1859 return rc;
1861 pSMB->FileID = (__u16) smb_file_id;
1862 pSMB->LastWriteTime = 0xFFFFFFFF;
1863 pSMB->ByteCount = 0;
1864 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1865 cifs_stats_inc(&tcon->num_closes);
1866 if (rc) {
1867 if (rc != -EINTR) {
1868 /* EINTR is expected when user ctl-c to kill app */
1869 cERROR(1, ("Send error in Close = %d", rc));
1873 /* Since session is dead, file will be closed on server already */
1874 if (rc == -EAGAIN)
1875 rc = 0;
1877 return rc;
1881 CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1883 int rc = 0;
1884 FLUSH_REQ *pSMB = NULL;
1885 cFYI(1, ("In CIFSSMBFlush"));
1887 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1888 if (rc)
1889 return rc;
1891 pSMB->FileID = (__u16) smb_file_id;
1892 pSMB->ByteCount = 0;
1893 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1894 cifs_stats_inc(&tcon->num_flushes);
1895 if (rc)
1896 cERROR(1, ("Send error in Flush = %d", rc));
1898 return rc;
1902 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1903 const char *fromName, const char *toName,
1904 const struct nls_table *nls_codepage, int remap)
1906 int rc = 0;
1907 RENAME_REQ *pSMB = NULL;
1908 RENAME_RSP *pSMBr = NULL;
1909 int bytes_returned;
1910 int name_len, name_len2;
1911 __u16 count;
1913 cFYI(1, ("In CIFSSMBRename"));
1914 renameRetry:
1915 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1916 (void **) &pSMBr);
1917 if (rc)
1918 return rc;
1920 pSMB->BufferFormat = 0x04;
1921 pSMB->SearchAttributes =
1922 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1923 ATTR_DIRECTORY);
1925 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1926 name_len =
1927 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1928 PATH_MAX, nls_codepage, remap);
1929 name_len++; /* trailing null */
1930 name_len *= 2;
1931 pSMB->OldFileName[name_len] = 0x04; /* pad */
1932 /* protocol requires ASCII signature byte on Unicode string */
1933 pSMB->OldFileName[name_len + 1] = 0x00;
1934 name_len2 =
1935 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1936 toName, PATH_MAX, nls_codepage, remap);
1937 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1938 name_len2 *= 2; /* convert to bytes */
1939 } else { /* BB improve the check for buffer overruns BB */
1940 name_len = strnlen(fromName, PATH_MAX);
1941 name_len++; /* trailing null */
1942 strncpy(pSMB->OldFileName, fromName, name_len);
1943 name_len2 = strnlen(toName, PATH_MAX);
1944 name_len2++; /* trailing null */
1945 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1946 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1947 name_len2++; /* trailing null */
1948 name_len2++; /* signature byte */
1951 count = 1 /* 1st signature byte */ + name_len + name_len2;
1952 pSMB->hdr.smb_buf_length += count;
1953 pSMB->ByteCount = cpu_to_le16(count);
1955 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1956 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1957 cifs_stats_inc(&tcon->num_renames);
1958 if (rc)
1959 cFYI(1, ("Send error in rename = %d", rc));
1961 cifs_buf_release(pSMB);
1963 if (rc == -EAGAIN)
1964 goto renameRetry;
1966 return rc;
1969 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1970 int netfid, const char *target_name,
1971 const struct nls_table *nls_codepage, int remap)
1973 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1974 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1975 struct set_file_rename *rename_info;
1976 char *data_offset;
1977 char dummy_string[30];
1978 int rc = 0;
1979 int bytes_returned = 0;
1980 int len_of_str;
1981 __u16 params, param_offset, offset, count, byte_count;
1983 cFYI(1, ("Rename to File by handle"));
1984 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1985 (void **) &pSMBr);
1986 if (rc)
1987 return rc;
1989 params = 6;
1990 pSMB->MaxSetupCount = 0;
1991 pSMB->Reserved = 0;
1992 pSMB->Flags = 0;
1993 pSMB->Timeout = 0;
1994 pSMB->Reserved2 = 0;
1995 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1996 offset = param_offset + params;
1998 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1999 rename_info = (struct set_file_rename *) data_offset;
2000 pSMB->MaxParameterCount = cpu_to_le16(2);
2001 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2002 pSMB->SetupCount = 1;
2003 pSMB->Reserved3 = 0;
2004 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2005 byte_count = 3 /* pad */ + params;
2006 pSMB->ParameterCount = cpu_to_le16(params);
2007 pSMB->TotalParameterCount = pSMB->ParameterCount;
2008 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2009 pSMB->DataOffset = cpu_to_le16(offset);
2010 /* construct random name ".cifs_tmp<inodenum><mid>" */
2011 rename_info->overwrite = cpu_to_le32(1);
2012 rename_info->root_fid = 0;
2013 /* unicode only call */
2014 if (target_name == NULL) {
2015 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2016 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2017 dummy_string, 24, nls_codepage, remap);
2018 } else {
2019 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2020 target_name, PATH_MAX, nls_codepage,
2021 remap);
2023 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2024 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2025 byte_count += count;
2026 pSMB->DataCount = cpu_to_le16(count);
2027 pSMB->TotalDataCount = pSMB->DataCount;
2028 pSMB->Fid = netfid;
2029 pSMB->InformationLevel =
2030 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2031 pSMB->Reserved4 = 0;
2032 pSMB->hdr.smb_buf_length += byte_count;
2033 pSMB->ByteCount = cpu_to_le16(byte_count);
2034 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2035 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2036 cifs_stats_inc(&pTcon->num_t2renames);
2037 if (rc)
2038 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2040 cifs_buf_release(pSMB);
2042 /* Note: On -EAGAIN error only caller can retry on handle based calls
2043 since file handle passed in no longer valid */
2045 return rc;
2049 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2050 const __u16 target_tid, const char *toName, const int flags,
2051 const struct nls_table *nls_codepage, int remap)
2053 int rc = 0;
2054 COPY_REQ *pSMB = NULL;
2055 COPY_RSP *pSMBr = NULL;
2056 int bytes_returned;
2057 int name_len, name_len2;
2058 __u16 count;
2060 cFYI(1, ("In CIFSSMBCopy"));
2061 copyRetry:
2062 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2063 (void **) &pSMBr);
2064 if (rc)
2065 return rc;
2067 pSMB->BufferFormat = 0x04;
2068 pSMB->Tid2 = target_tid;
2070 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2072 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2073 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2074 fromName, PATH_MAX, nls_codepage,
2075 remap);
2076 name_len++; /* trailing null */
2077 name_len *= 2;
2078 pSMB->OldFileName[name_len] = 0x04; /* pad */
2079 /* protocol requires ASCII signature byte on Unicode string */
2080 pSMB->OldFileName[name_len + 1] = 0x00;
2081 name_len2 =
2082 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2083 toName, PATH_MAX, nls_codepage, remap);
2084 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2085 name_len2 *= 2; /* convert to bytes */
2086 } else { /* BB improve the check for buffer overruns BB */
2087 name_len = strnlen(fromName, PATH_MAX);
2088 name_len++; /* trailing null */
2089 strncpy(pSMB->OldFileName, fromName, name_len);
2090 name_len2 = strnlen(toName, PATH_MAX);
2091 name_len2++; /* trailing null */
2092 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2093 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2094 name_len2++; /* trailing null */
2095 name_len2++; /* signature byte */
2098 count = 1 /* 1st signature byte */ + name_len + name_len2;
2099 pSMB->hdr.smb_buf_length += count;
2100 pSMB->ByteCount = cpu_to_le16(count);
2102 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2103 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2104 if (rc) {
2105 cFYI(1, ("Send error in copy = %d with %d files copied",
2106 rc, le16_to_cpu(pSMBr->CopyCount)));
2108 cifs_buf_release(pSMB);
2110 if (rc == -EAGAIN)
2111 goto copyRetry;
2113 return rc;
2117 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2118 const char *fromName, const char *toName,
2119 const struct nls_table *nls_codepage)
2121 TRANSACTION2_SPI_REQ *pSMB = NULL;
2122 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2123 char *data_offset;
2124 int name_len;
2125 int name_len_target;
2126 int rc = 0;
2127 int bytes_returned = 0;
2128 __u16 params, param_offset, offset, byte_count;
2130 cFYI(1, ("In Symlink Unix style"));
2131 createSymLinkRetry:
2132 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2133 (void **) &pSMBr);
2134 if (rc)
2135 return rc;
2137 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2138 name_len =
2139 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2140 /* find define for this maxpathcomponent */
2141 , nls_codepage);
2142 name_len++; /* trailing null */
2143 name_len *= 2;
2145 } else { /* BB improve the check for buffer overruns BB */
2146 name_len = strnlen(fromName, PATH_MAX);
2147 name_len++; /* trailing null */
2148 strncpy(pSMB->FileName, fromName, name_len);
2150 params = 6 + name_len;
2151 pSMB->MaxSetupCount = 0;
2152 pSMB->Reserved = 0;
2153 pSMB->Flags = 0;
2154 pSMB->Timeout = 0;
2155 pSMB->Reserved2 = 0;
2156 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2157 InformationLevel) - 4;
2158 offset = param_offset + params;
2160 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2161 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2162 name_len_target =
2163 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2164 /* find define for this maxpathcomponent */
2165 , nls_codepage);
2166 name_len_target++; /* trailing null */
2167 name_len_target *= 2;
2168 } else { /* BB improve the check for buffer overruns BB */
2169 name_len_target = strnlen(toName, PATH_MAX);
2170 name_len_target++; /* trailing null */
2171 strncpy(data_offset, toName, name_len_target);
2174 pSMB->MaxParameterCount = cpu_to_le16(2);
2175 /* BB find exact max on data count below from sess */
2176 pSMB->MaxDataCount = cpu_to_le16(1000);
2177 pSMB->SetupCount = 1;
2178 pSMB->Reserved3 = 0;
2179 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2180 byte_count = 3 /* pad */ + params + name_len_target;
2181 pSMB->DataCount = cpu_to_le16(name_len_target);
2182 pSMB->ParameterCount = cpu_to_le16(params);
2183 pSMB->TotalDataCount = pSMB->DataCount;
2184 pSMB->TotalParameterCount = pSMB->ParameterCount;
2185 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2186 pSMB->DataOffset = cpu_to_le16(offset);
2187 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2188 pSMB->Reserved4 = 0;
2189 pSMB->hdr.smb_buf_length += byte_count;
2190 pSMB->ByteCount = cpu_to_le16(byte_count);
2191 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2192 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2193 cifs_stats_inc(&tcon->num_symlinks);
2194 if (rc)
2195 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2197 cifs_buf_release(pSMB);
2199 if (rc == -EAGAIN)
2200 goto createSymLinkRetry;
2202 return rc;
2206 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2207 const char *fromName, const char *toName,
2208 const struct nls_table *nls_codepage, int remap)
2210 TRANSACTION2_SPI_REQ *pSMB = NULL;
2211 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2212 char *data_offset;
2213 int name_len;
2214 int name_len_target;
2215 int rc = 0;
2216 int bytes_returned = 0;
2217 __u16 params, param_offset, offset, byte_count;
2219 cFYI(1, ("In Create Hard link Unix style"));
2220 createHardLinkRetry:
2221 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2222 (void **) &pSMBr);
2223 if (rc)
2224 return rc;
2226 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2227 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2228 PATH_MAX, nls_codepage, remap);
2229 name_len++; /* trailing null */
2230 name_len *= 2;
2232 } else { /* BB improve the check for buffer overruns BB */
2233 name_len = strnlen(toName, PATH_MAX);
2234 name_len++; /* trailing null */
2235 strncpy(pSMB->FileName, toName, name_len);
2237 params = 6 + name_len;
2238 pSMB->MaxSetupCount = 0;
2239 pSMB->Reserved = 0;
2240 pSMB->Flags = 0;
2241 pSMB->Timeout = 0;
2242 pSMB->Reserved2 = 0;
2243 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2244 InformationLevel) - 4;
2245 offset = param_offset + params;
2247 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2248 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2249 name_len_target =
2250 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2251 nls_codepage, remap);
2252 name_len_target++; /* trailing null */
2253 name_len_target *= 2;
2254 } else { /* BB improve the check for buffer overruns BB */
2255 name_len_target = strnlen(fromName, PATH_MAX);
2256 name_len_target++; /* trailing null */
2257 strncpy(data_offset, fromName, name_len_target);
2260 pSMB->MaxParameterCount = cpu_to_le16(2);
2261 /* BB find exact max on data count below from sess*/
2262 pSMB->MaxDataCount = cpu_to_le16(1000);
2263 pSMB->SetupCount = 1;
2264 pSMB->Reserved3 = 0;
2265 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2266 byte_count = 3 /* pad */ + params + name_len_target;
2267 pSMB->ParameterCount = cpu_to_le16(params);
2268 pSMB->TotalParameterCount = pSMB->ParameterCount;
2269 pSMB->DataCount = cpu_to_le16(name_len_target);
2270 pSMB->TotalDataCount = pSMB->DataCount;
2271 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2272 pSMB->DataOffset = cpu_to_le16(offset);
2273 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2274 pSMB->Reserved4 = 0;
2275 pSMB->hdr.smb_buf_length += byte_count;
2276 pSMB->ByteCount = cpu_to_le16(byte_count);
2277 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2278 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2279 cifs_stats_inc(&tcon->num_hardlinks);
2280 if (rc)
2281 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2283 cifs_buf_release(pSMB);
2284 if (rc == -EAGAIN)
2285 goto createHardLinkRetry;
2287 return rc;
2291 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2292 const char *fromName, const char *toName,
2293 const struct nls_table *nls_codepage, int remap)
2295 int rc = 0;
2296 NT_RENAME_REQ *pSMB = NULL;
2297 RENAME_RSP *pSMBr = NULL;
2298 int bytes_returned;
2299 int name_len, name_len2;
2300 __u16 count;
2302 cFYI(1, ("In CIFSCreateHardLink"));
2303 winCreateHardLinkRetry:
2305 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2306 (void **) &pSMBr);
2307 if (rc)
2308 return rc;
2310 pSMB->SearchAttributes =
2311 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2312 ATTR_DIRECTORY);
2313 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2314 pSMB->ClusterCount = 0;
2316 pSMB->BufferFormat = 0x04;
2318 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2319 name_len =
2320 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2321 PATH_MAX, nls_codepage, remap);
2322 name_len++; /* trailing null */
2323 name_len *= 2;
2325 /* protocol specifies ASCII buffer format (0x04) for unicode */
2326 pSMB->OldFileName[name_len] = 0x04;
2327 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2328 name_len2 =
2329 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2330 toName, PATH_MAX, nls_codepage, remap);
2331 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2332 name_len2 *= 2; /* convert to bytes */
2333 } else { /* BB improve the check for buffer overruns BB */
2334 name_len = strnlen(fromName, PATH_MAX);
2335 name_len++; /* trailing null */
2336 strncpy(pSMB->OldFileName, fromName, name_len);
2337 name_len2 = strnlen(toName, PATH_MAX);
2338 name_len2++; /* trailing null */
2339 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2340 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2341 name_len2++; /* trailing null */
2342 name_len2++; /* signature byte */
2345 count = 1 /* string type byte */ + name_len + name_len2;
2346 pSMB->hdr.smb_buf_length += count;
2347 pSMB->ByteCount = cpu_to_le16(count);
2349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2351 cifs_stats_inc(&tcon->num_hardlinks);
2352 if (rc)
2353 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2355 cifs_buf_release(pSMB);
2356 if (rc == -EAGAIN)
2357 goto winCreateHardLinkRetry;
2359 return rc;
2363 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2364 const unsigned char *searchName, char **symlinkinfo,
2365 const struct nls_table *nls_codepage)
2367 /* SMB_QUERY_FILE_UNIX_LINK */
2368 TRANSACTION2_QPI_REQ *pSMB = NULL;
2369 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2370 int rc = 0;
2371 int bytes_returned;
2372 int name_len;
2373 __u16 params, byte_count;
2374 char *data_start;
2376 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2378 querySymLinkRetry:
2379 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2380 (void **) &pSMBr);
2381 if (rc)
2382 return rc;
2384 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2385 name_len =
2386 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2387 PATH_MAX, nls_codepage);
2388 name_len++; /* trailing null */
2389 name_len *= 2;
2390 } else { /* BB improve the check for buffer overruns BB */
2391 name_len = strnlen(searchName, PATH_MAX);
2392 name_len++; /* trailing null */
2393 strncpy(pSMB->FileName, searchName, name_len);
2396 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2397 pSMB->TotalDataCount = 0;
2398 pSMB->MaxParameterCount = cpu_to_le16(2);
2399 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
2400 pSMB->MaxSetupCount = 0;
2401 pSMB->Reserved = 0;
2402 pSMB->Flags = 0;
2403 pSMB->Timeout = 0;
2404 pSMB->Reserved2 = 0;
2405 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2406 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2407 pSMB->DataCount = 0;
2408 pSMB->DataOffset = 0;
2409 pSMB->SetupCount = 1;
2410 pSMB->Reserved3 = 0;
2411 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2412 byte_count = params + 1 /* pad */ ;
2413 pSMB->TotalParameterCount = cpu_to_le16(params);
2414 pSMB->ParameterCount = pSMB->TotalParameterCount;
2415 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2416 pSMB->Reserved4 = 0;
2417 pSMB->hdr.smb_buf_length += byte_count;
2418 pSMB->ByteCount = cpu_to_le16(byte_count);
2420 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2421 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2422 if (rc) {
2423 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2424 } else {
2425 /* decode response */
2427 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2428 /* BB also check enough total bytes returned */
2429 if (rc || (pSMBr->ByteCount < 2))
2430 rc = -EIO;
2431 else {
2432 bool is_unicode;
2433 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2435 data_start = ((char *) &pSMBr->hdr.Protocol) +
2436 le16_to_cpu(pSMBr->t2.DataOffset);
2438 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2439 is_unicode = true;
2440 else
2441 is_unicode = false;
2443 /* BB FIXME investigate remapping reserved chars here */
2444 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
2445 is_unicode, nls_codepage);
2446 if (!*symlinkinfo)
2447 rc = -ENOMEM;
2450 cifs_buf_release(pSMB);
2451 if (rc == -EAGAIN)
2452 goto querySymLinkRetry;
2453 return rc;
2456 #ifdef CONFIG_CIFS_EXPERIMENTAL
2457 /* Initialize NT TRANSACT SMB into small smb request buffer.
2458 This assumes that all NT TRANSACTS that we init here have
2459 total parm and data under about 400 bytes (to fit in small cifs
2460 buffer size), which is the case so far, it easily fits. NB:
2461 Setup words themselves and ByteCount
2462 MaxSetupCount (size of returned setup area) and
2463 MaxParameterCount (returned parms size) must be set by caller */
2464 static int
2465 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2466 const int parm_len, struct cifsTconInfo *tcon,
2467 void **ret_buf)
2469 int rc;
2470 __u32 temp_offset;
2471 struct smb_com_ntransact_req *pSMB;
2473 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2474 (void **)&pSMB);
2475 if (rc)
2476 return rc;
2477 *ret_buf = (void *)pSMB;
2478 pSMB->Reserved = 0;
2479 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2480 pSMB->TotalDataCount = 0;
2481 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2482 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2483 pSMB->ParameterCount = pSMB->TotalParameterCount;
2484 pSMB->DataCount = pSMB->TotalDataCount;
2485 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2486 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2487 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2488 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2489 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2490 pSMB->SubCommand = cpu_to_le16(sub_command);
2491 return 0;
2494 static int
2495 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2496 __u32 *pparmlen, __u32 *pdatalen)
2498 char *end_of_smb;
2499 __u32 data_count, data_offset, parm_count, parm_offset;
2500 struct smb_com_ntransact_rsp *pSMBr;
2502 *pdatalen = 0;
2503 *pparmlen = 0;
2505 if (buf == NULL)
2506 return -EINVAL;
2508 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2510 /* ByteCount was converted from little endian in SendReceive */
2511 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2512 (char *)&pSMBr->ByteCount;
2514 data_offset = le32_to_cpu(pSMBr->DataOffset);
2515 data_count = le32_to_cpu(pSMBr->DataCount);
2516 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2517 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2519 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2520 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2522 /* should we also check that parm and data areas do not overlap? */
2523 if (*ppparm > end_of_smb) {
2524 cFYI(1, ("parms start after end of smb"));
2525 return -EINVAL;
2526 } else if (parm_count + *ppparm > end_of_smb) {
2527 cFYI(1, ("parm end after end of smb"));
2528 return -EINVAL;
2529 } else if (*ppdata > end_of_smb) {
2530 cFYI(1, ("data starts after end of smb"));
2531 return -EINVAL;
2532 } else if (data_count + *ppdata > end_of_smb) {
2533 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2534 *ppdata, data_count, (data_count + *ppdata),
2535 end_of_smb, pSMBr));
2536 return -EINVAL;
2537 } else if (parm_count + data_count > pSMBr->ByteCount) {
2538 cFYI(1, ("parm count and data count larger than SMB"));
2539 return -EINVAL;
2541 *pdatalen = data_count;
2542 *pparmlen = parm_count;
2543 return 0;
2547 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2548 const unsigned char *searchName,
2549 char *symlinkinfo, const int buflen, __u16 fid,
2550 const struct nls_table *nls_codepage)
2552 int rc = 0;
2553 int bytes_returned;
2554 struct smb_com_transaction_ioctl_req *pSMB;
2555 struct smb_com_transaction_ioctl_rsp *pSMBr;
2557 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2558 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2559 (void **) &pSMBr);
2560 if (rc)
2561 return rc;
2563 pSMB->TotalParameterCount = 0 ;
2564 pSMB->TotalDataCount = 0;
2565 pSMB->MaxParameterCount = cpu_to_le32(2);
2566 /* BB find exact data count max from sess structure BB */
2567 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2568 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2569 pSMB->MaxSetupCount = 4;
2570 pSMB->Reserved = 0;
2571 pSMB->ParameterOffset = 0;
2572 pSMB->DataCount = 0;
2573 pSMB->DataOffset = 0;
2574 pSMB->SetupCount = 4;
2575 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2576 pSMB->ParameterCount = pSMB->TotalParameterCount;
2577 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2578 pSMB->IsFsctl = 1; /* FSCTL */
2579 pSMB->IsRootFlag = 0;
2580 pSMB->Fid = fid; /* file handle always le */
2581 pSMB->ByteCount = 0;
2583 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2584 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2585 if (rc) {
2586 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2587 } else { /* decode response */
2588 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2589 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2590 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
2591 /* BB also check enough total bytes returned */
2592 rc = -EIO; /* bad smb */
2593 goto qreparse_out;
2595 if (data_count && (data_count < 2048)) {
2596 char *end_of_smb = 2 /* sizeof byte count */ +
2597 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
2599 struct reparse_data *reparse_buf =
2600 (struct reparse_data *)
2601 ((char *)&pSMBr->hdr.Protocol
2602 + data_offset);
2603 if ((char *)reparse_buf >= end_of_smb) {
2604 rc = -EIO;
2605 goto qreparse_out;
2607 if ((reparse_buf->LinkNamesBuf +
2608 reparse_buf->TargetNameOffset +
2609 reparse_buf->TargetNameLen) > end_of_smb) {
2610 cFYI(1, ("reparse buf beyond SMB"));
2611 rc = -EIO;
2612 goto qreparse_out;
2615 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2616 cifs_from_ucs2(symlinkinfo, (__le16 *)
2617 (reparse_buf->LinkNamesBuf +
2618 reparse_buf->TargetNameOffset),
2619 buflen,
2620 reparse_buf->TargetNameLen,
2621 nls_codepage, 0);
2622 } else { /* ASCII names */
2623 strncpy(symlinkinfo,
2624 reparse_buf->LinkNamesBuf +
2625 reparse_buf->TargetNameOffset,
2626 min_t(const int, buflen,
2627 reparse_buf->TargetNameLen));
2629 } else {
2630 rc = -EIO;
2631 cFYI(1, ("Invalid return data count on "
2632 "get reparse info ioctl"));
2634 symlinkinfo[buflen] = 0; /* just in case so the caller
2635 does not go off the end of the buffer */
2636 cFYI(1, ("readlink result - %s", symlinkinfo));
2639 qreparse_out:
2640 cifs_buf_release(pSMB);
2642 /* Note: On -EAGAIN error only caller can retry on handle based calls
2643 since file handle passed in no longer valid */
2645 return rc;
2647 #endif /* CIFS_EXPERIMENTAL */
2649 #ifdef CONFIG_CIFS_POSIX
2651 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2652 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2653 struct cifs_posix_ace *cifs_ace)
2655 /* u8 cifs fields do not need le conversion */
2656 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2657 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2658 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2659 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2661 return;
2664 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2665 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2666 const int acl_type, const int size_of_data_area)
2668 int size = 0;
2669 int i;
2670 __u16 count;
2671 struct cifs_posix_ace *pACE;
2672 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2673 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2675 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2676 return -EOPNOTSUPP;
2678 if (acl_type & ACL_TYPE_ACCESS) {
2679 count = le16_to_cpu(cifs_acl->access_entry_count);
2680 pACE = &cifs_acl->ace_array[0];
2681 size = sizeof(struct cifs_posix_acl);
2682 size += sizeof(struct cifs_posix_ace) * count;
2683 /* check if we would go beyond end of SMB */
2684 if (size_of_data_area < size) {
2685 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2686 size_of_data_area, size));
2687 return -EINVAL;
2689 } else if (acl_type & ACL_TYPE_DEFAULT) {
2690 count = le16_to_cpu(cifs_acl->access_entry_count);
2691 size = sizeof(struct cifs_posix_acl);
2692 size += sizeof(struct cifs_posix_ace) * count;
2693 /* skip past access ACEs to get to default ACEs */
2694 pACE = &cifs_acl->ace_array[count];
2695 count = le16_to_cpu(cifs_acl->default_entry_count);
2696 size += sizeof(struct cifs_posix_ace) * count;
2697 /* check if we would go beyond end of SMB */
2698 if (size_of_data_area < size)
2699 return -EINVAL;
2700 } else {
2701 /* illegal type */
2702 return -EINVAL;
2705 size = posix_acl_xattr_size(count);
2706 if ((buflen == 0) || (local_acl == NULL)) {
2707 /* used to query ACL EA size */
2708 } else if (size > buflen) {
2709 return -ERANGE;
2710 } else /* buffer big enough */ {
2711 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2712 for (i = 0; i < count ; i++) {
2713 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2714 pACE++;
2717 return size;
2720 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2721 const posix_acl_xattr_entry *local_ace)
2723 __u16 rc = 0; /* 0 = ACL converted ok */
2725 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2726 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2727 /* BB is there a better way to handle the large uid? */
2728 if (local_ace->e_id == cpu_to_le32(-1)) {
2729 /* Probably no need to le convert -1 on any arch but can not hurt */
2730 cifs_ace->cifs_uid = cpu_to_le64(-1);
2731 } else
2732 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2733 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2734 return rc;
2737 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2738 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2739 const int buflen, const int acl_type)
2741 __u16 rc = 0;
2742 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2743 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2744 int count;
2745 int i;
2747 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2748 return 0;
2750 count = posix_acl_xattr_count((size_t)buflen);
2751 cFYI(1, ("setting acl with %d entries from buf of length %d and "
2752 "version of %d",
2753 count, buflen, le32_to_cpu(local_acl->a_version)));
2754 if (le32_to_cpu(local_acl->a_version) != 2) {
2755 cFYI(1, ("unknown POSIX ACL version %d",
2756 le32_to_cpu(local_acl->a_version)));
2757 return 0;
2759 cifs_acl->version = cpu_to_le16(1);
2760 if (acl_type == ACL_TYPE_ACCESS)
2761 cifs_acl->access_entry_count = cpu_to_le16(count);
2762 else if (acl_type == ACL_TYPE_DEFAULT)
2763 cifs_acl->default_entry_count = cpu_to_le16(count);
2764 else {
2765 cFYI(1, ("unknown ACL type %d", acl_type));
2766 return 0;
2768 for (i = 0; i < count; i++) {
2769 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2770 &local_acl->a_entries[i]);
2771 if (rc != 0) {
2772 /* ACE not converted */
2773 break;
2776 if (rc == 0) {
2777 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2778 rc += sizeof(struct cifs_posix_acl);
2779 /* BB add check to make sure ACL does not overflow SMB */
2781 return rc;
2785 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2786 const unsigned char *searchName,
2787 char *acl_inf, const int buflen, const int acl_type,
2788 const struct nls_table *nls_codepage, int remap)
2790 /* SMB_QUERY_POSIX_ACL */
2791 TRANSACTION2_QPI_REQ *pSMB = NULL;
2792 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2793 int rc = 0;
2794 int bytes_returned;
2795 int name_len;
2796 __u16 params, byte_count;
2798 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2800 queryAclRetry:
2801 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2802 (void **) &pSMBr);
2803 if (rc)
2804 return rc;
2806 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2807 name_len =
2808 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2809 PATH_MAX, nls_codepage, remap);
2810 name_len++; /* trailing null */
2811 name_len *= 2;
2812 pSMB->FileName[name_len] = 0;
2813 pSMB->FileName[name_len+1] = 0;
2814 } else { /* BB improve the check for buffer overruns BB */
2815 name_len = strnlen(searchName, PATH_MAX);
2816 name_len++; /* trailing null */
2817 strncpy(pSMB->FileName, searchName, name_len);
2820 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2821 pSMB->TotalDataCount = 0;
2822 pSMB->MaxParameterCount = cpu_to_le16(2);
2823 /* BB find exact max data count below from sess structure BB */
2824 pSMB->MaxDataCount = cpu_to_le16(4000);
2825 pSMB->MaxSetupCount = 0;
2826 pSMB->Reserved = 0;
2827 pSMB->Flags = 0;
2828 pSMB->Timeout = 0;
2829 pSMB->Reserved2 = 0;
2830 pSMB->ParameterOffset = cpu_to_le16(
2831 offsetof(struct smb_com_transaction2_qpi_req,
2832 InformationLevel) - 4);
2833 pSMB->DataCount = 0;
2834 pSMB->DataOffset = 0;
2835 pSMB->SetupCount = 1;
2836 pSMB->Reserved3 = 0;
2837 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2838 byte_count = params + 1 /* pad */ ;
2839 pSMB->TotalParameterCount = cpu_to_le16(params);
2840 pSMB->ParameterCount = pSMB->TotalParameterCount;
2841 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2842 pSMB->Reserved4 = 0;
2843 pSMB->hdr.smb_buf_length += byte_count;
2844 pSMB->ByteCount = cpu_to_le16(byte_count);
2846 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2847 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2848 cifs_stats_inc(&tcon->num_acl_get);
2849 if (rc) {
2850 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2851 } else {
2852 /* decode response */
2854 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2855 if (rc || (pSMBr->ByteCount < 2))
2856 /* BB also check enough total bytes returned */
2857 rc = -EIO; /* bad smb */
2858 else {
2859 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2860 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2861 rc = cifs_copy_posix_acl(acl_inf,
2862 (char *)&pSMBr->hdr.Protocol+data_offset,
2863 buflen, acl_type, count);
2866 cifs_buf_release(pSMB);
2867 if (rc == -EAGAIN)
2868 goto queryAclRetry;
2869 return rc;
2873 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2874 const unsigned char *fileName,
2875 const char *local_acl, const int buflen,
2876 const int acl_type,
2877 const struct nls_table *nls_codepage, int remap)
2879 struct smb_com_transaction2_spi_req *pSMB = NULL;
2880 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2881 char *parm_data;
2882 int name_len;
2883 int rc = 0;
2884 int bytes_returned = 0;
2885 __u16 params, byte_count, data_count, param_offset, offset;
2887 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2888 setAclRetry:
2889 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2890 (void **) &pSMBr);
2891 if (rc)
2892 return rc;
2893 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2894 name_len =
2895 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2896 PATH_MAX, nls_codepage, remap);
2897 name_len++; /* trailing null */
2898 name_len *= 2;
2899 } else { /* BB improve the check for buffer overruns BB */
2900 name_len = strnlen(fileName, PATH_MAX);
2901 name_len++; /* trailing null */
2902 strncpy(pSMB->FileName, fileName, name_len);
2904 params = 6 + name_len;
2905 pSMB->MaxParameterCount = cpu_to_le16(2);
2906 /* BB find max SMB size from sess */
2907 pSMB->MaxDataCount = cpu_to_le16(1000);
2908 pSMB->MaxSetupCount = 0;
2909 pSMB->Reserved = 0;
2910 pSMB->Flags = 0;
2911 pSMB->Timeout = 0;
2912 pSMB->Reserved2 = 0;
2913 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2914 InformationLevel) - 4;
2915 offset = param_offset + params;
2916 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2917 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2919 /* convert to on the wire format for POSIX ACL */
2920 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2922 if (data_count == 0) {
2923 rc = -EOPNOTSUPP;
2924 goto setACLerrorExit;
2926 pSMB->DataOffset = cpu_to_le16(offset);
2927 pSMB->SetupCount = 1;
2928 pSMB->Reserved3 = 0;
2929 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2930 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2931 byte_count = 3 /* pad */ + params + data_count;
2932 pSMB->DataCount = cpu_to_le16(data_count);
2933 pSMB->TotalDataCount = pSMB->DataCount;
2934 pSMB->ParameterCount = cpu_to_le16(params);
2935 pSMB->TotalParameterCount = pSMB->ParameterCount;
2936 pSMB->Reserved4 = 0;
2937 pSMB->hdr.smb_buf_length += byte_count;
2938 pSMB->ByteCount = cpu_to_le16(byte_count);
2939 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2940 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2941 if (rc)
2942 cFYI(1, ("Set POSIX ACL returned %d", rc));
2944 setACLerrorExit:
2945 cifs_buf_release(pSMB);
2946 if (rc == -EAGAIN)
2947 goto setAclRetry;
2948 return rc;
2951 /* BB fix tabs in this function FIXME BB */
2953 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2954 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2956 int rc = 0;
2957 struct smb_t2_qfi_req *pSMB = NULL;
2958 struct smb_t2_qfi_rsp *pSMBr = NULL;
2959 int bytes_returned;
2960 __u16 params, byte_count;
2962 cFYI(1, ("In GetExtAttr"));
2963 if (tcon == NULL)
2964 return -ENODEV;
2966 GetExtAttrRetry:
2967 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2968 (void **) &pSMBr);
2969 if (rc)
2970 return rc;
2972 params = 2 /* level */ + 2 /* fid */;
2973 pSMB->t2.TotalDataCount = 0;
2974 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2975 /* BB find exact max data count below from sess structure BB */
2976 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2977 pSMB->t2.MaxSetupCount = 0;
2978 pSMB->t2.Reserved = 0;
2979 pSMB->t2.Flags = 0;
2980 pSMB->t2.Timeout = 0;
2981 pSMB->t2.Reserved2 = 0;
2982 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2983 Fid) - 4);
2984 pSMB->t2.DataCount = 0;
2985 pSMB->t2.DataOffset = 0;
2986 pSMB->t2.SetupCount = 1;
2987 pSMB->t2.Reserved3 = 0;
2988 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2989 byte_count = params + 1 /* pad */ ;
2990 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2991 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2992 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2993 pSMB->Pad = 0;
2994 pSMB->Fid = netfid;
2995 pSMB->hdr.smb_buf_length += byte_count;
2996 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2999 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3000 if (rc) {
3001 cFYI(1, ("error %d in GetExtAttr", rc));
3002 } else {
3003 /* decode response */
3004 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3005 if (rc || (pSMBr->ByteCount < 2))
3006 /* BB also check enough total bytes returned */
3007 /* If rc should we check for EOPNOSUPP and
3008 disable the srvino flag? or in caller? */
3009 rc = -EIO; /* bad smb */
3010 else {
3011 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3012 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3013 struct file_chattr_info *pfinfo;
3014 /* BB Do we need a cast or hash here ? */
3015 if (count != 16) {
3016 cFYI(1, ("Illegal size ret in GetExtAttr"));
3017 rc = -EIO;
3018 goto GetExtAttrOut;
3020 pfinfo = (struct file_chattr_info *)
3021 (data_offset + (char *) &pSMBr->hdr.Protocol);
3022 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3023 *pMask = le64_to_cpu(pfinfo->mask);
3026 GetExtAttrOut:
3027 cifs_buf_release(pSMB);
3028 if (rc == -EAGAIN)
3029 goto GetExtAttrRetry;
3030 return rc;
3033 #endif /* CONFIG_POSIX */
3035 #ifdef CONFIG_CIFS_EXPERIMENTAL
3036 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3038 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3039 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3041 int rc = 0;
3042 int buf_type = 0;
3043 QUERY_SEC_DESC_REQ *pSMB;
3044 struct kvec iov[1];
3046 cFYI(1, ("GetCifsACL"));
3048 *pbuflen = 0;
3049 *acl_inf = NULL;
3051 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3052 8 /* parm len */, tcon, (void **) &pSMB);
3053 if (rc)
3054 return rc;
3056 pSMB->MaxParameterCount = cpu_to_le32(4);
3057 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3058 pSMB->MaxSetupCount = 0;
3059 pSMB->Fid = fid; /* file handle always le */
3060 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3061 CIFS_ACL_DACL);
3062 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3063 pSMB->hdr.smb_buf_length += 11;
3064 iov[0].iov_base = (char *)pSMB;
3065 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3067 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3068 CIFS_STD_OP);
3069 cifs_stats_inc(&tcon->num_acl_get);
3070 if (rc) {
3071 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3072 } else { /* decode response */
3073 __le32 *parm;
3074 __u32 parm_len;
3075 __u32 acl_len;
3076 struct smb_com_ntransact_rsp *pSMBr;
3077 char *pdata;
3079 /* validate_nttransact */
3080 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3081 &pdata, &parm_len, pbuflen);
3082 if (rc)
3083 goto qsec_out;
3084 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3086 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3088 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3089 rc = -EIO; /* bad smb */
3090 *pbuflen = 0;
3091 goto qsec_out;
3094 /* BB check that data area is minimum length and as big as acl_len */
3096 acl_len = le32_to_cpu(*parm);
3097 if (acl_len != *pbuflen) {
3098 cERROR(1, ("acl length %d does not match %d",
3099 acl_len, *pbuflen));
3100 if (*pbuflen > acl_len)
3101 *pbuflen = acl_len;
3104 /* check if buffer is big enough for the acl
3105 header followed by the smallest SID */
3106 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3107 (*pbuflen >= 64 * 1024)) {
3108 cERROR(1, ("bad acl length %d", *pbuflen));
3109 rc = -EINVAL;
3110 *pbuflen = 0;
3111 } else {
3112 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3113 if (*acl_inf == NULL) {
3114 *pbuflen = 0;
3115 rc = -ENOMEM;
3117 memcpy(*acl_inf, pdata, *pbuflen);
3120 qsec_out:
3121 if (buf_type == CIFS_SMALL_BUFFER)
3122 cifs_small_buf_release(iov[0].iov_base);
3123 else if (buf_type == CIFS_LARGE_BUFFER)
3124 cifs_buf_release(iov[0].iov_base);
3125 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3126 return rc;
3130 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3131 struct cifs_ntsd *pntsd, __u32 acllen)
3133 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3134 int rc = 0;
3135 int bytes_returned = 0;
3136 SET_SEC_DESC_REQ *pSMB = NULL;
3137 NTRANSACT_RSP *pSMBr = NULL;
3139 setCifsAclRetry:
3140 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3141 (void **) &pSMBr);
3142 if (rc)
3143 return (rc);
3145 pSMB->MaxSetupCount = 0;
3146 pSMB->Reserved = 0;
3148 param_count = 8;
3149 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3150 data_count = acllen;
3151 data_offset = param_offset + param_count;
3152 byte_count = 3 /* pad */ + param_count;
3154 pSMB->DataCount = cpu_to_le32(data_count);
3155 pSMB->TotalDataCount = pSMB->DataCount;
3156 pSMB->MaxParameterCount = cpu_to_le32(4);
3157 pSMB->MaxDataCount = cpu_to_le32(16384);
3158 pSMB->ParameterCount = cpu_to_le32(param_count);
3159 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3160 pSMB->TotalParameterCount = pSMB->ParameterCount;
3161 pSMB->DataOffset = cpu_to_le32(data_offset);
3162 pSMB->SetupCount = 0;
3163 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3164 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3166 pSMB->Fid = fid; /* file handle always le */
3167 pSMB->Reserved2 = 0;
3168 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3170 if (pntsd && acllen) {
3171 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3172 (char *) pntsd,
3173 acllen);
3174 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3176 } else
3177 pSMB->hdr.smb_buf_length += byte_count;
3179 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3180 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3182 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3183 if (rc)
3184 cFYI(1, ("Set CIFS ACL returned %d", rc));
3185 cifs_buf_release(pSMB);
3187 if (rc == -EAGAIN)
3188 goto setCifsAclRetry;
3190 return (rc);
3193 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3195 /* Legacy Query Path Information call for lookup to old servers such
3196 as Win9x/WinME */
3197 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3198 const unsigned char *searchName,
3199 FILE_ALL_INFO *pFinfo,
3200 const struct nls_table *nls_codepage, int remap)
3202 QUERY_INFORMATION_REQ *pSMB;
3203 QUERY_INFORMATION_RSP *pSMBr;
3204 int rc = 0;
3205 int bytes_returned;
3206 int name_len;
3208 cFYI(1, ("In SMBQPath path %s", searchName));
3209 QInfRetry:
3210 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3211 (void **) &pSMBr);
3212 if (rc)
3213 return rc;
3215 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3216 name_len =
3217 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3218 PATH_MAX, nls_codepage, remap);
3219 name_len++; /* trailing null */
3220 name_len *= 2;
3221 } else {
3222 name_len = strnlen(searchName, PATH_MAX);
3223 name_len++; /* trailing null */
3224 strncpy(pSMB->FileName, searchName, name_len);
3226 pSMB->BufferFormat = 0x04;
3227 name_len++; /* account for buffer type byte */
3228 pSMB->hdr.smb_buf_length += (__u16) name_len;
3229 pSMB->ByteCount = cpu_to_le16(name_len);
3231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3232 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3233 if (rc) {
3234 cFYI(1, ("Send error in QueryInfo = %d", rc));
3235 } else if (pFinfo) {
3236 struct timespec ts;
3237 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3239 /* decode response */
3240 /* BB FIXME - add time zone adjustment BB */
3241 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3242 ts.tv_nsec = 0;
3243 ts.tv_sec = time;
3244 /* decode time fields */
3245 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3246 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3247 pFinfo->LastAccessTime = 0;
3248 pFinfo->AllocationSize =
3249 cpu_to_le64(le32_to_cpu(pSMBr->size));
3250 pFinfo->EndOfFile = pFinfo->AllocationSize;
3251 pFinfo->Attributes =
3252 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3253 } else
3254 rc = -EIO; /* bad buffer passed in */
3256 cifs_buf_release(pSMB);
3258 if (rc == -EAGAIN)
3259 goto QInfRetry;
3261 return rc;
3265 CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3266 u16 netfid, FILE_ALL_INFO *pFindData)
3268 struct smb_t2_qfi_req *pSMB = NULL;
3269 struct smb_t2_qfi_rsp *pSMBr = NULL;
3270 int rc = 0;
3271 int bytes_returned;
3272 __u16 params, byte_count;
3274 QFileInfoRetry:
3275 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3276 (void **) &pSMBr);
3277 if (rc)
3278 return rc;
3280 params = 2 /* level */ + 2 /* fid */;
3281 pSMB->t2.TotalDataCount = 0;
3282 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3283 /* BB find exact max data count below from sess structure BB */
3284 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3285 pSMB->t2.MaxSetupCount = 0;
3286 pSMB->t2.Reserved = 0;
3287 pSMB->t2.Flags = 0;
3288 pSMB->t2.Timeout = 0;
3289 pSMB->t2.Reserved2 = 0;
3290 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3291 Fid) - 4);
3292 pSMB->t2.DataCount = 0;
3293 pSMB->t2.DataOffset = 0;
3294 pSMB->t2.SetupCount = 1;
3295 pSMB->t2.Reserved3 = 0;
3296 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3297 byte_count = params + 1 /* pad */ ;
3298 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3299 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3300 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3301 pSMB->Pad = 0;
3302 pSMB->Fid = netfid;
3303 pSMB->hdr.smb_buf_length += byte_count;
3305 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3306 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3307 if (rc) {
3308 cFYI(1, ("Send error in QPathInfo = %d", rc));
3309 } else { /* decode response */
3310 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3312 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3313 rc = -EIO;
3314 else if (pSMBr->ByteCount < 40)
3315 rc = -EIO; /* bad smb */
3316 else if (pFindData) {
3317 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3318 memcpy((char *) pFindData,
3319 (char *) &pSMBr->hdr.Protocol +
3320 data_offset, sizeof(FILE_ALL_INFO));
3321 } else
3322 rc = -ENOMEM;
3324 cifs_buf_release(pSMB);
3325 if (rc == -EAGAIN)
3326 goto QFileInfoRetry;
3328 return rc;
3332 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3333 const unsigned char *searchName,
3334 FILE_ALL_INFO *pFindData,
3335 int legacy /* old style infolevel */,
3336 const struct nls_table *nls_codepage, int remap)
3338 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3339 TRANSACTION2_QPI_REQ *pSMB = NULL;
3340 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3341 int rc = 0;
3342 int bytes_returned;
3343 int name_len;
3344 __u16 params, byte_count;
3346 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3347 QPathInfoRetry:
3348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3349 (void **) &pSMBr);
3350 if (rc)
3351 return rc;
3353 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3354 name_len =
3355 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3356 PATH_MAX, nls_codepage, remap);
3357 name_len++; /* trailing null */
3358 name_len *= 2;
3359 } else { /* BB improve the check for buffer overruns BB */
3360 name_len = strnlen(searchName, PATH_MAX);
3361 name_len++; /* trailing null */
3362 strncpy(pSMB->FileName, searchName, name_len);
3365 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3366 pSMB->TotalDataCount = 0;
3367 pSMB->MaxParameterCount = cpu_to_le16(2);
3368 /* BB find exact max SMB PDU from sess structure BB */
3369 pSMB->MaxDataCount = cpu_to_le16(4000);
3370 pSMB->MaxSetupCount = 0;
3371 pSMB->Reserved = 0;
3372 pSMB->Flags = 0;
3373 pSMB->Timeout = 0;
3374 pSMB->Reserved2 = 0;
3375 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3376 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3377 pSMB->DataCount = 0;
3378 pSMB->DataOffset = 0;
3379 pSMB->SetupCount = 1;
3380 pSMB->Reserved3 = 0;
3381 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3382 byte_count = params + 1 /* pad */ ;
3383 pSMB->TotalParameterCount = cpu_to_le16(params);
3384 pSMB->ParameterCount = pSMB->TotalParameterCount;
3385 if (legacy)
3386 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3387 else
3388 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3389 pSMB->Reserved4 = 0;
3390 pSMB->hdr.smb_buf_length += byte_count;
3391 pSMB->ByteCount = cpu_to_le16(byte_count);
3393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3395 if (rc) {
3396 cFYI(1, ("Send error in QPathInfo = %d", rc));
3397 } else { /* decode response */
3398 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3400 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3401 rc = -EIO;
3402 else if (!legacy && (pSMBr->ByteCount < 40))
3403 rc = -EIO; /* bad smb */
3404 else if (legacy && (pSMBr->ByteCount < 24))
3405 rc = -EIO; /* 24 or 26 expected but we do not read
3406 last field */
3407 else if (pFindData) {
3408 int size;
3409 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3411 /* On legacy responses we do not read the last field,
3412 EAsize, fortunately since it varies by subdialect and
3413 also note it differs on Set vs. Get, ie two bytes or 4
3414 bytes depending but we don't care here */
3415 if (legacy)
3416 size = sizeof(FILE_INFO_STANDARD);
3417 else
3418 size = sizeof(FILE_ALL_INFO);
3419 memcpy((char *) pFindData,
3420 (char *) &pSMBr->hdr.Protocol +
3421 data_offset, size);
3422 } else
3423 rc = -ENOMEM;
3425 cifs_buf_release(pSMB);
3426 if (rc == -EAGAIN)
3427 goto QPathInfoRetry;
3429 return rc;
3433 CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3434 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3436 struct smb_t2_qfi_req *pSMB = NULL;
3437 struct smb_t2_qfi_rsp *pSMBr = NULL;
3438 int rc = 0;
3439 int bytes_returned;
3440 __u16 params, byte_count;
3442 UnixQFileInfoRetry:
3443 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3444 (void **) &pSMBr);
3445 if (rc)
3446 return rc;
3448 params = 2 /* level */ + 2 /* fid */;
3449 pSMB->t2.TotalDataCount = 0;
3450 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3451 /* BB find exact max data count below from sess structure BB */
3452 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3453 pSMB->t2.MaxSetupCount = 0;
3454 pSMB->t2.Reserved = 0;
3455 pSMB->t2.Flags = 0;
3456 pSMB->t2.Timeout = 0;
3457 pSMB->t2.Reserved2 = 0;
3458 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3459 Fid) - 4);
3460 pSMB->t2.DataCount = 0;
3461 pSMB->t2.DataOffset = 0;
3462 pSMB->t2.SetupCount = 1;
3463 pSMB->t2.Reserved3 = 0;
3464 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3465 byte_count = params + 1 /* pad */ ;
3466 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3467 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3468 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3469 pSMB->Pad = 0;
3470 pSMB->Fid = netfid;
3471 pSMB->hdr.smb_buf_length += byte_count;
3473 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3474 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3475 if (rc) {
3476 cFYI(1, ("Send error in QPathInfo = %d", rc));
3477 } else { /* decode response */
3478 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3480 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3481 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3482 "Unix Extensions can be disabled on mount "
3483 "by specifying the nosfu mount option."));
3484 rc = -EIO; /* bad smb */
3485 } else {
3486 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3487 memcpy((char *) pFindData,
3488 (char *) &pSMBr->hdr.Protocol +
3489 data_offset,
3490 sizeof(FILE_UNIX_BASIC_INFO));
3494 cifs_buf_release(pSMB);
3495 if (rc == -EAGAIN)
3496 goto UnixQFileInfoRetry;
3498 return rc;
3502 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3503 const unsigned char *searchName,
3504 FILE_UNIX_BASIC_INFO *pFindData,
3505 const struct nls_table *nls_codepage, int remap)
3507 /* SMB_QUERY_FILE_UNIX_BASIC */
3508 TRANSACTION2_QPI_REQ *pSMB = NULL;
3509 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3510 int rc = 0;
3511 int bytes_returned = 0;
3512 int name_len;
3513 __u16 params, byte_count;
3515 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3516 UnixQPathInfoRetry:
3517 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3518 (void **) &pSMBr);
3519 if (rc)
3520 return rc;
3522 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3523 name_len =
3524 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3525 PATH_MAX, nls_codepage, remap);
3526 name_len++; /* trailing null */
3527 name_len *= 2;
3528 } else { /* BB improve the check for buffer overruns BB */
3529 name_len = strnlen(searchName, PATH_MAX);
3530 name_len++; /* trailing null */
3531 strncpy(pSMB->FileName, searchName, name_len);
3534 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3535 pSMB->TotalDataCount = 0;
3536 pSMB->MaxParameterCount = cpu_to_le16(2);
3537 /* BB find exact max SMB PDU from sess structure BB */
3538 pSMB->MaxDataCount = cpu_to_le16(4000);
3539 pSMB->MaxSetupCount = 0;
3540 pSMB->Reserved = 0;
3541 pSMB->Flags = 0;
3542 pSMB->Timeout = 0;
3543 pSMB->Reserved2 = 0;
3544 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3545 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3546 pSMB->DataCount = 0;
3547 pSMB->DataOffset = 0;
3548 pSMB->SetupCount = 1;
3549 pSMB->Reserved3 = 0;
3550 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3551 byte_count = params + 1 /* pad */ ;
3552 pSMB->TotalParameterCount = cpu_to_le16(params);
3553 pSMB->ParameterCount = pSMB->TotalParameterCount;
3554 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3555 pSMB->Reserved4 = 0;
3556 pSMB->hdr.smb_buf_length += byte_count;
3557 pSMB->ByteCount = cpu_to_le16(byte_count);
3559 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3560 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3561 if (rc) {
3562 cFYI(1, ("Send error in QPathInfo = %d", rc));
3563 } else { /* decode response */
3564 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3566 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3567 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3568 "Unix Extensions can be disabled on mount "
3569 "by specifying the nosfu mount option."));
3570 rc = -EIO; /* bad smb */
3571 } else {
3572 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3573 memcpy((char *) pFindData,
3574 (char *) &pSMBr->hdr.Protocol +
3575 data_offset,
3576 sizeof(FILE_UNIX_BASIC_INFO));
3579 cifs_buf_release(pSMB);
3580 if (rc == -EAGAIN)
3581 goto UnixQPathInfoRetry;
3583 return rc;
3586 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3588 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3589 const char *searchName,
3590 const struct nls_table *nls_codepage,
3591 __u16 *pnetfid,
3592 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3594 /* level 257 SMB_ */
3595 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3596 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3597 T2_FFIRST_RSP_PARMS *parms;
3598 int rc = 0;
3599 int bytes_returned = 0;
3600 int name_len;
3601 __u16 params, byte_count;
3603 cFYI(1, ("In FindFirst for %s", searchName));
3605 findFirstRetry:
3606 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3607 (void **) &pSMBr);
3608 if (rc)
3609 return rc;
3611 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3612 name_len =
3613 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3614 PATH_MAX, nls_codepage, remap);
3615 /* We can not add the asterik earlier in case
3616 it got remapped to 0xF03A as if it were part of the
3617 directory name instead of a wildcard */
3618 name_len *= 2;
3619 pSMB->FileName[name_len] = dirsep;
3620 pSMB->FileName[name_len+1] = 0;
3621 pSMB->FileName[name_len+2] = '*';
3622 pSMB->FileName[name_len+3] = 0;
3623 name_len += 4; /* now the trailing null */
3624 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3625 pSMB->FileName[name_len+1] = 0;
3626 name_len += 2;
3627 } else { /* BB add check for overrun of SMB buf BB */
3628 name_len = strnlen(searchName, PATH_MAX);
3629 /* BB fix here and in unicode clause above ie
3630 if (name_len > buffersize-header)
3631 free buffer exit; BB */
3632 strncpy(pSMB->FileName, searchName, name_len);
3633 pSMB->FileName[name_len] = dirsep;
3634 pSMB->FileName[name_len+1] = '*';
3635 pSMB->FileName[name_len+2] = 0;
3636 name_len += 3;
3639 params = 12 + name_len /* includes null */ ;
3640 pSMB->TotalDataCount = 0; /* no EAs */
3641 pSMB->MaxParameterCount = cpu_to_le16(10);
3642 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3643 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3644 pSMB->MaxSetupCount = 0;
3645 pSMB->Reserved = 0;
3646 pSMB->Flags = 0;
3647 pSMB->Timeout = 0;
3648 pSMB->Reserved2 = 0;
3649 byte_count = params + 1 /* pad */ ;
3650 pSMB->TotalParameterCount = cpu_to_le16(params);
3651 pSMB->ParameterCount = pSMB->TotalParameterCount;
3652 pSMB->ParameterOffset = cpu_to_le16(
3653 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3654 - 4);
3655 pSMB->DataCount = 0;
3656 pSMB->DataOffset = 0;
3657 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3658 pSMB->Reserved3 = 0;
3659 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3660 pSMB->SearchAttributes =
3661 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3662 ATTR_DIRECTORY);
3663 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3664 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3665 CIFS_SEARCH_RETURN_RESUME);
3666 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3668 /* BB what should we set StorageType to? Does it matter? BB */
3669 pSMB->SearchStorageType = 0;
3670 pSMB->hdr.smb_buf_length += byte_count;
3671 pSMB->ByteCount = cpu_to_le16(byte_count);
3673 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3674 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3675 cifs_stats_inc(&tcon->num_ffirst);
3677 if (rc) {/* BB add logic to retry regular search if Unix search
3678 rejected unexpectedly by server */
3679 /* BB Add code to handle unsupported level rc */
3680 cFYI(1, ("Error in FindFirst = %d", rc));
3682 cifs_buf_release(pSMB);
3684 /* BB eventually could optimize out free and realloc of buf */
3685 /* for this case */
3686 if (rc == -EAGAIN)
3687 goto findFirstRetry;
3688 } else { /* decode response */
3689 /* BB remember to free buffer if error BB */
3690 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3691 if (rc == 0) {
3692 unsigned int lnoff;
3694 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3695 psrch_inf->unicode = true;
3696 else
3697 psrch_inf->unicode = false;
3699 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3700 psrch_inf->smallBuf = 0;
3701 psrch_inf->srch_entries_start =
3702 (char *) &pSMBr->hdr.Protocol +
3703 le16_to_cpu(pSMBr->t2.DataOffset);
3704 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3705 le16_to_cpu(pSMBr->t2.ParameterOffset));
3707 if (parms->EndofSearch)
3708 psrch_inf->endOfSearch = true;
3709 else
3710 psrch_inf->endOfSearch = false;
3712 psrch_inf->entries_in_buffer =
3713 le16_to_cpu(parms->SearchCount);
3714 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3715 psrch_inf->entries_in_buffer;
3716 lnoff = le16_to_cpu(parms->LastNameOffset);
3717 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3718 lnoff) {
3719 cERROR(1, ("ignoring corrupt resume name"));
3720 psrch_inf->last_entry = NULL;
3721 return rc;
3724 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3725 lnoff;
3727 *pnetfid = parms->SearchHandle;
3728 } else {
3729 cifs_buf_release(pSMB);
3733 return rc;
3736 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3737 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3739 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3740 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3741 T2_FNEXT_RSP_PARMS *parms;
3742 char *response_data;
3743 int rc = 0;
3744 int bytes_returned, name_len;
3745 __u16 params, byte_count;
3747 cFYI(1, ("In FindNext"));
3749 if (psrch_inf->endOfSearch)
3750 return -ENOENT;
3752 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3753 (void **) &pSMBr);
3754 if (rc)
3755 return rc;
3757 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3758 byte_count = 0;
3759 pSMB->TotalDataCount = 0; /* no EAs */
3760 pSMB->MaxParameterCount = cpu_to_le16(8);
3761 pSMB->MaxDataCount =
3762 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3763 0xFFFFFF00);
3764 pSMB->MaxSetupCount = 0;
3765 pSMB->Reserved = 0;
3766 pSMB->Flags = 0;
3767 pSMB->Timeout = 0;
3768 pSMB->Reserved2 = 0;
3769 pSMB->ParameterOffset = cpu_to_le16(
3770 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3771 pSMB->DataCount = 0;
3772 pSMB->DataOffset = 0;
3773 pSMB->SetupCount = 1;
3774 pSMB->Reserved3 = 0;
3775 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3776 pSMB->SearchHandle = searchHandle; /* always kept as le */
3777 pSMB->SearchCount =
3778 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3779 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3780 pSMB->ResumeKey = psrch_inf->resume_key;
3781 pSMB->SearchFlags =
3782 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3784 name_len = psrch_inf->resume_name_len;
3785 params += name_len;
3786 if (name_len < PATH_MAX) {
3787 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3788 byte_count += name_len;
3789 /* 14 byte parm len above enough for 2 byte null terminator */
3790 pSMB->ResumeFileName[name_len] = 0;
3791 pSMB->ResumeFileName[name_len+1] = 0;
3792 } else {
3793 rc = -EINVAL;
3794 goto FNext2_err_exit;
3796 byte_count = params + 1 /* pad */ ;
3797 pSMB->TotalParameterCount = cpu_to_le16(params);
3798 pSMB->ParameterCount = pSMB->TotalParameterCount;
3799 pSMB->hdr.smb_buf_length += byte_count;
3800 pSMB->ByteCount = cpu_to_le16(byte_count);
3802 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3803 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3804 cifs_stats_inc(&tcon->num_fnext);
3805 if (rc) {
3806 if (rc == -EBADF) {
3807 psrch_inf->endOfSearch = true;
3808 cifs_buf_release(pSMB);
3809 rc = 0; /* search probably was closed at end of search*/
3810 } else
3811 cFYI(1, ("FindNext returned = %d", rc));
3812 } else { /* decode response */
3813 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3815 if (rc == 0) {
3816 unsigned int lnoff;
3818 /* BB fixme add lock for file (srch_info) struct here */
3819 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3820 psrch_inf->unicode = true;
3821 else
3822 psrch_inf->unicode = false;
3823 response_data = (char *) &pSMBr->hdr.Protocol +
3824 le16_to_cpu(pSMBr->t2.ParameterOffset);
3825 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3826 response_data = (char *)&pSMBr->hdr.Protocol +
3827 le16_to_cpu(pSMBr->t2.DataOffset);
3828 if (psrch_inf->smallBuf)
3829 cifs_small_buf_release(
3830 psrch_inf->ntwrk_buf_start);
3831 else
3832 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3833 psrch_inf->srch_entries_start = response_data;
3834 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3835 psrch_inf->smallBuf = 0;
3836 if (parms->EndofSearch)
3837 psrch_inf->endOfSearch = true;
3838 else
3839 psrch_inf->endOfSearch = false;
3840 psrch_inf->entries_in_buffer =
3841 le16_to_cpu(parms->SearchCount);
3842 psrch_inf->index_of_last_entry +=
3843 psrch_inf->entries_in_buffer;
3844 lnoff = le16_to_cpu(parms->LastNameOffset);
3845 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3846 lnoff) {
3847 cERROR(1, ("ignoring corrupt resume name"));
3848 psrch_inf->last_entry = NULL;
3849 return rc;
3850 } else
3851 psrch_inf->last_entry =
3852 psrch_inf->srch_entries_start + lnoff;
3854 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3855 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3857 /* BB fixme add unlock here */
3862 /* BB On error, should we leave previous search buf (and count and
3863 last entry fields) intact or free the previous one? */
3865 /* Note: On -EAGAIN error only caller can retry on handle based calls
3866 since file handle passed in no longer valid */
3867 FNext2_err_exit:
3868 if (rc != 0)
3869 cifs_buf_release(pSMB);
3870 return rc;
3874 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3875 const __u16 searchHandle)
3877 int rc = 0;
3878 FINDCLOSE_REQ *pSMB = NULL;
3880 cFYI(1, ("In CIFSSMBFindClose"));
3881 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3883 /* no sense returning error if session restarted
3884 as file handle has been closed */
3885 if (rc == -EAGAIN)
3886 return 0;
3887 if (rc)
3888 return rc;
3890 pSMB->FileID = searchHandle;
3891 pSMB->ByteCount = 0;
3892 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3893 if (rc)
3894 cERROR(1, ("Send error in FindClose = %d", rc));
3896 cifs_stats_inc(&tcon->num_fclose);
3898 /* Since session is dead, search handle closed on server already */
3899 if (rc == -EAGAIN)
3900 rc = 0;
3902 return rc;
3906 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3907 const unsigned char *searchName,
3908 __u64 *inode_number,
3909 const struct nls_table *nls_codepage, int remap)
3911 int rc = 0;
3912 TRANSACTION2_QPI_REQ *pSMB = NULL;
3913 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3914 int name_len, bytes_returned;
3915 __u16 params, byte_count;
3917 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3918 if (tcon == NULL)
3919 return -ENODEV;
3921 GetInodeNumberRetry:
3922 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3923 (void **) &pSMBr);
3924 if (rc)
3925 return rc;
3927 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3928 name_len =
3929 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3930 PATH_MAX, nls_codepage, remap);
3931 name_len++; /* trailing null */
3932 name_len *= 2;
3933 } else { /* BB improve the check for buffer overruns BB */
3934 name_len = strnlen(searchName, PATH_MAX);
3935 name_len++; /* trailing null */
3936 strncpy(pSMB->FileName, searchName, name_len);
3939 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3940 pSMB->TotalDataCount = 0;
3941 pSMB->MaxParameterCount = cpu_to_le16(2);
3942 /* BB find exact max data count below from sess structure BB */
3943 pSMB->MaxDataCount = cpu_to_le16(4000);
3944 pSMB->MaxSetupCount = 0;
3945 pSMB->Reserved = 0;
3946 pSMB->Flags = 0;
3947 pSMB->Timeout = 0;
3948 pSMB->Reserved2 = 0;
3949 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3950 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3951 pSMB->DataCount = 0;
3952 pSMB->DataOffset = 0;
3953 pSMB->SetupCount = 1;
3954 pSMB->Reserved3 = 0;
3955 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3956 byte_count = params + 1 /* pad */ ;
3957 pSMB->TotalParameterCount = cpu_to_le16(params);
3958 pSMB->ParameterCount = pSMB->TotalParameterCount;
3959 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3960 pSMB->Reserved4 = 0;
3961 pSMB->hdr.smb_buf_length += byte_count;
3962 pSMB->ByteCount = cpu_to_le16(byte_count);
3964 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3965 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3966 if (rc) {
3967 cFYI(1, ("error %d in QueryInternalInfo", rc));
3968 } else {
3969 /* decode response */
3970 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3971 if (rc || (pSMBr->ByteCount < 2))
3972 /* BB also check enough total bytes returned */
3973 /* If rc should we check for EOPNOSUPP and
3974 disable the srvino flag? or in caller? */
3975 rc = -EIO; /* bad smb */
3976 else {
3977 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3978 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3979 struct file_internal_info *pfinfo;
3980 /* BB Do we need a cast or hash here ? */
3981 if (count < 8) {
3982 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3983 rc = -EIO;
3984 goto GetInodeNumOut;
3986 pfinfo = (struct file_internal_info *)
3987 (data_offset + (char *) &pSMBr->hdr.Protocol);
3988 *inode_number = le64_to_cpu(pfinfo->UniqueId);
3991 GetInodeNumOut:
3992 cifs_buf_release(pSMB);
3993 if (rc == -EAGAIN)
3994 goto GetInodeNumberRetry;
3995 return rc;
3998 /* parses DFS refferal V3 structure
3999 * caller is responsible for freeing target_nodes
4000 * returns:
4001 * on success - 0
4002 * on failure - errno
4004 static int
4005 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
4006 unsigned int *num_of_nodes,
4007 struct dfs_info3_param **target_nodes,
4008 const struct nls_table *nls_codepage, int remap,
4009 const char *searchName)
4011 int i, rc = 0;
4012 char *data_end;
4013 bool is_unicode;
4014 struct dfs_referral_level_3 *ref;
4016 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4017 is_unicode = true;
4018 else
4019 is_unicode = false;
4020 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4022 if (*num_of_nodes < 1) {
4023 cERROR(1, ("num_referrals: must be at least > 0,"
4024 "but we get num_referrals = %d\n", *num_of_nodes));
4025 rc = -EINVAL;
4026 goto parse_DFS_referrals_exit;
4029 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
4030 if (ref->VersionNumber != cpu_to_le16(3)) {
4031 cERROR(1, ("Referrals of V%d version are not supported,"
4032 "should be V3", le16_to_cpu(ref->VersionNumber)));
4033 rc = -EINVAL;
4034 goto parse_DFS_referrals_exit;
4037 /* get the upper boundary of the resp buffer */
4038 data_end = (char *)(&(pSMBr->PathConsumed)) +
4039 le16_to_cpu(pSMBr->t2.DataCount);
4041 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
4042 *num_of_nodes,
4043 le32_to_cpu(pSMBr->DFSFlags)));
4045 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4046 *num_of_nodes, GFP_KERNEL);
4047 if (*target_nodes == NULL) {
4048 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
4049 rc = -ENOMEM;
4050 goto parse_DFS_referrals_exit;
4053 /* collect necessary data from referrals */
4054 for (i = 0; i < *num_of_nodes; i++) {
4055 char *temp;
4056 int max_len;
4057 struct dfs_info3_param *node = (*target_nodes)+i;
4059 node->flags = le32_to_cpu(pSMBr->DFSFlags);
4060 if (is_unicode) {
4061 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4062 GFP_KERNEL);
4063 if (tmp == NULL) {
4064 rc = -ENOMEM;
4065 goto parse_DFS_referrals_exit;
4067 cifsConvertToUCS((__le16 *) tmp, searchName,
4068 PATH_MAX, nls_codepage, remap);
4069 node->path_consumed = cifs_ucs2_bytes(tmp,
4070 le16_to_cpu(pSMBr->PathConsumed),
4071 nls_codepage);
4072 kfree(tmp);
4073 } else
4074 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4076 node->server_type = le16_to_cpu(ref->ServerType);
4077 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4079 /* copy DfsPath */
4080 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4081 max_len = data_end - temp;
4082 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4083 is_unicode, nls_codepage);
4084 if (!node->path_name) {
4085 rc = -ENOMEM;
4086 goto parse_DFS_referrals_exit;
4089 /* copy link target UNC */
4090 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4091 max_len = data_end - temp;
4092 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4093 is_unicode, nls_codepage);
4094 if (!node->node_name)
4095 rc = -ENOMEM;
4098 parse_DFS_referrals_exit:
4099 if (rc) {
4100 free_dfs_info_array(*target_nodes, *num_of_nodes);
4101 *target_nodes = NULL;
4102 *num_of_nodes = 0;
4104 return rc;
4108 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4109 const unsigned char *searchName,
4110 struct dfs_info3_param **target_nodes,
4111 unsigned int *num_of_nodes,
4112 const struct nls_table *nls_codepage, int remap)
4114 /* TRANS2_GET_DFS_REFERRAL */
4115 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4116 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4117 int rc = 0;
4118 int bytes_returned;
4119 int name_len;
4120 __u16 params, byte_count;
4121 *num_of_nodes = 0;
4122 *target_nodes = NULL;
4124 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4125 if (ses == NULL)
4126 return -ENODEV;
4127 getDFSRetry:
4128 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4129 (void **) &pSMBr);
4130 if (rc)
4131 return rc;
4133 /* server pointer checked in called function,
4134 but should never be null here anyway */
4135 pSMB->hdr.Mid = GetNextMid(ses->server);
4136 pSMB->hdr.Tid = ses->ipc_tid;
4137 pSMB->hdr.Uid = ses->Suid;
4138 if (ses->capabilities & CAP_STATUS32)
4139 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4140 if (ses->capabilities & CAP_DFS)
4141 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4143 if (ses->capabilities & CAP_UNICODE) {
4144 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4145 name_len =
4146 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4147 searchName, PATH_MAX, nls_codepage, remap);
4148 name_len++; /* trailing null */
4149 name_len *= 2;
4150 } else { /* BB improve the check for buffer overruns BB */
4151 name_len = strnlen(searchName, PATH_MAX);
4152 name_len++; /* trailing null */
4153 strncpy(pSMB->RequestFileName, searchName, name_len);
4156 if (ses->server) {
4157 if (ses->server->secMode &
4158 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4159 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4162 pSMB->hdr.Uid = ses->Suid;
4164 params = 2 /* level */ + name_len /*includes null */ ;
4165 pSMB->TotalDataCount = 0;
4166 pSMB->DataCount = 0;
4167 pSMB->DataOffset = 0;
4168 pSMB->MaxParameterCount = 0;
4169 /* BB find exact max SMB PDU from sess structure BB */
4170 pSMB->MaxDataCount = cpu_to_le16(4000);
4171 pSMB->MaxSetupCount = 0;
4172 pSMB->Reserved = 0;
4173 pSMB->Flags = 0;
4174 pSMB->Timeout = 0;
4175 pSMB->Reserved2 = 0;
4176 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4177 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4178 pSMB->SetupCount = 1;
4179 pSMB->Reserved3 = 0;
4180 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4181 byte_count = params + 3 /* pad */ ;
4182 pSMB->ParameterCount = cpu_to_le16(params);
4183 pSMB->TotalParameterCount = pSMB->ParameterCount;
4184 pSMB->MaxReferralLevel = cpu_to_le16(3);
4185 pSMB->hdr.smb_buf_length += byte_count;
4186 pSMB->ByteCount = cpu_to_le16(byte_count);
4188 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4189 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4190 if (rc) {
4191 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
4192 goto GetDFSRefExit;
4194 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4196 /* BB Also check if enough total bytes returned? */
4197 if (rc || (pSMBr->ByteCount < 17)) {
4198 rc = -EIO; /* bad smb */
4199 goto GetDFSRefExit;
4202 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4203 pSMBr->ByteCount,
4204 le16_to_cpu(pSMBr->t2.DataOffset)));
4206 /* parse returned result into more usable form */
4207 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4208 target_nodes, nls_codepage, remap,
4209 searchName);
4211 GetDFSRefExit:
4212 cifs_buf_release(pSMB);
4214 if (rc == -EAGAIN)
4215 goto getDFSRetry;
4217 return rc;
4220 /* Query File System Info such as free space to old servers such as Win 9x */
4222 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4224 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4225 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4226 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4227 FILE_SYSTEM_ALLOC_INFO *response_data;
4228 int rc = 0;
4229 int bytes_returned = 0;
4230 __u16 params, byte_count;
4232 cFYI(1, ("OldQFSInfo"));
4233 oldQFSInfoRetry:
4234 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4235 (void **) &pSMBr);
4236 if (rc)
4237 return rc;
4239 params = 2; /* level */
4240 pSMB->TotalDataCount = 0;
4241 pSMB->MaxParameterCount = cpu_to_le16(2);
4242 pSMB->MaxDataCount = cpu_to_le16(1000);
4243 pSMB->MaxSetupCount = 0;
4244 pSMB->Reserved = 0;
4245 pSMB->Flags = 0;
4246 pSMB->Timeout = 0;
4247 pSMB->Reserved2 = 0;
4248 byte_count = params + 1 /* pad */ ;
4249 pSMB->TotalParameterCount = cpu_to_le16(params);
4250 pSMB->ParameterCount = pSMB->TotalParameterCount;
4251 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4252 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4253 pSMB->DataCount = 0;
4254 pSMB->DataOffset = 0;
4255 pSMB->SetupCount = 1;
4256 pSMB->Reserved3 = 0;
4257 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4258 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4259 pSMB->hdr.smb_buf_length += byte_count;
4260 pSMB->ByteCount = cpu_to_le16(byte_count);
4262 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4263 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4264 if (rc) {
4265 cFYI(1, ("Send error in QFSInfo = %d", rc));
4266 } else { /* decode response */
4267 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4269 if (rc || (pSMBr->ByteCount < 18))
4270 rc = -EIO; /* bad smb */
4271 else {
4272 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4273 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4274 pSMBr->ByteCount, data_offset));
4276 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4277 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4278 FSData->f_bsize =
4279 le16_to_cpu(response_data->BytesPerSector) *
4280 le32_to_cpu(response_data->
4281 SectorsPerAllocationUnit);
4282 FSData->f_blocks =
4283 le32_to_cpu(response_data->TotalAllocationUnits);
4284 FSData->f_bfree = FSData->f_bavail =
4285 le32_to_cpu(response_data->FreeAllocationUnits);
4286 cFYI(1,
4287 ("Blocks: %lld Free: %lld Block size %ld",
4288 (unsigned long long)FSData->f_blocks,
4289 (unsigned long long)FSData->f_bfree,
4290 FSData->f_bsize));
4293 cifs_buf_release(pSMB);
4295 if (rc == -EAGAIN)
4296 goto oldQFSInfoRetry;
4298 return rc;
4302 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4304 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4305 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4306 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4307 FILE_SYSTEM_INFO *response_data;
4308 int rc = 0;
4309 int bytes_returned = 0;
4310 __u16 params, byte_count;
4312 cFYI(1, ("In QFSInfo"));
4313 QFSInfoRetry:
4314 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4315 (void **) &pSMBr);
4316 if (rc)
4317 return rc;
4319 params = 2; /* level */
4320 pSMB->TotalDataCount = 0;
4321 pSMB->MaxParameterCount = cpu_to_le16(2);
4322 pSMB->MaxDataCount = cpu_to_le16(1000);
4323 pSMB->MaxSetupCount = 0;
4324 pSMB->Reserved = 0;
4325 pSMB->Flags = 0;
4326 pSMB->Timeout = 0;
4327 pSMB->Reserved2 = 0;
4328 byte_count = params + 1 /* pad */ ;
4329 pSMB->TotalParameterCount = cpu_to_le16(params);
4330 pSMB->ParameterCount = pSMB->TotalParameterCount;
4331 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4332 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4333 pSMB->DataCount = 0;
4334 pSMB->DataOffset = 0;
4335 pSMB->SetupCount = 1;
4336 pSMB->Reserved3 = 0;
4337 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4338 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4339 pSMB->hdr.smb_buf_length += byte_count;
4340 pSMB->ByteCount = cpu_to_le16(byte_count);
4342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4343 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4344 if (rc) {
4345 cFYI(1, ("Send error in QFSInfo = %d", rc));
4346 } else { /* decode response */
4347 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4349 if (rc || (pSMBr->ByteCount < 24))
4350 rc = -EIO; /* bad smb */
4351 else {
4352 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4354 response_data =
4355 (FILE_SYSTEM_INFO
4356 *) (((char *) &pSMBr->hdr.Protocol) +
4357 data_offset);
4358 FSData->f_bsize =
4359 le32_to_cpu(response_data->BytesPerSector) *
4360 le32_to_cpu(response_data->
4361 SectorsPerAllocationUnit);
4362 FSData->f_blocks =
4363 le64_to_cpu(response_data->TotalAllocationUnits);
4364 FSData->f_bfree = FSData->f_bavail =
4365 le64_to_cpu(response_data->FreeAllocationUnits);
4366 cFYI(1,
4367 ("Blocks: %lld Free: %lld Block size %ld",
4368 (unsigned long long)FSData->f_blocks,
4369 (unsigned long long)FSData->f_bfree,
4370 FSData->f_bsize));
4373 cifs_buf_release(pSMB);
4375 if (rc == -EAGAIN)
4376 goto QFSInfoRetry;
4378 return rc;
4382 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4384 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4385 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4386 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4387 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4388 int rc = 0;
4389 int bytes_returned = 0;
4390 __u16 params, byte_count;
4392 cFYI(1, ("In QFSAttributeInfo"));
4393 QFSAttributeRetry:
4394 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4395 (void **) &pSMBr);
4396 if (rc)
4397 return rc;
4399 params = 2; /* level */
4400 pSMB->TotalDataCount = 0;
4401 pSMB->MaxParameterCount = cpu_to_le16(2);
4402 /* BB find exact max SMB PDU from sess structure BB */
4403 pSMB->MaxDataCount = cpu_to_le16(1000);
4404 pSMB->MaxSetupCount = 0;
4405 pSMB->Reserved = 0;
4406 pSMB->Flags = 0;
4407 pSMB->Timeout = 0;
4408 pSMB->Reserved2 = 0;
4409 byte_count = params + 1 /* pad */ ;
4410 pSMB->TotalParameterCount = cpu_to_le16(params);
4411 pSMB->ParameterCount = pSMB->TotalParameterCount;
4412 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4413 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4414 pSMB->DataCount = 0;
4415 pSMB->DataOffset = 0;
4416 pSMB->SetupCount = 1;
4417 pSMB->Reserved3 = 0;
4418 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4419 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4420 pSMB->hdr.smb_buf_length += byte_count;
4421 pSMB->ByteCount = cpu_to_le16(byte_count);
4423 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4424 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4425 if (rc) {
4426 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4427 } else { /* decode response */
4428 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4430 if (rc || (pSMBr->ByteCount < 13)) {
4431 /* BB also check if enough bytes returned */
4432 rc = -EIO; /* bad smb */
4433 } else {
4434 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4435 response_data =
4436 (FILE_SYSTEM_ATTRIBUTE_INFO
4437 *) (((char *) &pSMBr->hdr.Protocol) +
4438 data_offset);
4439 memcpy(&tcon->fsAttrInfo, response_data,
4440 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4443 cifs_buf_release(pSMB);
4445 if (rc == -EAGAIN)
4446 goto QFSAttributeRetry;
4448 return rc;
4452 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4454 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4455 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4456 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4457 FILE_SYSTEM_DEVICE_INFO *response_data;
4458 int rc = 0;
4459 int bytes_returned = 0;
4460 __u16 params, byte_count;
4462 cFYI(1, ("In QFSDeviceInfo"));
4463 QFSDeviceRetry:
4464 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4465 (void **) &pSMBr);
4466 if (rc)
4467 return rc;
4469 params = 2; /* level */
4470 pSMB->TotalDataCount = 0;
4471 pSMB->MaxParameterCount = cpu_to_le16(2);
4472 /* BB find exact max SMB PDU from sess structure BB */
4473 pSMB->MaxDataCount = cpu_to_le16(1000);
4474 pSMB->MaxSetupCount = 0;
4475 pSMB->Reserved = 0;
4476 pSMB->Flags = 0;
4477 pSMB->Timeout = 0;
4478 pSMB->Reserved2 = 0;
4479 byte_count = params + 1 /* pad */ ;
4480 pSMB->TotalParameterCount = cpu_to_le16(params);
4481 pSMB->ParameterCount = pSMB->TotalParameterCount;
4482 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4483 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4485 pSMB->DataCount = 0;
4486 pSMB->DataOffset = 0;
4487 pSMB->SetupCount = 1;
4488 pSMB->Reserved3 = 0;
4489 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4490 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4491 pSMB->hdr.smb_buf_length += byte_count;
4492 pSMB->ByteCount = cpu_to_le16(byte_count);
4494 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4495 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4496 if (rc) {
4497 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4498 } else { /* decode response */
4499 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4501 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4502 rc = -EIO; /* bad smb */
4503 else {
4504 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4505 response_data =
4506 (FILE_SYSTEM_DEVICE_INFO *)
4507 (((char *) &pSMBr->hdr.Protocol) +
4508 data_offset);
4509 memcpy(&tcon->fsDevInfo, response_data,
4510 sizeof(FILE_SYSTEM_DEVICE_INFO));
4513 cifs_buf_release(pSMB);
4515 if (rc == -EAGAIN)
4516 goto QFSDeviceRetry;
4518 return rc;
4522 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4524 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4525 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4526 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4527 FILE_SYSTEM_UNIX_INFO *response_data;
4528 int rc = 0;
4529 int bytes_returned = 0;
4530 __u16 params, byte_count;
4532 cFYI(1, ("In QFSUnixInfo"));
4533 QFSUnixRetry:
4534 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4535 (void **) &pSMBr);
4536 if (rc)
4537 return rc;
4539 params = 2; /* level */
4540 pSMB->TotalDataCount = 0;
4541 pSMB->DataCount = 0;
4542 pSMB->DataOffset = 0;
4543 pSMB->MaxParameterCount = cpu_to_le16(2);
4544 /* BB find exact max SMB PDU from sess structure BB */
4545 pSMB->MaxDataCount = cpu_to_le16(100);
4546 pSMB->MaxSetupCount = 0;
4547 pSMB->Reserved = 0;
4548 pSMB->Flags = 0;
4549 pSMB->Timeout = 0;
4550 pSMB->Reserved2 = 0;
4551 byte_count = params + 1 /* pad */ ;
4552 pSMB->ParameterCount = cpu_to_le16(params);
4553 pSMB->TotalParameterCount = pSMB->ParameterCount;
4554 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4555 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4556 pSMB->SetupCount = 1;
4557 pSMB->Reserved3 = 0;
4558 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4559 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4560 pSMB->hdr.smb_buf_length += byte_count;
4561 pSMB->ByteCount = cpu_to_le16(byte_count);
4563 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4564 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4565 if (rc) {
4566 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4567 } else { /* decode response */
4568 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4570 if (rc || (pSMBr->ByteCount < 13)) {
4571 rc = -EIO; /* bad smb */
4572 } else {
4573 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4574 response_data =
4575 (FILE_SYSTEM_UNIX_INFO
4576 *) (((char *) &pSMBr->hdr.Protocol) +
4577 data_offset);
4578 memcpy(&tcon->fsUnixInfo, response_data,
4579 sizeof(FILE_SYSTEM_UNIX_INFO));
4582 cifs_buf_release(pSMB);
4584 if (rc == -EAGAIN)
4585 goto QFSUnixRetry;
4588 return rc;
4592 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4594 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4595 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4596 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4597 int rc = 0;
4598 int bytes_returned = 0;
4599 __u16 params, param_offset, offset, byte_count;
4601 cFYI(1, ("In SETFSUnixInfo"));
4602 SETFSUnixRetry:
4603 /* BB switch to small buf init to save memory */
4604 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4605 (void **) &pSMBr);
4606 if (rc)
4607 return rc;
4609 params = 4; /* 2 bytes zero followed by info level. */
4610 pSMB->MaxSetupCount = 0;
4611 pSMB->Reserved = 0;
4612 pSMB->Flags = 0;
4613 pSMB->Timeout = 0;
4614 pSMB->Reserved2 = 0;
4615 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4616 - 4;
4617 offset = param_offset + params;
4619 pSMB->MaxParameterCount = cpu_to_le16(4);
4620 /* BB find exact max SMB PDU from sess structure BB */
4621 pSMB->MaxDataCount = cpu_to_le16(100);
4622 pSMB->SetupCount = 1;
4623 pSMB->Reserved3 = 0;
4624 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4625 byte_count = 1 /* pad */ + params + 12;
4627 pSMB->DataCount = cpu_to_le16(12);
4628 pSMB->ParameterCount = cpu_to_le16(params);
4629 pSMB->TotalDataCount = pSMB->DataCount;
4630 pSMB->TotalParameterCount = pSMB->ParameterCount;
4631 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4632 pSMB->DataOffset = cpu_to_le16(offset);
4634 /* Params. */
4635 pSMB->FileNum = 0;
4636 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4638 /* Data. */
4639 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4640 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4641 pSMB->ClientUnixCap = cpu_to_le64(cap);
4643 pSMB->hdr.smb_buf_length += byte_count;
4644 pSMB->ByteCount = cpu_to_le16(byte_count);
4646 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4647 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4648 if (rc) {
4649 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4650 } else { /* decode response */
4651 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4652 if (rc)
4653 rc = -EIO; /* bad smb */
4655 cifs_buf_release(pSMB);
4657 if (rc == -EAGAIN)
4658 goto SETFSUnixRetry;
4660 return rc;
4666 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4667 struct kstatfs *FSData)
4669 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4670 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4671 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4672 FILE_SYSTEM_POSIX_INFO *response_data;
4673 int rc = 0;
4674 int bytes_returned = 0;
4675 __u16 params, byte_count;
4677 cFYI(1, ("In QFSPosixInfo"));
4678 QFSPosixRetry:
4679 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4680 (void **) &pSMBr);
4681 if (rc)
4682 return rc;
4684 params = 2; /* level */
4685 pSMB->TotalDataCount = 0;
4686 pSMB->DataCount = 0;
4687 pSMB->DataOffset = 0;
4688 pSMB->MaxParameterCount = cpu_to_le16(2);
4689 /* BB find exact max SMB PDU from sess structure BB */
4690 pSMB->MaxDataCount = cpu_to_le16(100);
4691 pSMB->MaxSetupCount = 0;
4692 pSMB->Reserved = 0;
4693 pSMB->Flags = 0;
4694 pSMB->Timeout = 0;
4695 pSMB->Reserved2 = 0;
4696 byte_count = params + 1 /* pad */ ;
4697 pSMB->ParameterCount = cpu_to_le16(params);
4698 pSMB->TotalParameterCount = pSMB->ParameterCount;
4699 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4700 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4701 pSMB->SetupCount = 1;
4702 pSMB->Reserved3 = 0;
4703 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4704 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4705 pSMB->hdr.smb_buf_length += byte_count;
4706 pSMB->ByteCount = cpu_to_le16(byte_count);
4708 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4709 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4710 if (rc) {
4711 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4712 } else { /* decode response */
4713 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4715 if (rc || (pSMBr->ByteCount < 13)) {
4716 rc = -EIO; /* bad smb */
4717 } else {
4718 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4719 response_data =
4720 (FILE_SYSTEM_POSIX_INFO
4721 *) (((char *) &pSMBr->hdr.Protocol) +
4722 data_offset);
4723 FSData->f_bsize =
4724 le32_to_cpu(response_data->BlockSize);
4725 FSData->f_blocks =
4726 le64_to_cpu(response_data->TotalBlocks);
4727 FSData->f_bfree =
4728 le64_to_cpu(response_data->BlocksAvail);
4729 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4730 FSData->f_bavail = FSData->f_bfree;
4731 } else {
4732 FSData->f_bavail =
4733 le64_to_cpu(response_data->UserBlocksAvail);
4735 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4736 FSData->f_files =
4737 le64_to_cpu(response_data->TotalFileNodes);
4738 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4739 FSData->f_ffree =
4740 le64_to_cpu(response_data->FreeFileNodes);
4743 cifs_buf_release(pSMB);
4745 if (rc == -EAGAIN)
4746 goto QFSPosixRetry;
4748 return rc;
4752 /* We can not use write of zero bytes trick to
4753 set file size due to need for large file support. Also note that
4754 this SetPathInfo is preferred to SetFileInfo based method in next
4755 routine which is only needed to work around a sharing violation bug
4756 in Samba which this routine can run into */
4759 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4760 __u64 size, bool SetAllocation,
4761 const struct nls_table *nls_codepage, int remap)
4763 struct smb_com_transaction2_spi_req *pSMB = NULL;
4764 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4765 struct file_end_of_file_info *parm_data;
4766 int name_len;
4767 int rc = 0;
4768 int bytes_returned = 0;
4769 __u16 params, byte_count, data_count, param_offset, offset;
4771 cFYI(1, ("In SetEOF"));
4772 SetEOFRetry:
4773 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4774 (void **) &pSMBr);
4775 if (rc)
4776 return rc;
4778 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4779 name_len =
4780 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4781 PATH_MAX, nls_codepage, remap);
4782 name_len++; /* trailing null */
4783 name_len *= 2;
4784 } else { /* BB improve the check for buffer overruns BB */
4785 name_len = strnlen(fileName, PATH_MAX);
4786 name_len++; /* trailing null */
4787 strncpy(pSMB->FileName, fileName, name_len);
4789 params = 6 + name_len;
4790 data_count = sizeof(struct file_end_of_file_info);
4791 pSMB->MaxParameterCount = cpu_to_le16(2);
4792 pSMB->MaxDataCount = cpu_to_le16(4100);
4793 pSMB->MaxSetupCount = 0;
4794 pSMB->Reserved = 0;
4795 pSMB->Flags = 0;
4796 pSMB->Timeout = 0;
4797 pSMB->Reserved2 = 0;
4798 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4799 InformationLevel) - 4;
4800 offset = param_offset + params;
4801 if (SetAllocation) {
4802 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4803 pSMB->InformationLevel =
4804 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4805 else
4806 pSMB->InformationLevel =
4807 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4808 } else /* Set File Size */ {
4809 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4810 pSMB->InformationLevel =
4811 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4812 else
4813 pSMB->InformationLevel =
4814 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4817 parm_data =
4818 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4819 offset);
4820 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4821 pSMB->DataOffset = cpu_to_le16(offset);
4822 pSMB->SetupCount = 1;
4823 pSMB->Reserved3 = 0;
4824 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4825 byte_count = 3 /* pad */ + params + data_count;
4826 pSMB->DataCount = cpu_to_le16(data_count);
4827 pSMB->TotalDataCount = pSMB->DataCount;
4828 pSMB->ParameterCount = cpu_to_le16(params);
4829 pSMB->TotalParameterCount = pSMB->ParameterCount;
4830 pSMB->Reserved4 = 0;
4831 pSMB->hdr.smb_buf_length += byte_count;
4832 parm_data->FileSize = cpu_to_le64(size);
4833 pSMB->ByteCount = cpu_to_le16(byte_count);
4834 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4835 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4836 if (rc)
4837 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4839 cifs_buf_release(pSMB);
4841 if (rc == -EAGAIN)
4842 goto SetEOFRetry;
4844 return rc;
4848 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4849 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4851 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4852 char *data_offset;
4853 struct file_end_of_file_info *parm_data;
4854 int rc = 0;
4855 __u16 params, param_offset, offset, byte_count, count;
4857 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4858 (long long)size));
4859 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4861 if (rc)
4862 return rc;
4864 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4865 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4867 params = 6;
4868 pSMB->MaxSetupCount = 0;
4869 pSMB->Reserved = 0;
4870 pSMB->Flags = 0;
4871 pSMB->Timeout = 0;
4872 pSMB->Reserved2 = 0;
4873 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4874 offset = param_offset + params;
4876 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4878 count = sizeof(struct file_end_of_file_info);
4879 pSMB->MaxParameterCount = cpu_to_le16(2);
4880 /* BB find exact max SMB PDU from sess structure BB */
4881 pSMB->MaxDataCount = cpu_to_le16(1000);
4882 pSMB->SetupCount = 1;
4883 pSMB->Reserved3 = 0;
4884 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4885 byte_count = 3 /* pad */ + params + count;
4886 pSMB->DataCount = cpu_to_le16(count);
4887 pSMB->ParameterCount = cpu_to_le16(params);
4888 pSMB->TotalDataCount = pSMB->DataCount;
4889 pSMB->TotalParameterCount = pSMB->ParameterCount;
4890 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4891 parm_data =
4892 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4893 + offset);
4894 pSMB->DataOffset = cpu_to_le16(offset);
4895 parm_data->FileSize = cpu_to_le64(size);
4896 pSMB->Fid = fid;
4897 if (SetAllocation) {
4898 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4899 pSMB->InformationLevel =
4900 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4901 else
4902 pSMB->InformationLevel =
4903 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4904 } else /* Set File Size */ {
4905 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4906 pSMB->InformationLevel =
4907 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4908 else
4909 pSMB->InformationLevel =
4910 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4912 pSMB->Reserved4 = 0;
4913 pSMB->hdr.smb_buf_length += byte_count;
4914 pSMB->ByteCount = cpu_to_le16(byte_count);
4915 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4916 if (rc) {
4917 cFYI(1,
4918 ("Send error in SetFileInfo (SetFileSize) = %d",
4919 rc));
4922 /* Note: On -EAGAIN error only caller can retry on handle based calls
4923 since file handle passed in no longer valid */
4925 return rc;
4928 /* Some legacy servers such as NT4 require that the file times be set on
4929 an open handle, rather than by pathname - this is awkward due to
4930 potential access conflicts on the open, but it is unavoidable for these
4931 old servers since the only other choice is to go from 100 nanosecond DCE
4932 time and resort to the original setpathinfo level which takes the ancient
4933 DOS time format with 2 second granularity */
4935 CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4936 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4938 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4939 char *data_offset;
4940 int rc = 0;
4941 __u16 params, param_offset, offset, byte_count, count;
4943 cFYI(1, ("Set Times (via SetFileInfo)"));
4944 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4946 if (rc)
4947 return rc;
4949 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4950 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4952 params = 6;
4953 pSMB->MaxSetupCount = 0;
4954 pSMB->Reserved = 0;
4955 pSMB->Flags = 0;
4956 pSMB->Timeout = 0;
4957 pSMB->Reserved2 = 0;
4958 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4959 offset = param_offset + params;
4961 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4963 count = sizeof(FILE_BASIC_INFO);
4964 pSMB->MaxParameterCount = cpu_to_le16(2);
4965 /* BB find max SMB PDU from sess */
4966 pSMB->MaxDataCount = cpu_to_le16(1000);
4967 pSMB->SetupCount = 1;
4968 pSMB->Reserved3 = 0;
4969 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4970 byte_count = 3 /* pad */ + params + count;
4971 pSMB->DataCount = cpu_to_le16(count);
4972 pSMB->ParameterCount = cpu_to_le16(params);
4973 pSMB->TotalDataCount = pSMB->DataCount;
4974 pSMB->TotalParameterCount = pSMB->ParameterCount;
4975 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4976 pSMB->DataOffset = cpu_to_le16(offset);
4977 pSMB->Fid = fid;
4978 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4979 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4980 else
4981 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4982 pSMB->Reserved4 = 0;
4983 pSMB->hdr.smb_buf_length += byte_count;
4984 pSMB->ByteCount = cpu_to_le16(byte_count);
4985 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4986 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4987 if (rc)
4988 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4990 /* Note: On -EAGAIN error only caller can retry on handle based calls
4991 since file handle passed in no longer valid */
4993 return rc;
4997 CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4998 bool delete_file, __u16 fid, __u32 pid_of_opener)
5000 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5001 char *data_offset;
5002 int rc = 0;
5003 __u16 params, param_offset, offset, byte_count, count;
5005 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
5006 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5008 if (rc)
5009 return rc;
5011 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5012 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5014 params = 6;
5015 pSMB->MaxSetupCount = 0;
5016 pSMB->Reserved = 0;
5017 pSMB->Flags = 0;
5018 pSMB->Timeout = 0;
5019 pSMB->Reserved2 = 0;
5020 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5021 offset = param_offset + params;
5023 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5025 count = 1;
5026 pSMB->MaxParameterCount = cpu_to_le16(2);
5027 /* BB find max SMB PDU from sess */
5028 pSMB->MaxDataCount = cpu_to_le16(1000);
5029 pSMB->SetupCount = 1;
5030 pSMB->Reserved3 = 0;
5031 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5032 byte_count = 3 /* pad */ + params + count;
5033 pSMB->DataCount = cpu_to_le16(count);
5034 pSMB->ParameterCount = cpu_to_le16(params);
5035 pSMB->TotalDataCount = pSMB->DataCount;
5036 pSMB->TotalParameterCount = pSMB->ParameterCount;
5037 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5038 pSMB->DataOffset = cpu_to_le16(offset);
5039 pSMB->Fid = fid;
5040 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5041 pSMB->Reserved4 = 0;
5042 pSMB->hdr.smb_buf_length += byte_count;
5043 pSMB->ByteCount = cpu_to_le16(byte_count);
5044 *data_offset = delete_file ? 1 : 0;
5045 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5046 if (rc)
5047 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
5049 return rc;
5053 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5054 const char *fileName, const FILE_BASIC_INFO *data,
5055 const struct nls_table *nls_codepage, int remap)
5057 TRANSACTION2_SPI_REQ *pSMB = NULL;
5058 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5059 int name_len;
5060 int rc = 0;
5061 int bytes_returned = 0;
5062 char *data_offset;
5063 __u16 params, param_offset, offset, byte_count, count;
5065 cFYI(1, ("In SetTimes"));
5067 SetTimesRetry:
5068 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5069 (void **) &pSMBr);
5070 if (rc)
5071 return rc;
5073 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5074 name_len =
5075 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5076 PATH_MAX, nls_codepage, remap);
5077 name_len++; /* trailing null */
5078 name_len *= 2;
5079 } else { /* BB improve the check for buffer overruns BB */
5080 name_len = strnlen(fileName, PATH_MAX);
5081 name_len++; /* trailing null */
5082 strncpy(pSMB->FileName, fileName, name_len);
5085 params = 6 + name_len;
5086 count = sizeof(FILE_BASIC_INFO);
5087 pSMB->MaxParameterCount = cpu_to_le16(2);
5088 /* BB find max SMB PDU from sess structure BB */
5089 pSMB->MaxDataCount = cpu_to_le16(1000);
5090 pSMB->MaxSetupCount = 0;
5091 pSMB->Reserved = 0;
5092 pSMB->Flags = 0;
5093 pSMB->Timeout = 0;
5094 pSMB->Reserved2 = 0;
5095 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5096 InformationLevel) - 4;
5097 offset = param_offset + params;
5098 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5099 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5100 pSMB->DataOffset = cpu_to_le16(offset);
5101 pSMB->SetupCount = 1;
5102 pSMB->Reserved3 = 0;
5103 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5104 byte_count = 3 /* pad */ + params + count;
5106 pSMB->DataCount = cpu_to_le16(count);
5107 pSMB->ParameterCount = cpu_to_le16(params);
5108 pSMB->TotalDataCount = pSMB->DataCount;
5109 pSMB->TotalParameterCount = pSMB->ParameterCount;
5110 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5111 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5112 else
5113 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5114 pSMB->Reserved4 = 0;
5115 pSMB->hdr.smb_buf_length += byte_count;
5116 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5117 pSMB->ByteCount = cpu_to_le16(byte_count);
5118 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5120 if (rc)
5121 cFYI(1, ("SetPathInfo (times) returned %d", rc));
5123 cifs_buf_release(pSMB);
5125 if (rc == -EAGAIN)
5126 goto SetTimesRetry;
5128 return rc;
5131 /* Can not be used to set time stamps yet (due to old DOS time format) */
5132 /* Can be used to set attributes */
5133 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5134 handling it anyway and NT4 was what we thought it would be needed for
5135 Do not delete it until we prove whether needed for Win9x though */
5137 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5138 __u16 dos_attrs, const struct nls_table *nls_codepage)
5140 SETATTR_REQ *pSMB = NULL;
5141 SETATTR_RSP *pSMBr = NULL;
5142 int rc = 0;
5143 int bytes_returned;
5144 int name_len;
5146 cFYI(1, ("In SetAttrLegacy"));
5148 SetAttrLgcyRetry:
5149 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5150 (void **) &pSMBr);
5151 if (rc)
5152 return rc;
5154 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5155 name_len =
5156 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
5157 PATH_MAX, nls_codepage);
5158 name_len++; /* trailing null */
5159 name_len *= 2;
5160 } else { /* BB improve the check for buffer overruns BB */
5161 name_len = strnlen(fileName, PATH_MAX);
5162 name_len++; /* trailing null */
5163 strncpy(pSMB->fileName, fileName, name_len);
5165 pSMB->attr = cpu_to_le16(dos_attrs);
5166 pSMB->BufferFormat = 0x04;
5167 pSMB->hdr.smb_buf_length += name_len + 1;
5168 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5169 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5170 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5171 if (rc)
5172 cFYI(1, ("Error in LegacySetAttr = %d", rc));
5174 cifs_buf_release(pSMB);
5176 if (rc == -EAGAIN)
5177 goto SetAttrLgcyRetry;
5179 return rc;
5181 #endif /* temporarily unneeded SetAttr legacy function */
5183 static void
5184 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5185 const struct cifs_unix_set_info_args *args)
5187 u64 mode = args->mode;
5190 * Samba server ignores set of file size to zero due to bugs in some
5191 * older clients, but we should be precise - we use SetFileSize to
5192 * set file size and do not want to truncate file size to zero
5193 * accidently as happened on one Samba server beta by putting
5194 * zero instead of -1 here
5196 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5197 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5198 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5199 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5200 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5201 data_offset->Uid = cpu_to_le64(args->uid);
5202 data_offset->Gid = cpu_to_le64(args->gid);
5203 /* better to leave device as zero when it is */
5204 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5205 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5206 data_offset->Permissions = cpu_to_le64(mode);
5208 if (S_ISREG(mode))
5209 data_offset->Type = cpu_to_le32(UNIX_FILE);
5210 else if (S_ISDIR(mode))
5211 data_offset->Type = cpu_to_le32(UNIX_DIR);
5212 else if (S_ISLNK(mode))
5213 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5214 else if (S_ISCHR(mode))
5215 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5216 else if (S_ISBLK(mode))
5217 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5218 else if (S_ISFIFO(mode))
5219 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5220 else if (S_ISSOCK(mode))
5221 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5225 CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5226 const struct cifs_unix_set_info_args *args,
5227 u16 fid, u32 pid_of_opener)
5229 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5230 FILE_UNIX_BASIC_INFO *data_offset;
5231 int rc = 0;
5232 u16 params, param_offset, offset, byte_count, count;
5234 cFYI(1, ("Set Unix Info (via SetFileInfo)"));
5235 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5237 if (rc)
5238 return rc;
5240 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5241 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5243 params = 6;
5244 pSMB->MaxSetupCount = 0;
5245 pSMB->Reserved = 0;
5246 pSMB->Flags = 0;
5247 pSMB->Timeout = 0;
5248 pSMB->Reserved2 = 0;
5249 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5250 offset = param_offset + params;
5252 data_offset = (FILE_UNIX_BASIC_INFO *)
5253 ((char *)(&pSMB->hdr.Protocol) + offset);
5254 count = sizeof(FILE_UNIX_BASIC_INFO);
5256 pSMB->MaxParameterCount = cpu_to_le16(2);
5257 /* BB find max SMB PDU from sess */
5258 pSMB->MaxDataCount = cpu_to_le16(1000);
5259 pSMB->SetupCount = 1;
5260 pSMB->Reserved3 = 0;
5261 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5262 byte_count = 3 /* pad */ + params + count;
5263 pSMB->DataCount = cpu_to_le16(count);
5264 pSMB->ParameterCount = cpu_to_le16(params);
5265 pSMB->TotalDataCount = pSMB->DataCount;
5266 pSMB->TotalParameterCount = pSMB->ParameterCount;
5267 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5268 pSMB->DataOffset = cpu_to_le16(offset);
5269 pSMB->Fid = fid;
5270 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5271 pSMB->Reserved4 = 0;
5272 pSMB->hdr.smb_buf_length += byte_count;
5273 pSMB->ByteCount = cpu_to_le16(byte_count);
5275 cifs_fill_unix_set_info(data_offset, args);
5277 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5278 if (rc)
5279 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
5281 /* Note: On -EAGAIN error only caller can retry on handle based calls
5282 since file handle passed in no longer valid */
5284 return rc;
5288 CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5289 const struct cifs_unix_set_info_args *args,
5290 const struct nls_table *nls_codepage, int remap)
5292 TRANSACTION2_SPI_REQ *pSMB = NULL;
5293 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5294 int name_len;
5295 int rc = 0;
5296 int bytes_returned = 0;
5297 FILE_UNIX_BASIC_INFO *data_offset;
5298 __u16 params, param_offset, offset, count, byte_count;
5300 cFYI(1, ("In SetUID/GID/Mode"));
5301 setPermsRetry:
5302 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5303 (void **) &pSMBr);
5304 if (rc)
5305 return rc;
5307 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5308 name_len =
5309 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5310 PATH_MAX, nls_codepage, remap);
5311 name_len++; /* trailing null */
5312 name_len *= 2;
5313 } else { /* BB improve the check for buffer overruns BB */
5314 name_len = strnlen(fileName, PATH_MAX);
5315 name_len++; /* trailing null */
5316 strncpy(pSMB->FileName, fileName, name_len);
5319 params = 6 + name_len;
5320 count = sizeof(FILE_UNIX_BASIC_INFO);
5321 pSMB->MaxParameterCount = cpu_to_le16(2);
5322 /* BB find max SMB PDU from sess structure BB */
5323 pSMB->MaxDataCount = cpu_to_le16(1000);
5324 pSMB->MaxSetupCount = 0;
5325 pSMB->Reserved = 0;
5326 pSMB->Flags = 0;
5327 pSMB->Timeout = 0;
5328 pSMB->Reserved2 = 0;
5329 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5330 InformationLevel) - 4;
5331 offset = param_offset + params;
5332 data_offset =
5333 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5334 offset);
5335 memset(data_offset, 0, count);
5336 pSMB->DataOffset = cpu_to_le16(offset);
5337 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5338 pSMB->SetupCount = 1;
5339 pSMB->Reserved3 = 0;
5340 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5341 byte_count = 3 /* pad */ + params + count;
5342 pSMB->ParameterCount = cpu_to_le16(params);
5343 pSMB->DataCount = cpu_to_le16(count);
5344 pSMB->TotalParameterCount = pSMB->ParameterCount;
5345 pSMB->TotalDataCount = pSMB->DataCount;
5346 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5347 pSMB->Reserved4 = 0;
5348 pSMB->hdr.smb_buf_length += byte_count;
5350 cifs_fill_unix_set_info(data_offset, args);
5352 pSMB->ByteCount = cpu_to_le16(byte_count);
5353 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5354 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5355 if (rc)
5356 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5358 cifs_buf_release(pSMB);
5359 if (rc == -EAGAIN)
5360 goto setPermsRetry;
5361 return rc;
5364 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5365 const int notify_subdirs, const __u16 netfid,
5366 __u32 filter, struct file *pfile, int multishot,
5367 const struct nls_table *nls_codepage)
5369 int rc = 0;
5370 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5371 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5372 struct dir_notify_req *dnotify_req;
5373 int bytes_returned;
5375 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5376 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5377 (void **) &pSMBr);
5378 if (rc)
5379 return rc;
5381 pSMB->TotalParameterCount = 0 ;
5382 pSMB->TotalDataCount = 0;
5383 pSMB->MaxParameterCount = cpu_to_le32(2);
5384 /* BB find exact data count max from sess structure BB */
5385 pSMB->MaxDataCount = 0; /* same in little endian or be */
5386 /* BB VERIFY verify which is correct for above BB */
5387 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5388 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5390 pSMB->MaxSetupCount = 4;
5391 pSMB->Reserved = 0;
5392 pSMB->ParameterOffset = 0;
5393 pSMB->DataCount = 0;
5394 pSMB->DataOffset = 0;
5395 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5396 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5397 pSMB->ParameterCount = pSMB->TotalParameterCount;
5398 if (notify_subdirs)
5399 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5400 pSMB->Reserved2 = 0;
5401 pSMB->CompletionFilter = cpu_to_le32(filter);
5402 pSMB->Fid = netfid; /* file handle always le */
5403 pSMB->ByteCount = 0;
5405 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5406 (struct smb_hdr *)pSMBr, &bytes_returned,
5407 CIFS_ASYNC_OP);
5408 if (rc) {
5409 cFYI(1, ("Error in Notify = %d", rc));
5410 } else {
5411 /* Add file to outstanding requests */
5412 /* BB change to kmem cache alloc */
5413 dnotify_req = kmalloc(
5414 sizeof(struct dir_notify_req),
5415 GFP_KERNEL);
5416 if (dnotify_req) {
5417 dnotify_req->Pid = pSMB->hdr.Pid;
5418 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5419 dnotify_req->Mid = pSMB->hdr.Mid;
5420 dnotify_req->Tid = pSMB->hdr.Tid;
5421 dnotify_req->Uid = pSMB->hdr.Uid;
5422 dnotify_req->netfid = netfid;
5423 dnotify_req->pfile = pfile;
5424 dnotify_req->filter = filter;
5425 dnotify_req->multishot = multishot;
5426 spin_lock(&GlobalMid_Lock);
5427 list_add_tail(&dnotify_req->lhead,
5428 &GlobalDnotifyReqList);
5429 spin_unlock(&GlobalMid_Lock);
5430 } else
5431 rc = -ENOMEM;
5433 cifs_buf_release(pSMB);
5434 return rc;
5437 #ifdef CONFIG_CIFS_XATTR
5439 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5440 * function used by listxattr and getxattr type calls. When ea_name is set,
5441 * it looks for that attribute name and stuffs that value into the EAData
5442 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5443 * buffer. In both cases, the return value is either the length of the
5444 * resulting data or a negative error code. If EAData is a NULL pointer then
5445 * the data isn't copied to it, but the length is returned.
5447 ssize_t
5448 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5449 const unsigned char *searchName, const unsigned char *ea_name,
5450 char *EAData, size_t buf_size,
5451 const struct nls_table *nls_codepage, int remap)
5453 /* BB assumes one setup word */
5454 TRANSACTION2_QPI_REQ *pSMB = NULL;
5455 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5456 int rc = 0;
5457 int bytes_returned;
5458 int list_len;
5459 struct fealist *ea_response_data;
5460 struct fea *temp_fea;
5461 char *temp_ptr;
5462 char *end_of_smb;
5463 __u16 params, byte_count, data_offset;
5465 cFYI(1, ("In Query All EAs path %s", searchName));
5466 QAllEAsRetry:
5467 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5468 (void **) &pSMBr);
5469 if (rc)
5470 return rc;
5472 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5473 list_len =
5474 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5475 PATH_MAX, nls_codepage, remap);
5476 list_len++; /* trailing null */
5477 list_len *= 2;
5478 } else { /* BB improve the check for buffer overruns BB */
5479 list_len = strnlen(searchName, PATH_MAX);
5480 list_len++; /* trailing null */
5481 strncpy(pSMB->FileName, searchName, list_len);
5484 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
5485 pSMB->TotalDataCount = 0;
5486 pSMB->MaxParameterCount = cpu_to_le16(2);
5487 /* BB find exact max SMB PDU from sess structure BB */
5488 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
5489 pSMB->MaxSetupCount = 0;
5490 pSMB->Reserved = 0;
5491 pSMB->Flags = 0;
5492 pSMB->Timeout = 0;
5493 pSMB->Reserved2 = 0;
5494 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5495 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5496 pSMB->DataCount = 0;
5497 pSMB->DataOffset = 0;
5498 pSMB->SetupCount = 1;
5499 pSMB->Reserved3 = 0;
5500 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5501 byte_count = params + 1 /* pad */ ;
5502 pSMB->TotalParameterCount = cpu_to_le16(params);
5503 pSMB->ParameterCount = pSMB->TotalParameterCount;
5504 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5505 pSMB->Reserved4 = 0;
5506 pSMB->hdr.smb_buf_length += byte_count;
5507 pSMB->ByteCount = cpu_to_le16(byte_count);
5509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5510 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5511 if (rc) {
5512 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5513 goto QAllEAsOut;
5517 /* BB also check enough total bytes returned */
5518 /* BB we need to improve the validity checking
5519 of these trans2 responses */
5521 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5522 if (rc || (pSMBr->ByteCount < 4)) {
5523 rc = -EIO; /* bad smb */
5524 goto QAllEAsOut;
5527 /* check that length of list is not more than bcc */
5528 /* check that each entry does not go beyond length
5529 of list */
5530 /* check that each element of each entry does not
5531 go beyond end of list */
5532 /* validate_trans2_offsets() */
5533 /* BB check if start of smb + data_offset > &bcc+ bcc */
5535 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5536 ea_response_data = (struct fealist *)
5537 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5539 list_len = le32_to_cpu(ea_response_data->list_len);
5540 cFYI(1, ("ea length %d", list_len));
5541 if (list_len <= 8) {
5542 cFYI(1, ("empty EA list returned from server"));
5543 goto QAllEAsOut;
5546 /* make sure list_len doesn't go past end of SMB */
5547 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5548 if ((char *)ea_response_data + list_len > end_of_smb) {
5549 cFYI(1, ("EA list appears to go beyond SMB"));
5550 rc = -EIO;
5551 goto QAllEAsOut;
5554 /* account for ea list len */
5555 list_len -= 4;
5556 temp_fea = ea_response_data->list;
5557 temp_ptr = (char *)temp_fea;
5558 while (list_len > 0) {
5559 unsigned int name_len;
5560 __u16 value_len;
5562 list_len -= 4;
5563 temp_ptr += 4;
5564 /* make sure we can read name_len and value_len */
5565 if (list_len < 0) {
5566 cFYI(1, ("EA entry goes beyond length of list"));
5567 rc = -EIO;
5568 goto QAllEAsOut;
5571 name_len = temp_fea->name_len;
5572 value_len = le16_to_cpu(temp_fea->value_len);
5573 list_len -= name_len + 1 + value_len;
5574 if (list_len < 0) {
5575 cFYI(1, ("EA entry goes beyond length of list"));
5576 rc = -EIO;
5577 goto QAllEAsOut;
5580 if (ea_name) {
5581 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5582 temp_ptr += name_len + 1;
5583 rc = value_len;
5584 if (buf_size == 0)
5585 goto QAllEAsOut;
5586 if ((size_t)value_len > buf_size) {
5587 rc = -ERANGE;
5588 goto QAllEAsOut;
5590 memcpy(EAData, temp_ptr, value_len);
5591 goto QAllEAsOut;
5593 } else {
5594 /* account for prefix user. and trailing null */
5595 rc += (5 + 1 + name_len);
5596 if (rc < (int) buf_size) {
5597 memcpy(EAData, "user.", 5);
5598 EAData += 5;
5599 memcpy(EAData, temp_ptr, name_len);
5600 EAData += name_len;
5601 /* null terminate name */
5602 *EAData = 0;
5603 ++EAData;
5604 } else if (buf_size == 0) {
5605 /* skip copy - calc size only */
5606 } else {
5607 /* stop before overrun buffer */
5608 rc = -ERANGE;
5609 break;
5612 temp_ptr += name_len + 1 + value_len;
5613 temp_fea = (struct fea *)temp_ptr;
5616 /* didn't find the named attribute */
5617 if (ea_name)
5618 rc = -ENODATA;
5620 QAllEAsOut:
5621 cifs_buf_release(pSMB);
5622 if (rc == -EAGAIN)
5623 goto QAllEAsRetry;
5625 return (ssize_t)rc;
5629 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5630 const char *ea_name, const void *ea_value,
5631 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5632 int remap)
5634 struct smb_com_transaction2_spi_req *pSMB = NULL;
5635 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5636 struct fealist *parm_data;
5637 int name_len;
5638 int rc = 0;
5639 int bytes_returned = 0;
5640 __u16 params, param_offset, byte_count, offset, count;
5642 cFYI(1, ("In SetEA"));
5643 SetEARetry:
5644 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5645 (void **) &pSMBr);
5646 if (rc)
5647 return rc;
5649 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5650 name_len =
5651 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5652 PATH_MAX, nls_codepage, remap);
5653 name_len++; /* trailing null */
5654 name_len *= 2;
5655 } else { /* BB improve the check for buffer overruns BB */
5656 name_len = strnlen(fileName, PATH_MAX);
5657 name_len++; /* trailing null */
5658 strncpy(pSMB->FileName, fileName, name_len);
5661 params = 6 + name_len;
5663 /* done calculating parms using name_len of file name,
5664 now use name_len to calculate length of ea name
5665 we are going to create in the inode xattrs */
5666 if (ea_name == NULL)
5667 name_len = 0;
5668 else
5669 name_len = strnlen(ea_name, 255);
5671 count = sizeof(*parm_data) + ea_value_len + name_len;
5672 pSMB->MaxParameterCount = cpu_to_le16(2);
5673 /* BB find max SMB PDU from sess */
5674 pSMB->MaxDataCount = cpu_to_le16(1000);
5675 pSMB->MaxSetupCount = 0;
5676 pSMB->Reserved = 0;
5677 pSMB->Flags = 0;
5678 pSMB->Timeout = 0;
5679 pSMB->Reserved2 = 0;
5680 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5681 InformationLevel) - 4;
5682 offset = param_offset + params;
5683 pSMB->InformationLevel =
5684 cpu_to_le16(SMB_SET_FILE_EA);
5686 parm_data =
5687 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5688 offset);
5689 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5690 pSMB->DataOffset = cpu_to_le16(offset);
5691 pSMB->SetupCount = 1;
5692 pSMB->Reserved3 = 0;
5693 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5694 byte_count = 3 /* pad */ + params + count;
5695 pSMB->DataCount = cpu_to_le16(count);
5696 parm_data->list_len = cpu_to_le32(count);
5697 parm_data->list[0].EA_flags = 0;
5698 /* we checked above that name len is less than 255 */
5699 parm_data->list[0].name_len = (__u8)name_len;
5700 /* EA names are always ASCII */
5701 if (ea_name)
5702 strncpy(parm_data->list[0].name, ea_name, name_len);
5703 parm_data->list[0].name[name_len] = 0;
5704 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5705 /* caller ensures that ea_value_len is less than 64K but
5706 we need to ensure that it fits within the smb */
5708 /*BB add length check to see if it would fit in
5709 negotiated SMB buffer size BB */
5710 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5711 if (ea_value_len)
5712 memcpy(parm_data->list[0].name+name_len+1,
5713 ea_value, ea_value_len);
5715 pSMB->TotalDataCount = pSMB->DataCount;
5716 pSMB->ParameterCount = cpu_to_le16(params);
5717 pSMB->TotalParameterCount = pSMB->ParameterCount;
5718 pSMB->Reserved4 = 0;
5719 pSMB->hdr.smb_buf_length += byte_count;
5720 pSMB->ByteCount = cpu_to_le16(byte_count);
5721 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5722 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5723 if (rc)
5724 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5726 cifs_buf_release(pSMB);
5728 if (rc == -EAGAIN)
5729 goto SetEARetry;
5731 return rc;
5734 #endif