GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / fs / cifs / cifssmb.c
blob399362b2d8476bf5ad7cc2a7ad575f0f75e10b14
1 /*
2 * fs/cifs/cifssmb.c
4 * Copyright (C) International Business Machines Corp., 2002,2010
5 * Author(s): Steve French (sfrench@us.ibm.com)
7 * Contains the routines for constructing the SMB PDUs themselves
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
27 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/slab.h>
34 #include <linux/posix_acl_xattr.h>
35 #include <asm/uaccess.h>
36 #include "cifspdu.h"
37 #include "cifsglob.h"
38 #include "cifsacl.h"
39 #include "cifsproto.h"
40 #include "cifs_unicode.h"
41 #include "cifs_debug.h"
43 #ifdef CONFIG_CIFS_POSIX
44 static struct {
45 int index;
46 char *name;
47 } protocols[] = {
48 #ifdef CONFIG_CIFS_WEAK_PW_HASH
49 {LANMAN_PROT, "\2LM1.2X002"},
50 {LANMAN2_PROT, "\2LANMAN2.1"},
51 #endif /* weak password hashing for legacy clients */
52 {CIFS_PROT, "\2NT LM 0.12"},
53 {POSIX_PROT, "\2POSIX 2"},
54 {BAD_PROT, "\2"}
56 #else
57 static struct {
58 int index;
59 char *name;
60 } protocols[] = {
61 #ifdef CONFIG_CIFS_WEAK_PW_HASH
62 {LANMAN_PROT, "\2LM1.2X002"},
63 {LANMAN2_PROT, "\2LANMAN2.1"},
64 #endif /* weak password hashing for legacy clients */
65 {CIFS_PROT, "\2NT LM 0.12"},
66 {BAD_PROT, "\2"}
68 #endif
70 /* define the number of elements in the cifs dialect array */
71 #ifdef CONFIG_CIFS_POSIX
72 #ifdef CONFIG_CIFS_WEAK_PW_HASH
73 #define CIFS_NUM_PROT 4
74 #else
75 #define CIFS_NUM_PROT 2
76 #endif /* CIFS_WEAK_PW_HASH */
77 #else /* not posix */
78 #ifdef CONFIG_CIFS_WEAK_PW_HASH
79 #define CIFS_NUM_PROT 3
80 #else
81 #define CIFS_NUM_PROT 1
82 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
83 #endif /* CIFS_POSIX */
85 /* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
87 static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
89 struct cifsFileInfo *open_file = NULL;
90 struct list_head *tmp;
91 struct list_head *tmp1;
93 /* list all files open on tree connection and mark them invalid */
94 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 rc = cifs_negotiate_protocol(0, ses);
176 if (rc == 0 && ses->need_reconnect)
177 rc = cifs_setup_session(0, ses, nls_codepage);
179 /* do we need to reconnect tcon? */
180 if (rc || !tcon->need_reconnect) {
181 mutex_unlock(&ses->session_mutex);
182 goto out;
185 mark_open_files_invalid(tcon);
186 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
187 mutex_unlock(&ses->session_mutex);
188 cFYI(1, "reconnect tcon rc = %d", rc);
190 if (rc)
191 goto out;
193 atomic_inc(&tconInfoReconnectCount);
195 /* tell server Unix caps we support */
196 if (ses->capabilities & CAP_UNIX)
197 reset_cifs_unix_caps(0, tcon, NULL, NULL);
200 out:
202 * Check if handle based operation so we know whether we can continue
203 * or not without returning to caller to reset file handle
205 switch (smb_command) {
206 case SMB_COM_READ_ANDX:
207 case SMB_COM_WRITE_ANDX:
208 case SMB_COM_CLOSE:
209 case SMB_COM_FIND_CLOSE2:
210 case SMB_COM_LOCKING_ANDX:
211 rc = -EAGAIN;
214 unload_nls(nls_codepage);
215 return rc;
218 /* Allocate and return pointer to an SMB request buffer, and set basic
219 SMB information in the SMB header. If the return code is zero, this
220 function must have filled in request_buf pointer */
221 static int
222 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
223 void **request_buf)
225 int rc;
227 rc = cifs_reconnect_tcon(tcon, smb_command);
228 if (rc)
229 return rc;
231 *request_buf = cifs_small_buf_get();
232 if (*request_buf == NULL) {
233 /* BB should we add a retry in here if not a writepage? */
234 return -ENOMEM;
237 header_assemble((struct smb_hdr *) *request_buf, smb_command,
238 tcon, wct);
240 if (tcon != NULL)
241 cifs_stats_inc(&tcon->num_smbs_sent);
243 return 0;
247 small_smb_init_no_tc(const int smb_command, const int wct,
248 struct cifsSesInfo *ses, void **request_buf)
250 int rc;
251 struct smb_hdr *buffer;
253 rc = small_smb_init(smb_command, wct, NULL, request_buf);
254 if (rc)
255 return rc;
257 buffer = (struct smb_hdr *)*request_buf;
258 buffer->Mid = GetNextMid(ses->server);
259 if (ses->capabilities & CAP_UNICODE)
260 buffer->Flags2 |= SMBFLG2_UNICODE;
261 if (ses->capabilities & CAP_STATUS32)
262 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
264 /* uid, tid can stay at zero as set in header assemble */
266 /* BB add support for turning on the signing when
267 this function is used after 1st of session setup requests */
269 return rc;
272 /* If the return code is zero, this function must fill in request_buf pointer */
273 static int
274 __smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
275 void **request_buf, void **response_buf)
277 *request_buf = cifs_buf_get();
278 if (*request_buf == NULL) {
279 /* BB should we add a retry in here if not a writepage? */
280 return -ENOMEM;
282 /* Although the original thought was we needed the response buf for */
283 /* potential retries of smb operations it turns out we can determine */
284 /* from the mid flags when the request buffer can be resent without */
285 /* having to use a second distinct buffer for the response */
286 if (response_buf)
287 *response_buf = *request_buf;
289 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
290 wct);
292 if (tcon != NULL)
293 cifs_stats_inc(&tcon->num_smbs_sent);
295 return 0;
298 /* If the return code is zero, this function must fill in request_buf pointer */
299 static int
300 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
301 void **request_buf, void **response_buf)
303 int rc;
305 rc = cifs_reconnect_tcon(tcon, smb_command);
306 if (rc)
307 return rc;
309 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
312 static int
313 smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
314 void **request_buf, void **response_buf)
316 if (tcon->ses->need_reconnect || tcon->need_reconnect)
317 return -EHOSTDOWN;
319 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
322 static int validate_t2(struct smb_t2_rsp *pSMB)
324 int rc = -EINVAL;
325 int total_size;
326 char *pBCC;
328 /* check for plausible wct, bcc and t2 data and parm sizes */
329 /* check for parm and data offset going beyond end of smb */
330 if (pSMB->hdr.WordCount >= 10) {
331 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
332 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
333 /* check that bcc is at least as big as parms + data */
334 /* check that bcc is less than negotiated smb buffer */
335 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
336 if (total_size < 512) {
337 total_size +=
338 le16_to_cpu(pSMB->t2_rsp.DataCount);
339 /* BCC le converted in SendReceive */
340 pBCC = (pSMB->hdr.WordCount * 2) +
341 sizeof(struct smb_hdr) +
342 (char *)pSMB;
343 if ((total_size <= (*(u16 *)pBCC)) &&
344 (total_size <
345 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
346 return 0;
351 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
352 sizeof(struct smb_t2_rsp) + 16);
353 return rc;
356 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
358 NEGOTIATE_REQ *pSMB;
359 NEGOTIATE_RSP *pSMBr;
360 int rc = 0;
361 int bytes_returned;
362 int i;
363 struct TCP_Server_Info *server;
364 u16 count;
365 unsigned int secFlags;
367 if (ses->server)
368 server = ses->server;
369 else {
370 rc = -EIO;
371 return rc;
373 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
374 (void **) &pSMB, (void **) &pSMBr);
375 if (rc)
376 return rc;
378 /* if any of auth flags (ie not sign or seal) are overriden use them */
379 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
380 secFlags = ses->overrideSecFlg;
381 else /* if override flags set only sign/seal OR them with global auth */
382 secFlags = global_secflags | ses->overrideSecFlg;
384 cFYI(1, "secFlags 0x%x", secFlags);
386 pSMB->hdr.Mid = GetNextMid(server);
387 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
389 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
390 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
391 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
392 cFYI(1, "Kerberos only mechanism, enable extended security");
393 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
395 #ifdef CONFIG_CIFS_EXPERIMENTAL
396 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
397 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
398 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
399 cFYI(1, "NTLMSSP only mechanism, enable extended security");
400 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
402 #endif
404 count = 0;
405 for (i = 0; i < CIFS_NUM_PROT; i++) {
406 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
407 count += strlen(protocols[i].name) + 1;
408 /* null at end of source and target buffers anyway */
410 pSMB->hdr.smb_buf_length += count;
411 pSMB->ByteCount = cpu_to_le16(count);
413 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
414 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
415 if (rc != 0)
416 goto neg_err_exit;
418 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
419 cFYI(1, "Dialect: %d", server->dialect);
420 /* Check wct = 1 error case */
421 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
422 /* core returns wct = 1, but we do not ask for core - otherwise
423 small wct just comes when dialect index is -1 indicating we
424 could not negotiate a common dialect */
425 rc = -EOPNOTSUPP;
426 goto neg_err_exit;
427 #ifdef CONFIG_CIFS_WEAK_PW_HASH
428 } else if ((pSMBr->hdr.WordCount == 13)
429 && ((server->dialect == LANMAN_PROT)
430 || (server->dialect == LANMAN2_PROT))) {
431 __s16 tmp;
432 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
434 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
435 (secFlags & CIFSSEC_MAY_PLNTXT))
436 server->secType = LANMAN;
437 else {
438 cERROR(1, "mount failed weak security disabled"
439 " in /proc/fs/cifs/SecurityFlags");
440 rc = -EOPNOTSUPP;
441 goto neg_err_exit;
443 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
444 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
445 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
446 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
447 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
448 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
449 /* even though we do not use raw we might as well set this
450 accurately, in case we ever find a need for it */
451 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
452 server->max_rw = 0xFF00;
453 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
454 } else {
455 server->max_rw = 0;/* do not need to use raw anyway */
456 server->capabilities = CAP_MPX_MODE;
458 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
459 if (tmp == -1) {
460 /* OS/2 often does not set timezone therefore
461 * we must use server time to calc time zone.
462 * Could deviate slightly from the right zone.
463 * Smallest defined timezone difference is 15 minutes
464 * (i.e. Nepal). Rounding up/down is done to match
465 * this requirement.
467 int val, seconds, remain, result;
468 struct timespec ts, utc;
469 utc = CURRENT_TIME;
470 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
471 rsp->SrvTime.Time, 0);
472 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
473 (int)ts.tv_sec, (int)utc.tv_sec,
474 (int)(utc.tv_sec - ts.tv_sec));
475 val = (int)(utc.tv_sec - ts.tv_sec);
476 seconds = abs(val);
477 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
478 remain = seconds % MIN_TZ_ADJ;
479 if (remain >= (MIN_TZ_ADJ / 2))
480 result += MIN_TZ_ADJ;
481 if (val < 0)
482 result = -result;
483 server->timeAdj = result;
484 } else {
485 server->timeAdj = (int)tmp;
486 server->timeAdj *= 60; /* also in seconds */
488 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
491 /* BB get server time for time conversions and add
492 code to use it and timezone since this is not UTC */
494 if (rsp->EncryptionKeyLength ==
495 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
496 memcpy(server->cryptKey, rsp->EncryptionKey,
497 CIFS_CRYPTO_KEY_SIZE);
498 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
499 rc = -EIO; /* need cryptkey unless plain text */
500 goto neg_err_exit;
503 cFYI(1, "LANMAN negotiated");
504 /* we will not end up setting signing flags - as no signing
505 was in LANMAN and server did not return the flags on */
506 goto signing_check;
507 #else /* weak security disabled */
508 } else if (pSMBr->hdr.WordCount == 13) {
509 cERROR(1, "mount failed, cifs module not built "
510 "with CIFS_WEAK_PW_HASH support");
511 rc = -EOPNOTSUPP;
512 #endif /* WEAK_PW_HASH */
513 goto neg_err_exit;
514 } else if (pSMBr->hdr.WordCount != 17) {
515 /* unknown wct */
516 rc = -EOPNOTSUPP;
517 goto neg_err_exit;
519 /* else wct == 17 NTLM */
520 server->secMode = pSMBr->SecurityMode;
521 if ((server->secMode & SECMODE_USER) == 0)
522 cFYI(1, "share mode security");
524 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
525 #ifdef CONFIG_CIFS_WEAK_PW_HASH
526 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
527 #endif /* CIFS_WEAK_PW_HASH */
528 cERROR(1, "Server requests plain text password"
529 " but client support disabled");
531 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
532 server->secType = NTLMv2;
533 else if (secFlags & CIFSSEC_MAY_NTLM)
534 server->secType = NTLM;
535 else if (secFlags & CIFSSEC_MAY_NTLMV2)
536 server->secType = NTLMv2;
537 else if (secFlags & CIFSSEC_MAY_KRB5)
538 server->secType = Kerberos;
539 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
540 server->secType = RawNTLMSSP;
541 else if (secFlags & CIFSSEC_MAY_LANMAN)
542 server->secType = LANMAN;
543 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
544 else if (secFlags & CIFSSEC_MAY_PLNTXT)
545 server->secType = ??
546 #endif */
547 else {
548 rc = -EOPNOTSUPP;
549 cERROR(1, "Invalid security type");
550 goto neg_err_exit;
552 /* else ... any others ...? */
554 /* one byte, so no need to convert this or EncryptionKeyLen from
555 little endian */
556 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
557 /* probably no need to store and check maxvcs */
558 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
559 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
560 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
561 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
562 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
563 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
564 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
565 server->timeAdj *= 60;
566 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
567 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
568 CIFS_CRYPTO_KEY_SIZE);
569 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
570 && (pSMBr->EncryptionKeyLength == 0)) {
571 /* decode security blob */
572 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
573 rc = -EIO; /* no crypt key only if plain text pwd */
574 goto neg_err_exit;
577 /* BB might be helpful to save off the domain of server here */
579 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
580 (server->capabilities & CAP_EXTENDED_SECURITY)) {
581 count = pSMBr->ByteCount;
582 if (count < 16) {
583 rc = -EIO;
584 goto neg_err_exit;
586 read_lock(&cifs_tcp_ses_lock);
587 if (server->srv_count > 1) {
588 read_unlock(&cifs_tcp_ses_lock);
589 if (memcmp(server->server_GUID,
590 pSMBr->u.extended_response.
591 GUID, 16) != 0) {
592 cFYI(1, "server UID changed");
593 memcpy(server->server_GUID,
594 pSMBr->u.extended_response.GUID,
595 16);
597 } else {
598 read_unlock(&cifs_tcp_ses_lock);
599 memcpy(server->server_GUID,
600 pSMBr->u.extended_response.GUID, 16);
603 if (count == 16) {
604 server->secType = RawNTLMSSP;
605 } else {
606 rc = decode_negTokenInit(pSMBr->u.extended_response.
607 SecurityBlob, count - 16,
608 server);
609 if (rc == 1)
610 rc = 0;
611 else
612 rc = -EINVAL;
614 if (server->sec_kerberos || server->sec_mskerberos)
615 server->secType = Kerberos;
616 else if (server->sec_ntlmssp)
617 server->secType = RawNTLMSSP;
618 else
619 rc = -EOPNOTSUPP;
621 } else
622 server->capabilities &= ~CAP_EXTENDED_SECURITY;
624 #ifdef CONFIG_CIFS_WEAK_PW_HASH
625 signing_check:
626 #endif
627 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
628 /* MUST_SIGN already includes the MAY_SIGN FLAG
629 so if this is zero it means that signing is disabled */
630 cFYI(1, "Signing disabled");
631 if (server->secMode & SECMODE_SIGN_REQUIRED) {
632 cERROR(1, "Server requires "
633 "packet signing to be enabled in "
634 "/proc/fs/cifs/SecurityFlags.");
635 rc = -EOPNOTSUPP;
637 server->secMode &=
638 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
639 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
640 /* signing required */
641 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
642 if ((server->secMode &
643 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
644 cERROR(1, "signing required but server lacks support");
645 rc = -EOPNOTSUPP;
646 } else
647 server->secMode |= SECMODE_SIGN_REQUIRED;
648 } else {
649 /* signing optional ie CIFSSEC_MAY_SIGN */
650 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
651 server->secMode &=
652 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
655 neg_err_exit:
656 cifs_buf_release(pSMB);
658 cFYI(1, "negprot rc %d", rc);
659 return rc;
663 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
665 struct smb_hdr *smb_buffer;
666 int rc = 0;
668 cFYI(1, "In tree disconnect");
670 /* BB: do we need to check this? These should never be NULL. */
671 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
672 return -EIO;
675 * No need to return error on this operation if tid invalidated and
676 * closed on server already e.g. due to tcp session crashing. Also,
677 * the tcon is no longer on the list, so no need to take lock before
678 * checking this.
680 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
681 return 0;
683 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
684 (void **)&smb_buffer);
685 if (rc)
686 return rc;
688 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
689 if (rc)
690 cFYI(1, "Tree disconnect failed %d", rc);
692 /* No need to return error on this operation if tid invalidated and
693 closed on server already e.g. due to tcp session crashing */
694 if (rc == -EAGAIN)
695 rc = 0;
697 return rc;
701 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
703 LOGOFF_ANDX_REQ *pSMB;
704 int rc = 0;
706 cFYI(1, "In SMBLogoff for session disconnect");
709 * BB: do we need to check validity of ses and server? They should
710 * always be valid since we have an active reference. If not, that
711 * should probably be a BUG()
713 if (!ses || !ses->server)
714 return -EIO;
716 mutex_lock(&ses->session_mutex);
717 if (ses->need_reconnect)
718 goto session_already_dead; /* no need to send SMBlogoff if uid
719 already closed due to reconnect */
720 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
721 if (rc) {
722 mutex_unlock(&ses->session_mutex);
723 return rc;
726 pSMB->hdr.Mid = GetNextMid(ses->server);
728 if (ses->server->secMode &
729 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
730 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
732 pSMB->hdr.Uid = ses->Suid;
734 pSMB->AndXCommand = 0xFF;
735 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
736 session_already_dead:
737 mutex_unlock(&ses->session_mutex);
739 /* if session dead then we do not need to do ulogoff,
740 since server closed smb session, no sense reporting
741 error */
742 if (rc == -EAGAIN)
743 rc = 0;
744 return rc;
748 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
749 __u16 type, const struct nls_table *nls_codepage, int remap)
751 TRANSACTION2_SPI_REQ *pSMB = NULL;
752 TRANSACTION2_SPI_RSP *pSMBr = NULL;
753 struct unlink_psx_rq *pRqD;
754 int name_len;
755 int rc = 0;
756 int bytes_returned = 0;
757 __u16 params, param_offset, offset, byte_count;
759 cFYI(1, "In POSIX delete");
760 PsxDelete:
761 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
762 (void **) &pSMBr);
763 if (rc)
764 return rc;
766 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
767 name_len =
768 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
769 PATH_MAX, nls_codepage, remap);
770 name_len++; /* trailing null */
771 name_len *= 2;
772 } else { /* BB add path length overrun check */
773 name_len = strnlen(fileName, PATH_MAX);
774 name_len++; /* trailing null */
775 strncpy(pSMB->FileName, fileName, name_len);
778 params = 6 + name_len;
779 pSMB->MaxParameterCount = cpu_to_le16(2);
780 pSMB->MaxDataCount = 0; /* BB double check this with jra */
781 pSMB->MaxSetupCount = 0;
782 pSMB->Reserved = 0;
783 pSMB->Flags = 0;
784 pSMB->Timeout = 0;
785 pSMB->Reserved2 = 0;
786 param_offset = offsetof(struct smb_com_transaction2_spi_req,
787 InformationLevel) - 4;
788 offset = param_offset + params;
790 /* Setup pointer to Request Data (inode type) */
791 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
792 pRqD->type = cpu_to_le16(type);
793 pSMB->ParameterOffset = cpu_to_le16(param_offset);
794 pSMB->DataOffset = cpu_to_le16(offset);
795 pSMB->SetupCount = 1;
796 pSMB->Reserved3 = 0;
797 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
798 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
800 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
801 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
802 pSMB->ParameterCount = cpu_to_le16(params);
803 pSMB->TotalParameterCount = pSMB->ParameterCount;
804 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
805 pSMB->Reserved4 = 0;
806 pSMB->hdr.smb_buf_length += byte_count;
807 pSMB->ByteCount = cpu_to_le16(byte_count);
808 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
809 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
810 if (rc)
811 cFYI(1, "Posix delete returned %d", rc);
812 cifs_buf_release(pSMB);
814 cifs_stats_inc(&tcon->num_deletes);
816 if (rc == -EAGAIN)
817 goto PsxDelete;
819 return rc;
823 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
824 const struct nls_table *nls_codepage, int remap)
826 DELETE_FILE_REQ *pSMB = NULL;
827 DELETE_FILE_RSP *pSMBr = NULL;
828 int rc = 0;
829 int bytes_returned;
830 int name_len;
832 DelFileRetry:
833 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
834 (void **) &pSMBr);
835 if (rc)
836 return rc;
838 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
839 name_len =
840 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
841 PATH_MAX, nls_codepage, remap);
842 name_len++; /* trailing null */
843 name_len *= 2;
844 } else { /* BB improve check for buffer overruns BB */
845 name_len = strnlen(fileName, PATH_MAX);
846 name_len++; /* trailing null */
847 strncpy(pSMB->fileName, fileName, name_len);
849 pSMB->SearchAttributes =
850 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
851 pSMB->BufferFormat = 0x04;
852 pSMB->hdr.smb_buf_length += name_len + 1;
853 pSMB->ByteCount = cpu_to_le16(name_len + 1);
854 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
855 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
856 cifs_stats_inc(&tcon->num_deletes);
857 if (rc)
858 cFYI(1, "Error in RMFile = %d", rc);
860 cifs_buf_release(pSMB);
861 if (rc == -EAGAIN)
862 goto DelFileRetry;
864 return rc;
868 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
869 const struct nls_table *nls_codepage, int remap)
871 DELETE_DIRECTORY_REQ *pSMB = NULL;
872 DELETE_DIRECTORY_RSP *pSMBr = NULL;
873 int rc = 0;
874 int bytes_returned;
875 int name_len;
877 cFYI(1, "In CIFSSMBRmDir");
878 RmDirRetry:
879 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
880 (void **) &pSMBr);
881 if (rc)
882 return rc;
884 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
885 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
886 PATH_MAX, nls_codepage, remap);
887 name_len++; /* trailing null */
888 name_len *= 2;
889 } else { /* BB improve check for buffer overruns BB */
890 name_len = strnlen(dirName, PATH_MAX);
891 name_len++; /* trailing null */
892 strncpy(pSMB->DirName, dirName, name_len);
895 pSMB->BufferFormat = 0x04;
896 pSMB->hdr.smb_buf_length += name_len + 1;
897 pSMB->ByteCount = cpu_to_le16(name_len + 1);
898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
899 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
900 cifs_stats_inc(&tcon->num_rmdirs);
901 if (rc)
902 cFYI(1, "Error in RMDir = %d", rc);
904 cifs_buf_release(pSMB);
905 if (rc == -EAGAIN)
906 goto RmDirRetry;
907 return rc;
911 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
912 const char *name, const struct nls_table *nls_codepage, int remap)
914 int rc = 0;
915 CREATE_DIRECTORY_REQ *pSMB = NULL;
916 CREATE_DIRECTORY_RSP *pSMBr = NULL;
917 int bytes_returned;
918 int name_len;
920 cFYI(1, "In CIFSSMBMkDir");
921 MkDirRetry:
922 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
923 (void **) &pSMBr);
924 if (rc)
925 return rc;
927 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
928 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
929 PATH_MAX, nls_codepage, remap);
930 name_len++; /* trailing null */
931 name_len *= 2;
932 } else { /* BB improve check for buffer overruns BB */
933 name_len = strnlen(name, PATH_MAX);
934 name_len++; /* trailing null */
935 strncpy(pSMB->DirName, name, name_len);
938 pSMB->BufferFormat = 0x04;
939 pSMB->hdr.smb_buf_length += name_len + 1;
940 pSMB->ByteCount = cpu_to_le16(name_len + 1);
941 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
942 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
943 cifs_stats_inc(&tcon->num_mkdirs);
944 if (rc)
945 cFYI(1, "Error in Mkdir = %d", rc);
947 cifs_buf_release(pSMB);
948 if (rc == -EAGAIN)
949 goto MkDirRetry;
950 return rc;
954 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
955 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
956 __u32 *pOplock, const char *name,
957 const struct nls_table *nls_codepage, int remap)
959 TRANSACTION2_SPI_REQ *pSMB = NULL;
960 TRANSACTION2_SPI_RSP *pSMBr = NULL;
961 int name_len;
962 int rc = 0;
963 int bytes_returned = 0;
964 __u16 params, param_offset, offset, byte_count, count;
965 OPEN_PSX_REQ *pdata;
966 OPEN_PSX_RSP *psx_rsp;
968 cFYI(1, "In POSIX Create");
969 PsxCreat:
970 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
971 (void **) &pSMBr);
972 if (rc)
973 return rc;
975 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
976 name_len =
977 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
978 PATH_MAX, nls_codepage, remap);
979 name_len++; /* trailing null */
980 name_len *= 2;
981 } else { /* BB improve the check for buffer overruns BB */
982 name_len = strnlen(name, PATH_MAX);
983 name_len++; /* trailing null */
984 strncpy(pSMB->FileName, name, name_len);
987 params = 6 + name_len;
988 count = sizeof(OPEN_PSX_REQ);
989 pSMB->MaxParameterCount = cpu_to_le16(2);
990 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
991 pSMB->MaxSetupCount = 0;
992 pSMB->Reserved = 0;
993 pSMB->Flags = 0;
994 pSMB->Timeout = 0;
995 pSMB->Reserved2 = 0;
996 param_offset = offsetof(struct smb_com_transaction2_spi_req,
997 InformationLevel) - 4;
998 offset = param_offset + params;
999 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1000 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1001 pdata->Permissions = cpu_to_le64(mode);
1002 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1003 pdata->OpenFlags = cpu_to_le32(*pOplock);
1004 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1005 pSMB->DataOffset = cpu_to_le16(offset);
1006 pSMB->SetupCount = 1;
1007 pSMB->Reserved3 = 0;
1008 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1009 byte_count = 3 /* pad */ + params + count;
1011 pSMB->DataCount = cpu_to_le16(count);
1012 pSMB->ParameterCount = cpu_to_le16(params);
1013 pSMB->TotalDataCount = pSMB->DataCount;
1014 pSMB->TotalParameterCount = pSMB->ParameterCount;
1015 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1016 pSMB->Reserved4 = 0;
1017 pSMB->hdr.smb_buf_length += byte_count;
1018 pSMB->ByteCount = cpu_to_le16(byte_count);
1019 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1020 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1021 if (rc) {
1022 cFYI(1, "Posix create returned %d", rc);
1023 goto psx_create_err;
1026 cFYI(1, "copying inode info");
1027 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1029 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1030 rc = -EIO; /* bad smb */
1031 goto psx_create_err;
1034 /* copy return information to pRetData */
1035 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1036 + le16_to_cpu(pSMBr->t2.DataOffset));
1038 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1039 if (netfid)
1040 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1041 /* Let caller know file was created so we can set the mode. */
1042 /* Do we care about the CreateAction in any other cases? */
1043 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1044 *pOplock |= CIFS_CREATE_ACTION;
1045 /* check to make sure response data is there */
1046 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1047 pRetData->Type = cpu_to_le32(-1); /* unknown */
1048 cFYI(DBG2, "unknown type");
1049 } else {
1050 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1051 + sizeof(FILE_UNIX_BASIC_INFO)) {
1052 cERROR(1, "Open response data too small");
1053 pRetData->Type = cpu_to_le32(-1);
1054 goto psx_create_err;
1056 memcpy((char *) pRetData,
1057 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1058 sizeof(FILE_UNIX_BASIC_INFO));
1061 psx_create_err:
1062 cifs_buf_release(pSMB);
1064 if (posix_flags & SMB_O_DIRECTORY)
1065 cifs_stats_inc(&tcon->num_posixmkdirs);
1066 else
1067 cifs_stats_inc(&tcon->num_posixopens);
1069 if (rc == -EAGAIN)
1070 goto PsxCreat;
1072 return rc;
1075 static __u16 convert_disposition(int disposition)
1077 __u16 ofun = 0;
1079 switch (disposition) {
1080 case FILE_SUPERSEDE:
1081 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1082 break;
1083 case FILE_OPEN:
1084 ofun = SMBOPEN_OAPPEND;
1085 break;
1086 case FILE_CREATE:
1087 ofun = SMBOPEN_OCREATE;
1088 break;
1089 case FILE_OPEN_IF:
1090 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1091 break;
1092 case FILE_OVERWRITE:
1093 ofun = SMBOPEN_OTRUNC;
1094 break;
1095 case FILE_OVERWRITE_IF:
1096 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1097 break;
1098 default:
1099 cFYI(1, "unknown disposition %d", disposition);
1100 ofun = SMBOPEN_OAPPEND; /* regular open */
1102 return ofun;
1105 static int
1106 access_flags_to_smbopen_mode(const int access_flags)
1108 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1110 if (masked_flags == GENERIC_READ)
1111 return SMBOPEN_READ;
1112 else if (masked_flags == GENERIC_WRITE)
1113 return SMBOPEN_WRITE;
1115 /* just go for read/write */
1116 return SMBOPEN_READWRITE;
1120 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1121 const char *fileName, const int openDisposition,
1122 const int access_flags, const int create_options, __u16 *netfid,
1123 int *pOplock, FILE_ALL_INFO *pfile_info,
1124 const struct nls_table *nls_codepage, int remap)
1126 int rc = -EACCES;
1127 OPENX_REQ *pSMB = NULL;
1128 OPENX_RSP *pSMBr = NULL;
1129 int bytes_returned;
1130 int name_len;
1131 __u16 count;
1133 OldOpenRetry:
1134 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1135 (void **) &pSMBr);
1136 if (rc)
1137 return rc;
1139 pSMB->AndXCommand = 0xFF; /* none */
1141 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1142 count = 1; /* account for one byte pad to word boundary */
1143 name_len =
1144 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1145 fileName, PATH_MAX, nls_codepage, remap);
1146 name_len++; /* trailing null */
1147 name_len *= 2;
1148 } else { /* BB improve check for buffer overruns BB */
1149 count = 0; /* no pad */
1150 name_len = strnlen(fileName, PATH_MAX);
1151 name_len++; /* trailing null */
1152 strncpy(pSMB->fileName, fileName, name_len);
1154 if (*pOplock & REQ_OPLOCK)
1155 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1156 else if (*pOplock & REQ_BATCHOPLOCK)
1157 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1159 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1160 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1161 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1162 /* set file as system file if special file such
1163 as fifo and server expecting SFU style and
1164 no Unix extensions */
1166 if (create_options & CREATE_OPTION_SPECIAL)
1167 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1168 else
1169 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1171 if (create_options & CREATE_OPTION_READONLY)
1172 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1174 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1175 CREATE_OPTIONS_MASK); */
1177 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1178 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1179 count += name_len;
1180 pSMB->hdr.smb_buf_length += count;
1182 pSMB->ByteCount = cpu_to_le16(count);
1183 /* long_op set to 1 to allow for oplock break timeouts */
1184 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1185 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1186 cifs_stats_inc(&tcon->num_opens);
1187 if (rc) {
1188 cFYI(1, "Error in Open = %d", rc);
1189 } else {
1190 /* BB verify if wct == 15 */
1192 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1194 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1195 /* Let caller know file was created so we can set the mode. */
1196 /* Do we care about the CreateAction in any other cases? */
1197 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1198 *pOplock |= CIFS_CREATE_ACTION; */
1200 if (pfile_info) {
1201 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1202 pfile_info->LastAccessTime = 0;
1203 pfile_info->LastWriteTime = 0;
1204 pfile_info->ChangeTime = 0;
1205 pfile_info->Attributes =
1206 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1207 /* the file_info buf is endian converted by caller */
1208 pfile_info->AllocationSize =
1209 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1210 pfile_info->EndOfFile = pfile_info->AllocationSize;
1211 pfile_info->NumberOfLinks = cpu_to_le32(1);
1212 pfile_info->DeletePending = 0;
1216 cifs_buf_release(pSMB);
1217 if (rc == -EAGAIN)
1218 goto OldOpenRetry;
1219 return rc;
1223 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1224 const char *fileName, const int openDisposition,
1225 const int access_flags, const int create_options, __u16 *netfid,
1226 int *pOplock, FILE_ALL_INFO *pfile_info,
1227 const struct nls_table *nls_codepage, int remap)
1229 int rc = -EACCES;
1230 OPEN_REQ *pSMB = NULL;
1231 OPEN_RSP *pSMBr = NULL;
1232 int bytes_returned;
1233 int name_len;
1234 __u16 count;
1236 openRetry:
1237 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1238 (void **) &pSMBr);
1239 if (rc)
1240 return rc;
1242 pSMB->AndXCommand = 0xFF; /* none */
1244 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1245 count = 1; /* account for one byte pad to word boundary */
1246 name_len =
1247 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1248 fileName, PATH_MAX, nls_codepage, remap);
1249 name_len++; /* trailing null */
1250 name_len *= 2;
1251 pSMB->NameLength = cpu_to_le16(name_len);
1252 } else { /* BB improve check for buffer overruns BB */
1253 count = 0; /* no pad */
1254 name_len = strnlen(fileName, PATH_MAX);
1255 name_len++; /* trailing null */
1256 pSMB->NameLength = cpu_to_le16(name_len);
1257 strncpy(pSMB->fileName, fileName, name_len);
1259 if (*pOplock & REQ_OPLOCK)
1260 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1261 else if (*pOplock & REQ_BATCHOPLOCK)
1262 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1263 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1264 pSMB->AllocationSize = 0;
1265 /* set file as system file if special file such
1266 as fifo and server expecting SFU style and
1267 no Unix extensions */
1268 if (create_options & CREATE_OPTION_SPECIAL)
1269 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1270 else
1271 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1273 /* XP does not handle ATTR_POSIX_SEMANTICS */
1274 /* but it helps speed up case sensitive checks for other
1275 servers such as Samba */
1276 if (tcon->ses->capabilities & CAP_UNIX)
1277 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1279 if (create_options & CREATE_OPTION_READONLY)
1280 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1282 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1283 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1284 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1285 /* BB Expirement with various impersonation levels and verify */
1286 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1287 pSMB->SecurityFlags =
1288 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1290 count += name_len;
1291 pSMB->hdr.smb_buf_length += count;
1293 pSMB->ByteCount = cpu_to_le16(count);
1294 /* long_op set to 1 to allow for oplock break timeouts */
1295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1296 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1297 cifs_stats_inc(&tcon->num_opens);
1298 if (rc) {
1299 cFYI(1, "Error in Open = %d", rc);
1300 } else {
1301 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1302 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1303 /* Let caller know file was created so we can set the mode. */
1304 /* Do we care about the CreateAction in any other cases? */
1305 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1306 *pOplock |= CIFS_CREATE_ACTION;
1307 if (pfile_info) {
1308 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1309 36 /* CreationTime to Attributes */);
1310 /* the file_info buf is endian converted by caller */
1311 pfile_info->AllocationSize = pSMBr->AllocationSize;
1312 pfile_info->EndOfFile = pSMBr->EndOfFile;
1313 pfile_info->NumberOfLinks = cpu_to_le32(1);
1314 pfile_info->DeletePending = 0;
1318 cifs_buf_release(pSMB);
1319 if (rc == -EAGAIN)
1320 goto openRetry;
1321 return rc;
1325 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1326 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1327 char **buf, int *pbuf_type)
1329 int rc = -EACCES;
1330 READ_REQ *pSMB = NULL;
1331 READ_RSP *pSMBr = NULL;
1332 char *pReadData = NULL;
1333 int wct;
1334 int resp_buf_type = 0;
1335 struct kvec iov[1];
1337 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
1338 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1339 wct = 12;
1340 else {
1341 wct = 10; /* old style read */
1342 if ((lseek >> 32) > 0) {
1343 /* can not handle this big offset for old */
1344 return -EIO;
1348 *nbytes = 0;
1349 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1350 if (rc)
1351 return rc;
1353 /* tcon and ses pointer are checked in smb_init */
1354 if (tcon->ses->server == NULL)
1355 return -ECONNABORTED;
1357 pSMB->AndXCommand = 0xFF; /* none */
1358 pSMB->Fid = netfid;
1359 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1360 if (wct == 12)
1361 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1363 pSMB->Remaining = 0;
1364 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1365 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1366 if (wct == 12)
1367 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1368 else {
1369 /* old style read */
1370 struct smb_com_readx_req *pSMBW =
1371 (struct smb_com_readx_req *)pSMB;
1372 pSMBW->ByteCount = 0;
1375 iov[0].iov_base = (char *)pSMB;
1376 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1377 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1378 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1379 cifs_stats_inc(&tcon->num_reads);
1380 pSMBr = (READ_RSP *)iov[0].iov_base;
1381 if (rc) {
1382 cERROR(1, "Send error in read = %d", rc);
1383 } else {
1384 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1385 data_length = data_length << 16;
1386 data_length += le16_to_cpu(pSMBr->DataLength);
1387 *nbytes = data_length;
1389 /*check that DataLength would not go beyond end of SMB */
1390 if ((data_length > CIFSMaxBufSize)
1391 || (data_length > count)) {
1392 cFYI(1, "bad length %d for count %d",
1393 data_length, count);
1394 rc = -EIO;
1395 *nbytes = 0;
1396 } else {
1397 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1398 le16_to_cpu(pSMBr->DataOffset);
1399 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1400 cERROR(1, "Faulting on read rc = %d",rc);
1401 rc = -EFAULT;
1402 }*/ /* can not use copy_to_user when using page cache*/
1403 if (*buf)
1404 memcpy(*buf, pReadData, data_length);
1408 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1409 if (*buf) {
1410 if (resp_buf_type == CIFS_SMALL_BUFFER)
1411 cifs_small_buf_release(iov[0].iov_base);
1412 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1413 cifs_buf_release(iov[0].iov_base);
1414 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1415 /* return buffer to caller to free */
1416 *buf = iov[0].iov_base;
1417 if (resp_buf_type == CIFS_SMALL_BUFFER)
1418 *pbuf_type = CIFS_SMALL_BUFFER;
1419 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1420 *pbuf_type = CIFS_LARGE_BUFFER;
1421 } /* else no valid buffer on return - leave as null */
1423 /* Note: On -EAGAIN error only caller can retry on handle based calls
1424 since file handle passed in no longer valid */
1425 return rc;
1430 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1431 const int netfid, const unsigned int count,
1432 const __u64 offset, unsigned int *nbytes, const char *buf,
1433 const char __user *ubuf, const int long_op)
1435 int rc = -EACCES;
1436 WRITE_REQ *pSMB = NULL;
1437 WRITE_RSP *pSMBr = NULL;
1438 int bytes_returned, wct;
1439 __u32 bytes_sent;
1440 __u16 byte_count;
1442 *nbytes = 0;
1444 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
1445 if (tcon->ses == NULL)
1446 return -ECONNABORTED;
1448 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1449 wct = 14;
1450 else {
1451 wct = 12;
1452 if ((offset >> 32) > 0) {
1453 /* can not handle big offset for old srv */
1454 return -EIO;
1458 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1459 (void **) &pSMBr);
1460 if (rc)
1461 return rc;
1462 /* tcon and ses pointer are checked in smb_init */
1463 if (tcon->ses->server == NULL)
1464 return -ECONNABORTED;
1466 pSMB->AndXCommand = 0xFF; /* none */
1467 pSMB->Fid = netfid;
1468 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1469 if (wct == 14)
1470 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1472 pSMB->Reserved = 0xFFFFFFFF;
1473 pSMB->WriteMode = 0;
1474 pSMB->Remaining = 0;
1476 /* Can increase buffer size if buffer is big enough in some cases ie we
1477 can send more if LARGE_WRITE_X capability returned by the server and if
1478 our buffer is big enough or if we convert to iovecs on socket writes
1479 and eliminate the copy to the CIFS buffer */
1480 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1481 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1482 } else {
1483 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1484 & ~0xFF;
1487 if (bytes_sent > count)
1488 bytes_sent = count;
1489 pSMB->DataOffset =
1490 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1491 if (buf)
1492 memcpy(pSMB->Data, buf, bytes_sent);
1493 else if (ubuf) {
1494 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1495 cifs_buf_release(pSMB);
1496 return -EFAULT;
1498 } else if (count != 0) {
1499 /* No buffer */
1500 cifs_buf_release(pSMB);
1501 return -EINVAL;
1502 } /* else setting file size with write of zero bytes */
1503 if (wct == 14)
1504 byte_count = bytes_sent + 1; /* pad */
1505 else /* wct == 12 */
1506 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1508 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1509 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1510 pSMB->hdr.smb_buf_length += byte_count;
1512 if (wct == 14)
1513 pSMB->ByteCount = cpu_to_le16(byte_count);
1514 else { /* old style write has byte count 4 bytes earlier
1515 so 4 bytes pad */
1516 struct smb_com_writex_req *pSMBW =
1517 (struct smb_com_writex_req *)pSMB;
1518 pSMBW->ByteCount = cpu_to_le16(byte_count);
1521 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1522 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1523 cifs_stats_inc(&tcon->num_writes);
1524 if (rc) {
1525 cFYI(1, "Send error in write = %d", rc);
1526 } else {
1527 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1528 *nbytes = (*nbytes) << 16;
1529 *nbytes += le16_to_cpu(pSMBr->Count);
1532 * Mask off high 16 bits when bytes written as returned by the
1533 * server is greater than bytes requested by the client. Some
1534 * OS/2 servers are known to set incorrect CountHigh values.
1536 if (*nbytes > count)
1537 *nbytes &= 0xFFFF;
1540 cifs_buf_release(pSMB);
1542 /* Note: On -EAGAIN error only caller can retry on handle based calls
1543 since file handle passed in no longer valid */
1545 return rc;
1549 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1550 const int netfid, const unsigned int count,
1551 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1552 int n_vec, const int long_op)
1554 int rc = -EACCES;
1555 WRITE_REQ *pSMB = NULL;
1556 int wct;
1557 int smb_hdr_len;
1558 int resp_buf_type = 0;
1560 *nbytes = 0;
1562 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
1564 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1565 wct = 14;
1566 } else {
1567 wct = 12;
1568 if ((offset >> 32) > 0) {
1569 /* can not handle big offset for old srv */
1570 return -EIO;
1573 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1574 if (rc)
1575 return rc;
1576 /* tcon and ses pointer are checked in smb_init */
1577 if (tcon->ses->server == NULL)
1578 return -ECONNABORTED;
1580 pSMB->AndXCommand = 0xFF; /* none */
1581 pSMB->Fid = netfid;
1582 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1583 if (wct == 14)
1584 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1585 pSMB->Reserved = 0xFFFFFFFF;
1586 pSMB->WriteMode = 0;
1587 pSMB->Remaining = 0;
1589 pSMB->DataOffset =
1590 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1592 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1593 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1594 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1595 if (wct == 14)
1596 pSMB->hdr.smb_buf_length += count+1;
1597 else /* wct == 12 */
1598 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1599 if (wct == 14)
1600 pSMB->ByteCount = cpu_to_le16(count + 1);
1601 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1602 struct smb_com_writex_req *pSMBW =
1603 (struct smb_com_writex_req *)pSMB;
1604 pSMBW->ByteCount = cpu_to_le16(count + 5);
1606 iov[0].iov_base = pSMB;
1607 if (wct == 14)
1608 iov[0].iov_len = smb_hdr_len + 4;
1609 else /* wct == 12 pad bigger by four bytes */
1610 iov[0].iov_len = smb_hdr_len + 8;
1613 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1614 long_op);
1615 cifs_stats_inc(&tcon->num_writes);
1616 if (rc) {
1617 cFYI(1, "Send error Write2 = %d", rc);
1618 } else if (resp_buf_type == 0) {
1619 /* presumably this can not happen, but best to be safe */
1620 rc = -EIO;
1621 } else {
1622 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1623 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1624 *nbytes = (*nbytes) << 16;
1625 *nbytes += le16_to_cpu(pSMBr->Count);
1628 * Mask off high 16 bits when bytes written as returned by the
1629 * server is greater than bytes requested by the client. OS/2
1630 * servers are known to set incorrect CountHigh values.
1632 if (*nbytes > count)
1633 *nbytes &= 0xFFFF;
1636 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1637 if (resp_buf_type == CIFS_SMALL_BUFFER)
1638 cifs_small_buf_release(iov[0].iov_base);
1639 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1640 cifs_buf_release(iov[0].iov_base);
1642 /* Note: On -EAGAIN error only caller can retry on handle based calls
1643 since file handle passed in no longer valid */
1645 return rc;
1650 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1651 const __u16 smb_file_id, const __u64 len,
1652 const __u64 offset, const __u32 numUnlock,
1653 const __u32 numLock, const __u8 lockType, const bool waitFlag)
1655 int rc = 0;
1656 LOCK_REQ *pSMB = NULL;
1657 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1658 int bytes_returned;
1659 int timeout = 0;
1660 __u16 count;
1662 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
1663 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1665 if (rc)
1666 return rc;
1668 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1669 timeout = CIFS_ASYNC_OP; /* no response expected */
1670 pSMB->Timeout = 0;
1671 } else if (waitFlag) {
1672 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1673 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1674 } else {
1675 pSMB->Timeout = 0;
1678 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1679 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1680 pSMB->LockType = lockType;
1681 pSMB->AndXCommand = 0xFF; /* none */
1682 pSMB->Fid = smb_file_id; /* netfid stays le */
1684 if ((numLock != 0) || (numUnlock != 0)) {
1685 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1686 /* BB where to store pid high? */
1687 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1688 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1689 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1690 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1691 count = sizeof(LOCKING_ANDX_RANGE);
1692 } else {
1693 /* oplock break */
1694 count = 0;
1696 pSMB->hdr.smb_buf_length += count;
1697 pSMB->ByteCount = cpu_to_le16(count);
1699 if (waitFlag) {
1700 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1701 (struct smb_hdr *) pSMB, &bytes_returned);
1702 cifs_small_buf_release(pSMB);
1703 } else {
1704 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1705 timeout);
1706 /* SMB buffer freed by function above */
1708 cifs_stats_inc(&tcon->num_locks);
1709 if (rc)
1710 cFYI(1, "Send error in Lock = %d", rc);
1712 /* Note: On -EAGAIN error only caller can retry on handle based calls
1713 since file handle passed in no longer valid */
1714 return rc;
1718 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1719 const __u16 smb_file_id, const int get_flag, const __u64 len,
1720 struct file_lock *pLockData, const __u16 lock_type,
1721 const bool waitFlag)
1723 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1724 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1725 struct cifs_posix_lock *parm_data;
1726 int rc = 0;
1727 int timeout = 0;
1728 int bytes_returned = 0;
1729 int resp_buf_type = 0;
1730 __u16 params, param_offset, offset, byte_count, count;
1731 struct kvec iov[1];
1733 cFYI(1, "Posix Lock");
1735 if (pLockData == NULL)
1736 return -EINVAL;
1738 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1740 if (rc)
1741 return rc;
1743 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1745 params = 6;
1746 pSMB->MaxSetupCount = 0;
1747 pSMB->Reserved = 0;
1748 pSMB->Flags = 0;
1749 pSMB->Reserved2 = 0;
1750 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1751 offset = param_offset + params;
1753 count = sizeof(struct cifs_posix_lock);
1754 pSMB->MaxParameterCount = cpu_to_le16(2);
1755 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1756 pSMB->SetupCount = 1;
1757 pSMB->Reserved3 = 0;
1758 if (get_flag)
1759 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1760 else
1761 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1762 byte_count = 3 /* pad */ + params + count;
1763 pSMB->DataCount = cpu_to_le16(count);
1764 pSMB->ParameterCount = cpu_to_le16(params);
1765 pSMB->TotalDataCount = pSMB->DataCount;
1766 pSMB->TotalParameterCount = pSMB->ParameterCount;
1767 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1768 parm_data = (struct cifs_posix_lock *)
1769 (((char *) &pSMB->hdr.Protocol) + offset);
1771 parm_data->lock_type = cpu_to_le16(lock_type);
1772 if (waitFlag) {
1773 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1774 parm_data->lock_flags = cpu_to_le16(1);
1775 pSMB->Timeout = cpu_to_le32(-1);
1776 } else
1777 pSMB->Timeout = 0;
1779 parm_data->pid = cpu_to_le32(current->tgid);
1780 parm_data->start = cpu_to_le64(pLockData->fl_start);
1781 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1783 pSMB->DataOffset = cpu_to_le16(offset);
1784 pSMB->Fid = smb_file_id;
1785 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1786 pSMB->Reserved4 = 0;
1787 pSMB->hdr.smb_buf_length += byte_count;
1788 pSMB->ByteCount = cpu_to_le16(byte_count);
1789 if (waitFlag) {
1790 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1791 (struct smb_hdr *) pSMBr, &bytes_returned);
1792 } else {
1793 iov[0].iov_base = (char *)pSMB;
1794 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1795 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1796 &resp_buf_type, timeout);
1797 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1798 not try to free it twice below on exit */
1799 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1802 if (rc) {
1803 cFYI(1, "Send error in Posix Lock = %d", rc);
1804 } else if (get_flag) {
1805 /* lock structure can be returned on get */
1806 __u16 data_offset;
1807 __u16 data_count;
1808 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1810 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1811 rc = -EIO; /* bad smb */
1812 goto plk_err_exit;
1814 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1815 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1816 if (data_count < sizeof(struct cifs_posix_lock)) {
1817 rc = -EIO;
1818 goto plk_err_exit;
1820 parm_data = (struct cifs_posix_lock *)
1821 ((char *)&pSMBr->hdr.Protocol + data_offset);
1822 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
1823 pLockData->fl_type = F_UNLCK;
1824 else {
1825 if (parm_data->lock_type ==
1826 __constant_cpu_to_le16(CIFS_RDLCK))
1827 pLockData->fl_type = F_RDLCK;
1828 else if (parm_data->lock_type ==
1829 __constant_cpu_to_le16(CIFS_WRLCK))
1830 pLockData->fl_type = F_WRLCK;
1832 pLockData->fl_start = parm_data->start;
1833 pLockData->fl_end = parm_data->start +
1834 parm_data->length - 1;
1835 pLockData->fl_pid = parm_data->pid;
1839 plk_err_exit:
1840 if (pSMB)
1841 cifs_small_buf_release(pSMB);
1843 if (resp_buf_type == CIFS_SMALL_BUFFER)
1844 cifs_small_buf_release(iov[0].iov_base);
1845 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1846 cifs_buf_release(iov[0].iov_base);
1848 /* Note: On -EAGAIN error only caller can retry on handle based calls
1849 since file handle passed in no longer valid */
1851 return rc;
1856 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1858 int rc = 0;
1859 CLOSE_REQ *pSMB = NULL;
1860 cFYI(1, "In CIFSSMBClose");
1862 /* do not retry on dead session on close */
1863 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1864 if (rc == -EAGAIN)
1865 return 0;
1866 if (rc)
1867 return rc;
1869 pSMB->FileID = (__u16) smb_file_id;
1870 pSMB->LastWriteTime = 0xFFFFFFFF;
1871 pSMB->ByteCount = 0;
1872 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1873 cifs_stats_inc(&tcon->num_closes);
1874 if (rc) {
1875 if (rc != -EINTR) {
1876 /* EINTR is expected when user ctl-c to kill app */
1877 cERROR(1, "Send error in Close = %d", rc);
1881 /* Since session is dead, file will be closed on server already */
1882 if (rc == -EAGAIN)
1883 rc = 0;
1885 return rc;
1889 CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1891 int rc = 0;
1892 FLUSH_REQ *pSMB = NULL;
1893 cFYI(1, "In CIFSSMBFlush");
1895 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1896 if (rc)
1897 return rc;
1899 pSMB->FileID = (__u16) smb_file_id;
1900 pSMB->ByteCount = 0;
1901 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1902 cifs_stats_inc(&tcon->num_flushes);
1903 if (rc)
1904 cERROR(1, "Send error in Flush = %d", rc);
1906 return rc;
1910 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1911 const char *fromName, const char *toName,
1912 const struct nls_table *nls_codepage, int remap)
1914 int rc = 0;
1915 RENAME_REQ *pSMB = NULL;
1916 RENAME_RSP *pSMBr = NULL;
1917 int bytes_returned;
1918 int name_len, name_len2;
1919 __u16 count;
1921 cFYI(1, "In CIFSSMBRename");
1922 renameRetry:
1923 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1924 (void **) &pSMBr);
1925 if (rc)
1926 return rc;
1928 pSMB->BufferFormat = 0x04;
1929 pSMB->SearchAttributes =
1930 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1931 ATTR_DIRECTORY);
1933 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1934 name_len =
1935 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1936 PATH_MAX, nls_codepage, remap);
1937 name_len++; /* trailing null */
1938 name_len *= 2;
1939 pSMB->OldFileName[name_len] = 0x04; /* pad */
1940 /* protocol requires ASCII signature byte on Unicode string */
1941 pSMB->OldFileName[name_len + 1] = 0x00;
1942 name_len2 =
1943 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1944 toName, PATH_MAX, nls_codepage, remap);
1945 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1946 name_len2 *= 2; /* convert to bytes */
1947 } else { /* BB improve the check for buffer overruns BB */
1948 name_len = strnlen(fromName, PATH_MAX);
1949 name_len++; /* trailing null */
1950 strncpy(pSMB->OldFileName, fromName, name_len);
1951 name_len2 = strnlen(toName, PATH_MAX);
1952 name_len2++; /* trailing null */
1953 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1954 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1955 name_len2++; /* trailing null */
1956 name_len2++; /* signature byte */
1959 count = 1 /* 1st signature byte */ + name_len + name_len2;
1960 pSMB->hdr.smb_buf_length += count;
1961 pSMB->ByteCount = cpu_to_le16(count);
1963 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1964 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1965 cifs_stats_inc(&tcon->num_renames);
1966 if (rc)
1967 cFYI(1, "Send error in rename = %d", rc);
1969 cifs_buf_release(pSMB);
1971 if (rc == -EAGAIN)
1972 goto renameRetry;
1974 return rc;
1977 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1978 int netfid, const char *target_name,
1979 const struct nls_table *nls_codepage, int remap)
1981 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1982 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1983 struct set_file_rename *rename_info;
1984 char *data_offset;
1985 char dummy_string[30];
1986 int rc = 0;
1987 int bytes_returned = 0;
1988 int len_of_str;
1989 __u16 params, param_offset, offset, count, byte_count;
1991 cFYI(1, "Rename to File by handle");
1992 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1993 (void **) &pSMBr);
1994 if (rc)
1995 return rc;
1997 params = 6;
1998 pSMB->MaxSetupCount = 0;
1999 pSMB->Reserved = 0;
2000 pSMB->Flags = 0;
2001 pSMB->Timeout = 0;
2002 pSMB->Reserved2 = 0;
2003 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2004 offset = param_offset + params;
2006 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2007 rename_info = (struct set_file_rename *) data_offset;
2008 pSMB->MaxParameterCount = cpu_to_le16(2);
2009 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2010 pSMB->SetupCount = 1;
2011 pSMB->Reserved3 = 0;
2012 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2013 byte_count = 3 /* pad */ + params;
2014 pSMB->ParameterCount = cpu_to_le16(params);
2015 pSMB->TotalParameterCount = pSMB->ParameterCount;
2016 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2017 pSMB->DataOffset = cpu_to_le16(offset);
2018 /* construct random name ".cifs_tmp<inodenum><mid>" */
2019 rename_info->overwrite = cpu_to_le32(1);
2020 rename_info->root_fid = 0;
2021 /* unicode only call */
2022 if (target_name == NULL) {
2023 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2024 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2025 dummy_string, 24, nls_codepage, remap);
2026 } else {
2027 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2028 target_name, PATH_MAX, nls_codepage,
2029 remap);
2031 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2032 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2033 byte_count += count;
2034 pSMB->DataCount = cpu_to_le16(count);
2035 pSMB->TotalDataCount = pSMB->DataCount;
2036 pSMB->Fid = netfid;
2037 pSMB->InformationLevel =
2038 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2039 pSMB->Reserved4 = 0;
2040 pSMB->hdr.smb_buf_length += byte_count;
2041 pSMB->ByteCount = cpu_to_le16(byte_count);
2042 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2044 cifs_stats_inc(&pTcon->num_t2renames);
2045 if (rc)
2046 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
2048 cifs_buf_release(pSMB);
2050 /* Note: On -EAGAIN error only caller can retry on handle based calls
2051 since file handle passed in no longer valid */
2053 return rc;
2057 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2058 const __u16 target_tid, const char *toName, const int flags,
2059 const struct nls_table *nls_codepage, int remap)
2061 int rc = 0;
2062 COPY_REQ *pSMB = NULL;
2063 COPY_RSP *pSMBr = NULL;
2064 int bytes_returned;
2065 int name_len, name_len2;
2066 __u16 count;
2068 cFYI(1, "In CIFSSMBCopy");
2069 copyRetry:
2070 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2071 (void **) &pSMBr);
2072 if (rc)
2073 return rc;
2075 pSMB->BufferFormat = 0x04;
2076 pSMB->Tid2 = target_tid;
2078 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2080 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2081 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2082 fromName, PATH_MAX, nls_codepage,
2083 remap);
2084 name_len++; /* trailing null */
2085 name_len *= 2;
2086 pSMB->OldFileName[name_len] = 0x04; /* pad */
2087 /* protocol requires ASCII signature byte on Unicode string */
2088 pSMB->OldFileName[name_len + 1] = 0x00;
2089 name_len2 =
2090 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2091 toName, PATH_MAX, nls_codepage, remap);
2092 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2093 name_len2 *= 2; /* convert to bytes */
2094 } else { /* BB improve the check for buffer overruns BB */
2095 name_len = strnlen(fromName, PATH_MAX);
2096 name_len++; /* trailing null */
2097 strncpy(pSMB->OldFileName, fromName, name_len);
2098 name_len2 = strnlen(toName, PATH_MAX);
2099 name_len2++; /* trailing null */
2100 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2101 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2102 name_len2++; /* trailing null */
2103 name_len2++; /* signature byte */
2106 count = 1 /* 1st signature byte */ + name_len + name_len2;
2107 pSMB->hdr.smb_buf_length += count;
2108 pSMB->ByteCount = cpu_to_le16(count);
2110 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2111 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2112 if (rc) {
2113 cFYI(1, "Send error in copy = %d with %d files copied",
2114 rc, le16_to_cpu(pSMBr->CopyCount));
2116 cifs_buf_release(pSMB);
2118 if (rc == -EAGAIN)
2119 goto copyRetry;
2121 return rc;
2125 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2126 const char *fromName, const char *toName,
2127 const struct nls_table *nls_codepage)
2129 TRANSACTION2_SPI_REQ *pSMB = NULL;
2130 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2131 char *data_offset;
2132 int name_len;
2133 int name_len_target;
2134 int rc = 0;
2135 int bytes_returned = 0;
2136 __u16 params, param_offset, offset, byte_count;
2138 cFYI(1, "In Symlink Unix style");
2139 createSymLinkRetry:
2140 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2141 (void **) &pSMBr);
2142 if (rc)
2143 return rc;
2145 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2146 name_len =
2147 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2148 /* find define for this maxpathcomponent */
2149 , nls_codepage);
2150 name_len++; /* trailing null */
2151 name_len *= 2;
2153 } else { /* BB improve the check for buffer overruns BB */
2154 name_len = strnlen(fromName, PATH_MAX);
2155 name_len++; /* trailing null */
2156 strncpy(pSMB->FileName, fromName, name_len);
2158 params = 6 + name_len;
2159 pSMB->MaxSetupCount = 0;
2160 pSMB->Reserved = 0;
2161 pSMB->Flags = 0;
2162 pSMB->Timeout = 0;
2163 pSMB->Reserved2 = 0;
2164 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2165 InformationLevel) - 4;
2166 offset = param_offset + params;
2168 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2169 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2170 name_len_target =
2171 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2172 /* find define for this maxpathcomponent */
2173 , nls_codepage);
2174 name_len_target++; /* trailing null */
2175 name_len_target *= 2;
2176 } else { /* BB improve the check for buffer overruns BB */
2177 name_len_target = strnlen(toName, PATH_MAX);
2178 name_len_target++; /* trailing null */
2179 strncpy(data_offset, toName, name_len_target);
2182 pSMB->MaxParameterCount = cpu_to_le16(2);
2183 /* BB find exact max on data count below from sess */
2184 pSMB->MaxDataCount = cpu_to_le16(1000);
2185 pSMB->SetupCount = 1;
2186 pSMB->Reserved3 = 0;
2187 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2188 byte_count = 3 /* pad */ + params + name_len_target;
2189 pSMB->DataCount = cpu_to_le16(name_len_target);
2190 pSMB->ParameterCount = cpu_to_le16(params);
2191 pSMB->TotalDataCount = pSMB->DataCount;
2192 pSMB->TotalParameterCount = pSMB->ParameterCount;
2193 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2194 pSMB->DataOffset = cpu_to_le16(offset);
2195 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2196 pSMB->Reserved4 = 0;
2197 pSMB->hdr.smb_buf_length += byte_count;
2198 pSMB->ByteCount = cpu_to_le16(byte_count);
2199 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2200 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2201 cifs_stats_inc(&tcon->num_symlinks);
2202 if (rc)
2203 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
2205 cifs_buf_release(pSMB);
2207 if (rc == -EAGAIN)
2208 goto createSymLinkRetry;
2210 return rc;
2214 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2215 const char *fromName, const char *toName,
2216 const struct nls_table *nls_codepage, int remap)
2218 TRANSACTION2_SPI_REQ *pSMB = NULL;
2219 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2220 char *data_offset;
2221 int name_len;
2222 int name_len_target;
2223 int rc = 0;
2224 int bytes_returned = 0;
2225 __u16 params, param_offset, offset, byte_count;
2227 cFYI(1, "In Create Hard link Unix style");
2228 createHardLinkRetry:
2229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2230 (void **) &pSMBr);
2231 if (rc)
2232 return rc;
2234 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2235 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2236 PATH_MAX, nls_codepage, remap);
2237 name_len++; /* trailing null */
2238 name_len *= 2;
2240 } else { /* BB improve the check for buffer overruns BB */
2241 name_len = strnlen(toName, PATH_MAX);
2242 name_len++; /* trailing null */
2243 strncpy(pSMB->FileName, toName, name_len);
2245 params = 6 + name_len;
2246 pSMB->MaxSetupCount = 0;
2247 pSMB->Reserved = 0;
2248 pSMB->Flags = 0;
2249 pSMB->Timeout = 0;
2250 pSMB->Reserved2 = 0;
2251 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2252 InformationLevel) - 4;
2253 offset = param_offset + params;
2255 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2256 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2257 name_len_target =
2258 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2259 nls_codepage, remap);
2260 name_len_target++; /* trailing null */
2261 name_len_target *= 2;
2262 } else { /* BB improve the check for buffer overruns BB */
2263 name_len_target = strnlen(fromName, PATH_MAX);
2264 name_len_target++; /* trailing null */
2265 strncpy(data_offset, fromName, name_len_target);
2268 pSMB->MaxParameterCount = cpu_to_le16(2);
2269 /* BB find exact max on data count below from sess*/
2270 pSMB->MaxDataCount = cpu_to_le16(1000);
2271 pSMB->SetupCount = 1;
2272 pSMB->Reserved3 = 0;
2273 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2274 byte_count = 3 /* pad */ + params + name_len_target;
2275 pSMB->ParameterCount = cpu_to_le16(params);
2276 pSMB->TotalParameterCount = pSMB->ParameterCount;
2277 pSMB->DataCount = cpu_to_le16(name_len_target);
2278 pSMB->TotalDataCount = pSMB->DataCount;
2279 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2280 pSMB->DataOffset = cpu_to_le16(offset);
2281 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2282 pSMB->Reserved4 = 0;
2283 pSMB->hdr.smb_buf_length += byte_count;
2284 pSMB->ByteCount = cpu_to_le16(byte_count);
2285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2286 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2287 cifs_stats_inc(&tcon->num_hardlinks);
2288 if (rc)
2289 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
2291 cifs_buf_release(pSMB);
2292 if (rc == -EAGAIN)
2293 goto createHardLinkRetry;
2295 return rc;
2299 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2300 const char *fromName, const char *toName,
2301 const struct nls_table *nls_codepage, int remap)
2303 int rc = 0;
2304 NT_RENAME_REQ *pSMB = NULL;
2305 RENAME_RSP *pSMBr = NULL;
2306 int bytes_returned;
2307 int name_len, name_len2;
2308 __u16 count;
2310 cFYI(1, "In CIFSCreateHardLink");
2311 winCreateHardLinkRetry:
2313 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2314 (void **) &pSMBr);
2315 if (rc)
2316 return rc;
2318 pSMB->SearchAttributes =
2319 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2320 ATTR_DIRECTORY);
2321 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2322 pSMB->ClusterCount = 0;
2324 pSMB->BufferFormat = 0x04;
2326 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2327 name_len =
2328 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2329 PATH_MAX, nls_codepage, remap);
2330 name_len++; /* trailing null */
2331 name_len *= 2;
2333 /* protocol specifies ASCII buffer format (0x04) for unicode */
2334 pSMB->OldFileName[name_len] = 0x04;
2335 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2336 name_len2 =
2337 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2338 toName, PATH_MAX, nls_codepage, remap);
2339 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2340 name_len2 *= 2; /* convert to bytes */
2341 } else { /* BB improve the check for buffer overruns BB */
2342 name_len = strnlen(fromName, PATH_MAX);
2343 name_len++; /* trailing null */
2344 strncpy(pSMB->OldFileName, fromName, name_len);
2345 name_len2 = strnlen(toName, PATH_MAX);
2346 name_len2++; /* trailing null */
2347 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2348 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2349 name_len2++; /* trailing null */
2350 name_len2++; /* signature byte */
2353 count = 1 /* string type byte */ + name_len + name_len2;
2354 pSMB->hdr.smb_buf_length += count;
2355 pSMB->ByteCount = cpu_to_le16(count);
2357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2359 cifs_stats_inc(&tcon->num_hardlinks);
2360 if (rc)
2361 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
2363 cifs_buf_release(pSMB);
2364 if (rc == -EAGAIN)
2365 goto winCreateHardLinkRetry;
2367 return rc;
2371 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2372 const unsigned char *searchName, char **symlinkinfo,
2373 const struct nls_table *nls_codepage)
2375 /* SMB_QUERY_FILE_UNIX_LINK */
2376 TRANSACTION2_QPI_REQ *pSMB = NULL;
2377 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2378 int rc = 0;
2379 int bytes_returned;
2380 int name_len;
2381 __u16 params, byte_count;
2382 char *data_start;
2384 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
2386 querySymLinkRetry:
2387 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2388 (void **) &pSMBr);
2389 if (rc)
2390 return rc;
2392 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2393 name_len =
2394 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2395 PATH_MAX, nls_codepage);
2396 name_len++; /* trailing null */
2397 name_len *= 2;
2398 } else { /* BB improve the check for buffer overruns BB */
2399 name_len = strnlen(searchName, PATH_MAX);
2400 name_len++; /* trailing null */
2401 strncpy(pSMB->FileName, searchName, name_len);
2404 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2405 pSMB->TotalDataCount = 0;
2406 pSMB->MaxParameterCount = cpu_to_le16(2);
2407 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
2408 pSMB->MaxSetupCount = 0;
2409 pSMB->Reserved = 0;
2410 pSMB->Flags = 0;
2411 pSMB->Timeout = 0;
2412 pSMB->Reserved2 = 0;
2413 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2414 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2415 pSMB->DataCount = 0;
2416 pSMB->DataOffset = 0;
2417 pSMB->SetupCount = 1;
2418 pSMB->Reserved3 = 0;
2419 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2420 byte_count = params + 1 /* pad */ ;
2421 pSMB->TotalParameterCount = cpu_to_le16(params);
2422 pSMB->ParameterCount = pSMB->TotalParameterCount;
2423 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2424 pSMB->Reserved4 = 0;
2425 pSMB->hdr.smb_buf_length += byte_count;
2426 pSMB->ByteCount = cpu_to_le16(byte_count);
2428 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2429 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2430 if (rc) {
2431 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
2432 } else {
2433 /* decode response */
2435 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2436 /* BB also check enough total bytes returned */
2437 if (rc || (pSMBr->ByteCount < 2))
2438 rc = -EIO;
2439 else {
2440 bool is_unicode;
2441 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2443 data_start = ((char *) &pSMBr->hdr.Protocol) +
2444 le16_to_cpu(pSMBr->t2.DataOffset);
2446 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2447 is_unicode = true;
2448 else
2449 is_unicode = false;
2451 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
2452 is_unicode, nls_codepage);
2453 if (!*symlinkinfo)
2454 rc = -ENOMEM;
2457 cifs_buf_release(pSMB);
2458 if (rc == -EAGAIN)
2459 goto querySymLinkRetry;
2460 return rc;
2463 #ifdef CONFIG_CIFS_EXPERIMENTAL
2464 /* Initialize NT TRANSACT SMB into small smb request buffer.
2465 This assumes that all NT TRANSACTS that we init here have
2466 total parm and data under about 400 bytes (to fit in small cifs
2467 buffer size), which is the case so far, it easily fits. NB:
2468 Setup words themselves and ByteCount
2469 MaxSetupCount (size of returned setup area) and
2470 MaxParameterCount (returned parms size) must be set by caller */
2471 static int
2472 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2473 const int parm_len, struct cifsTconInfo *tcon,
2474 void **ret_buf)
2476 int rc;
2477 __u32 temp_offset;
2478 struct smb_com_ntransact_req *pSMB;
2480 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2481 (void **)&pSMB);
2482 if (rc)
2483 return rc;
2484 *ret_buf = (void *)pSMB;
2485 pSMB->Reserved = 0;
2486 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2487 pSMB->TotalDataCount = 0;
2488 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2489 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2490 pSMB->ParameterCount = pSMB->TotalParameterCount;
2491 pSMB->DataCount = pSMB->TotalDataCount;
2492 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2493 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2494 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2495 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2496 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2497 pSMB->SubCommand = cpu_to_le16(sub_command);
2498 return 0;
2501 static int
2502 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2503 __u32 *pparmlen, __u32 *pdatalen)
2505 char *end_of_smb;
2506 __u32 data_count, data_offset, parm_count, parm_offset;
2507 struct smb_com_ntransact_rsp *pSMBr;
2509 *pdatalen = 0;
2510 *pparmlen = 0;
2512 if (buf == NULL)
2513 return -EINVAL;
2515 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2517 /* ByteCount was converted from little endian in SendReceive */
2518 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2519 (char *)&pSMBr->ByteCount;
2521 data_offset = le32_to_cpu(pSMBr->DataOffset);
2522 data_count = le32_to_cpu(pSMBr->DataCount);
2523 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2524 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2526 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2527 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2529 /* should we also check that parm and data areas do not overlap? */
2530 if (*ppparm > end_of_smb) {
2531 cFYI(1, "parms start after end of smb");
2532 return -EINVAL;
2533 } else if (parm_count + *ppparm > end_of_smb) {
2534 cFYI(1, "parm end after end of smb");
2535 return -EINVAL;
2536 } else if (*ppdata > end_of_smb) {
2537 cFYI(1, "data starts after end of smb");
2538 return -EINVAL;
2539 } else if (data_count + *ppdata > end_of_smb) {
2540 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
2541 *ppdata, data_count, (data_count + *ppdata),
2542 end_of_smb, pSMBr);
2543 return -EINVAL;
2544 } else if (parm_count + data_count > pSMBr->ByteCount) {
2545 cFYI(1, "parm count and data count larger than SMB");
2546 return -EINVAL;
2548 *pdatalen = data_count;
2549 *pparmlen = parm_count;
2550 return 0;
2554 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2555 const unsigned char *searchName,
2556 char *symlinkinfo, const int buflen, __u16 fid,
2557 const struct nls_table *nls_codepage)
2559 int rc = 0;
2560 int bytes_returned;
2561 struct smb_com_transaction_ioctl_req *pSMB;
2562 struct smb_com_transaction_ioctl_rsp *pSMBr;
2564 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
2565 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2566 (void **) &pSMBr);
2567 if (rc)
2568 return rc;
2570 pSMB->TotalParameterCount = 0 ;
2571 pSMB->TotalDataCount = 0;
2572 pSMB->MaxParameterCount = cpu_to_le32(2);
2573 /* BB find exact data count max from sess structure BB */
2574 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2575 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2576 pSMB->MaxSetupCount = 4;
2577 pSMB->Reserved = 0;
2578 pSMB->ParameterOffset = 0;
2579 pSMB->DataCount = 0;
2580 pSMB->DataOffset = 0;
2581 pSMB->SetupCount = 4;
2582 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2583 pSMB->ParameterCount = pSMB->TotalParameterCount;
2584 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2585 pSMB->IsFsctl = 1; /* FSCTL */
2586 pSMB->IsRootFlag = 0;
2587 pSMB->Fid = fid; /* file handle always le */
2588 pSMB->ByteCount = 0;
2590 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2591 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2592 if (rc) {
2593 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
2594 } else { /* decode response */
2595 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2596 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2597 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
2598 /* BB also check enough total bytes returned */
2599 rc = -EIO; /* bad smb */
2600 goto qreparse_out;
2602 if (data_count && (data_count < 2048)) {
2603 char *end_of_smb = 2 /* sizeof byte count */ +
2604 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
2606 struct reparse_data *reparse_buf =
2607 (struct reparse_data *)
2608 ((char *)&pSMBr->hdr.Protocol
2609 + data_offset);
2610 if ((char *)reparse_buf >= end_of_smb) {
2611 rc = -EIO;
2612 goto qreparse_out;
2614 if ((reparse_buf->LinkNamesBuf +
2615 reparse_buf->TargetNameOffset +
2616 reparse_buf->TargetNameLen) > end_of_smb) {
2617 cFYI(1, "reparse buf beyond SMB");
2618 rc = -EIO;
2619 goto qreparse_out;
2622 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2623 cifs_from_ucs2(symlinkinfo, (__le16 *)
2624 (reparse_buf->LinkNamesBuf +
2625 reparse_buf->TargetNameOffset),
2626 buflen,
2627 reparse_buf->TargetNameLen,
2628 nls_codepage, 0);
2629 } else { /* ASCII names */
2630 strncpy(symlinkinfo,
2631 reparse_buf->LinkNamesBuf +
2632 reparse_buf->TargetNameOffset,
2633 min_t(const int, buflen,
2634 reparse_buf->TargetNameLen));
2636 } else {
2637 rc = -EIO;
2638 cFYI(1, "Invalid return data count on "
2639 "get reparse info ioctl");
2641 symlinkinfo[buflen] = 0; /* just in case so the caller
2642 does not go off the end of the buffer */
2643 cFYI(1, "readlink result - %s", symlinkinfo);
2646 qreparse_out:
2647 cifs_buf_release(pSMB);
2649 /* Note: On -EAGAIN error only caller can retry on handle based calls
2650 since file handle passed in no longer valid */
2652 return rc;
2654 #endif /* CIFS_EXPERIMENTAL */
2656 #ifdef CONFIG_CIFS_POSIX
2658 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2659 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2660 struct cifs_posix_ace *cifs_ace)
2662 /* u8 cifs fields do not need le conversion */
2663 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2664 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2665 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2666 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
2668 return;
2671 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2672 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2673 const int acl_type, const int size_of_data_area)
2675 int size = 0;
2676 int i;
2677 __u16 count;
2678 struct cifs_posix_ace *pACE;
2679 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2680 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2682 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2683 return -EOPNOTSUPP;
2685 if (acl_type & ACL_TYPE_ACCESS) {
2686 count = le16_to_cpu(cifs_acl->access_entry_count);
2687 pACE = &cifs_acl->ace_array[0];
2688 size = sizeof(struct cifs_posix_acl);
2689 size += sizeof(struct cifs_posix_ace) * count;
2690 /* check if we would go beyond end of SMB */
2691 if (size_of_data_area < size) {
2692 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2693 size_of_data_area, size);
2694 return -EINVAL;
2696 } else if (acl_type & ACL_TYPE_DEFAULT) {
2697 count = le16_to_cpu(cifs_acl->access_entry_count);
2698 size = sizeof(struct cifs_posix_acl);
2699 size += sizeof(struct cifs_posix_ace) * count;
2700 /* skip past access ACEs to get to default ACEs */
2701 pACE = &cifs_acl->ace_array[count];
2702 count = le16_to_cpu(cifs_acl->default_entry_count);
2703 size += sizeof(struct cifs_posix_ace) * count;
2704 /* check if we would go beyond end of SMB */
2705 if (size_of_data_area < size)
2706 return -EINVAL;
2707 } else {
2708 /* illegal type */
2709 return -EINVAL;
2712 size = posix_acl_xattr_size(count);
2713 if ((buflen == 0) || (local_acl == NULL)) {
2714 /* used to query ACL EA size */
2715 } else if (size > buflen) {
2716 return -ERANGE;
2717 } else /* buffer big enough */ {
2718 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2719 for (i = 0; i < count ; i++) {
2720 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2721 pACE++;
2724 return size;
2727 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2728 const posix_acl_xattr_entry *local_ace)
2730 __u16 rc = 0; /* 0 = ACL converted ok */
2732 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2733 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2734 /* BB is there a better way to handle the large uid? */
2735 if (local_ace->e_id == cpu_to_le32(-1)) {
2736 /* Probably no need to le convert -1 on any arch but can not hurt */
2737 cifs_ace->cifs_uid = cpu_to_le64(-1);
2738 } else
2739 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2740 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
2741 return rc;
2744 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2745 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2746 const int buflen, const int acl_type)
2748 __u16 rc = 0;
2749 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2750 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2751 int count;
2752 int i;
2754 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2755 return 0;
2757 count = posix_acl_xattr_count((size_t)buflen);
2758 cFYI(1, "setting acl with %d entries from buf of length %d and "
2759 "version of %d",
2760 count, buflen, le32_to_cpu(local_acl->a_version));
2761 if (le32_to_cpu(local_acl->a_version) != 2) {
2762 cFYI(1, "unknown POSIX ACL version %d",
2763 le32_to_cpu(local_acl->a_version));
2764 return 0;
2766 cifs_acl->version = cpu_to_le16(1);
2767 if (acl_type == ACL_TYPE_ACCESS)
2768 cifs_acl->access_entry_count = cpu_to_le16(count);
2769 else if (acl_type == ACL_TYPE_DEFAULT)
2770 cifs_acl->default_entry_count = cpu_to_le16(count);
2771 else {
2772 cFYI(1, "unknown ACL type %d", acl_type);
2773 return 0;
2775 for (i = 0; i < count; i++) {
2776 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2777 &local_acl->a_entries[i]);
2778 if (rc != 0) {
2779 /* ACE not converted */
2780 break;
2783 if (rc == 0) {
2784 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2785 rc += sizeof(struct cifs_posix_acl);
2786 /* BB add check to make sure ACL does not overflow SMB */
2788 return rc;
2792 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2793 const unsigned char *searchName,
2794 char *acl_inf, const int buflen, const int acl_type,
2795 const struct nls_table *nls_codepage, int remap)
2797 /* SMB_QUERY_POSIX_ACL */
2798 TRANSACTION2_QPI_REQ *pSMB = NULL;
2799 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2800 int rc = 0;
2801 int bytes_returned;
2802 int name_len;
2803 __u16 params, byte_count;
2805 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
2807 queryAclRetry:
2808 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2809 (void **) &pSMBr);
2810 if (rc)
2811 return rc;
2813 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2814 name_len =
2815 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2816 PATH_MAX, nls_codepage, remap);
2817 name_len++; /* trailing null */
2818 name_len *= 2;
2819 pSMB->FileName[name_len] = 0;
2820 pSMB->FileName[name_len+1] = 0;
2821 } else { /* BB improve the check for buffer overruns BB */
2822 name_len = strnlen(searchName, PATH_MAX);
2823 name_len++; /* trailing null */
2824 strncpy(pSMB->FileName, searchName, name_len);
2827 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2828 pSMB->TotalDataCount = 0;
2829 pSMB->MaxParameterCount = cpu_to_le16(2);
2830 /* BB find exact max data count below from sess structure BB */
2831 pSMB->MaxDataCount = cpu_to_le16(4000);
2832 pSMB->MaxSetupCount = 0;
2833 pSMB->Reserved = 0;
2834 pSMB->Flags = 0;
2835 pSMB->Timeout = 0;
2836 pSMB->Reserved2 = 0;
2837 pSMB->ParameterOffset = cpu_to_le16(
2838 offsetof(struct smb_com_transaction2_qpi_req,
2839 InformationLevel) - 4);
2840 pSMB->DataCount = 0;
2841 pSMB->DataOffset = 0;
2842 pSMB->SetupCount = 1;
2843 pSMB->Reserved3 = 0;
2844 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2845 byte_count = params + 1 /* pad */ ;
2846 pSMB->TotalParameterCount = cpu_to_le16(params);
2847 pSMB->ParameterCount = pSMB->TotalParameterCount;
2848 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2849 pSMB->Reserved4 = 0;
2850 pSMB->hdr.smb_buf_length += byte_count;
2851 pSMB->ByteCount = cpu_to_le16(byte_count);
2853 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2854 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2855 cifs_stats_inc(&tcon->num_acl_get);
2856 if (rc) {
2857 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
2858 } else {
2859 /* decode response */
2861 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2862 if (rc || (pSMBr->ByteCount < 2))
2863 /* BB also check enough total bytes returned */
2864 rc = -EIO; /* bad smb */
2865 else {
2866 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2867 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2868 rc = cifs_copy_posix_acl(acl_inf,
2869 (char *)&pSMBr->hdr.Protocol+data_offset,
2870 buflen, acl_type, count);
2873 cifs_buf_release(pSMB);
2874 if (rc == -EAGAIN)
2875 goto queryAclRetry;
2876 return rc;
2880 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2881 const unsigned char *fileName,
2882 const char *local_acl, const int buflen,
2883 const int acl_type,
2884 const struct nls_table *nls_codepage, int remap)
2886 struct smb_com_transaction2_spi_req *pSMB = NULL;
2887 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2888 char *parm_data;
2889 int name_len;
2890 int rc = 0;
2891 int bytes_returned = 0;
2892 __u16 params, byte_count, data_count, param_offset, offset;
2894 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
2895 setAclRetry:
2896 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2897 (void **) &pSMBr);
2898 if (rc)
2899 return rc;
2900 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2901 name_len =
2902 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2903 PATH_MAX, nls_codepage, remap);
2904 name_len++; /* trailing null */
2905 name_len *= 2;
2906 } else { /* BB improve the check for buffer overruns BB */
2907 name_len = strnlen(fileName, PATH_MAX);
2908 name_len++; /* trailing null */
2909 strncpy(pSMB->FileName, fileName, name_len);
2911 params = 6 + name_len;
2912 pSMB->MaxParameterCount = cpu_to_le16(2);
2913 /* BB find max SMB size from sess */
2914 pSMB->MaxDataCount = cpu_to_le16(1000);
2915 pSMB->MaxSetupCount = 0;
2916 pSMB->Reserved = 0;
2917 pSMB->Flags = 0;
2918 pSMB->Timeout = 0;
2919 pSMB->Reserved2 = 0;
2920 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2921 InformationLevel) - 4;
2922 offset = param_offset + params;
2923 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2924 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2926 /* convert to on the wire format for POSIX ACL */
2927 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2929 if (data_count == 0) {
2930 rc = -EOPNOTSUPP;
2931 goto setACLerrorExit;
2933 pSMB->DataOffset = cpu_to_le16(offset);
2934 pSMB->SetupCount = 1;
2935 pSMB->Reserved3 = 0;
2936 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2937 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2938 byte_count = 3 /* pad */ + params + data_count;
2939 pSMB->DataCount = cpu_to_le16(data_count);
2940 pSMB->TotalDataCount = pSMB->DataCount;
2941 pSMB->ParameterCount = cpu_to_le16(params);
2942 pSMB->TotalParameterCount = pSMB->ParameterCount;
2943 pSMB->Reserved4 = 0;
2944 pSMB->hdr.smb_buf_length += byte_count;
2945 pSMB->ByteCount = cpu_to_le16(byte_count);
2946 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2947 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2948 if (rc)
2949 cFYI(1, "Set POSIX ACL returned %d", rc);
2951 setACLerrorExit:
2952 cifs_buf_release(pSMB);
2953 if (rc == -EAGAIN)
2954 goto setAclRetry;
2955 return rc;
2959 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2960 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2962 int rc = 0;
2963 struct smb_t2_qfi_req *pSMB = NULL;
2964 struct smb_t2_qfi_rsp *pSMBr = NULL;
2965 int bytes_returned;
2966 __u16 params, byte_count;
2968 cFYI(1, "In GetExtAttr");
2969 if (tcon == NULL)
2970 return -ENODEV;
2972 GetExtAttrRetry:
2973 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2974 (void **) &pSMBr);
2975 if (rc)
2976 return rc;
2978 params = 2 /* level */ + 2 /* fid */;
2979 pSMB->t2.TotalDataCount = 0;
2980 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2981 /* BB find exact max data count below from sess structure BB */
2982 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2983 pSMB->t2.MaxSetupCount = 0;
2984 pSMB->t2.Reserved = 0;
2985 pSMB->t2.Flags = 0;
2986 pSMB->t2.Timeout = 0;
2987 pSMB->t2.Reserved2 = 0;
2988 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2989 Fid) - 4);
2990 pSMB->t2.DataCount = 0;
2991 pSMB->t2.DataOffset = 0;
2992 pSMB->t2.SetupCount = 1;
2993 pSMB->t2.Reserved3 = 0;
2994 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2995 byte_count = params + 1 /* pad */ ;
2996 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2997 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2998 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2999 pSMB->Pad = 0;
3000 pSMB->Fid = netfid;
3001 pSMB->hdr.smb_buf_length += byte_count;
3002 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3004 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3005 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3006 if (rc) {
3007 cFYI(1, "error %d in GetExtAttr", rc);
3008 } else {
3009 /* decode response */
3010 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3011 if (rc || (pSMBr->ByteCount < 2))
3012 /* BB also check enough total bytes returned */
3013 /* If rc should we check for EOPNOSUPP and
3014 disable the srvino flag? or in caller? */
3015 rc = -EIO; /* bad smb */
3016 else {
3017 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3018 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3019 struct file_chattr_info *pfinfo;
3020 /* BB Do we need a cast or hash here ? */
3021 if (count != 16) {
3022 cFYI(1, "Illegal size ret in GetExtAttr");
3023 rc = -EIO;
3024 goto GetExtAttrOut;
3026 pfinfo = (struct file_chattr_info *)
3027 (data_offset + (char *) &pSMBr->hdr.Protocol);
3028 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3029 *pMask = le64_to_cpu(pfinfo->mask);
3032 GetExtAttrOut:
3033 cifs_buf_release(pSMB);
3034 if (rc == -EAGAIN)
3035 goto GetExtAttrRetry;
3036 return rc;
3039 #endif /* CONFIG_POSIX */
3041 #ifdef CONFIG_CIFS_EXPERIMENTAL
3042 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3044 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3045 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3047 int rc = 0;
3048 int buf_type = 0;
3049 QUERY_SEC_DESC_REQ *pSMB;
3050 struct kvec iov[1];
3052 cFYI(1, "GetCifsACL");
3054 *pbuflen = 0;
3055 *acl_inf = NULL;
3057 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3058 8 /* parm len */, tcon, (void **) &pSMB);
3059 if (rc)
3060 return rc;
3062 pSMB->MaxParameterCount = cpu_to_le32(4);
3063 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3064 pSMB->MaxSetupCount = 0;
3065 pSMB->Fid = fid; /* file handle always le */
3066 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3067 CIFS_ACL_DACL);
3068 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3069 pSMB->hdr.smb_buf_length += 11;
3070 iov[0].iov_base = (char *)pSMB;
3071 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3073 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3074 CIFS_STD_OP);
3075 cifs_stats_inc(&tcon->num_acl_get);
3076 if (rc) {
3077 cFYI(1, "Send error in QuerySecDesc = %d", rc);
3078 } else { /* decode response */
3079 __le32 *parm;
3080 __u32 parm_len;
3081 __u32 acl_len;
3082 struct smb_com_ntransact_rsp *pSMBr;
3083 char *pdata;
3085 /* validate_nttransact */
3086 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3087 &pdata, &parm_len, pbuflen);
3088 if (rc)
3089 goto qsec_out;
3090 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3092 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
3094 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3095 rc = -EIO; /* bad smb */
3096 *pbuflen = 0;
3097 goto qsec_out;
3100 /* BB check that data area is minimum length and as big as acl_len */
3102 acl_len = le32_to_cpu(*parm);
3103 if (acl_len != *pbuflen) {
3104 cERROR(1, "acl length %d does not match %d",
3105 acl_len, *pbuflen);
3106 if (*pbuflen > acl_len)
3107 *pbuflen = acl_len;
3110 /* check if buffer is big enough for the acl
3111 header followed by the smallest SID */
3112 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3113 (*pbuflen >= 64 * 1024)) {
3114 cERROR(1, "bad acl length %d", *pbuflen);
3115 rc = -EINVAL;
3116 *pbuflen = 0;
3117 } else {
3118 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3119 if (*acl_inf == NULL) {
3120 *pbuflen = 0;
3121 rc = -ENOMEM;
3123 memcpy(*acl_inf, pdata, *pbuflen);
3126 qsec_out:
3127 if (buf_type == CIFS_SMALL_BUFFER)
3128 cifs_small_buf_release(iov[0].iov_base);
3129 else if (buf_type == CIFS_LARGE_BUFFER)
3130 cifs_buf_release(iov[0].iov_base);
3131 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3132 return rc;
3136 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3137 struct cifs_ntsd *pntsd, __u32 acllen)
3139 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3140 int rc = 0;
3141 int bytes_returned = 0;
3142 SET_SEC_DESC_REQ *pSMB = NULL;
3143 NTRANSACT_RSP *pSMBr = NULL;
3145 setCifsAclRetry:
3146 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3147 (void **) &pSMBr);
3148 if (rc)
3149 return (rc);
3151 pSMB->MaxSetupCount = 0;
3152 pSMB->Reserved = 0;
3154 param_count = 8;
3155 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3156 data_count = acllen;
3157 data_offset = param_offset + param_count;
3158 byte_count = 3 /* pad */ + param_count;
3160 pSMB->DataCount = cpu_to_le32(data_count);
3161 pSMB->TotalDataCount = pSMB->DataCount;
3162 pSMB->MaxParameterCount = cpu_to_le32(4);
3163 pSMB->MaxDataCount = cpu_to_le32(16384);
3164 pSMB->ParameterCount = cpu_to_le32(param_count);
3165 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3166 pSMB->TotalParameterCount = pSMB->ParameterCount;
3167 pSMB->DataOffset = cpu_to_le32(data_offset);
3168 pSMB->SetupCount = 0;
3169 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3170 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3172 pSMB->Fid = fid; /* file handle always le */
3173 pSMB->Reserved2 = 0;
3174 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3176 if (pntsd && acllen) {
3177 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3178 (char *) pntsd,
3179 acllen);
3180 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3182 } else
3183 pSMB->hdr.smb_buf_length += byte_count;
3185 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3186 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3188 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
3189 if (rc)
3190 cFYI(1, "Set CIFS ACL returned %d", rc);
3191 cifs_buf_release(pSMB);
3193 if (rc == -EAGAIN)
3194 goto setCifsAclRetry;
3196 return (rc);
3199 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3201 /* Legacy Query Path Information call for lookup to old servers such
3202 as Win9x/WinME */
3203 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3204 const unsigned char *searchName,
3205 FILE_ALL_INFO *pFinfo,
3206 const struct nls_table *nls_codepage, int remap)
3208 QUERY_INFORMATION_REQ *pSMB;
3209 QUERY_INFORMATION_RSP *pSMBr;
3210 int rc = 0;
3211 int bytes_returned;
3212 int name_len;
3214 cFYI(1, "In SMBQPath path %s", searchName);
3215 QInfRetry:
3216 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3217 (void **) &pSMBr);
3218 if (rc)
3219 return rc;
3221 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3222 name_len =
3223 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3224 PATH_MAX, nls_codepage, remap);
3225 name_len++; /* trailing null */
3226 name_len *= 2;
3227 } else {
3228 name_len = strnlen(searchName, PATH_MAX);
3229 name_len++; /* trailing null */
3230 strncpy(pSMB->FileName, searchName, name_len);
3232 pSMB->BufferFormat = 0x04;
3233 name_len++; /* account for buffer type byte */
3234 pSMB->hdr.smb_buf_length += (__u16) name_len;
3235 pSMB->ByteCount = cpu_to_le16(name_len);
3237 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3238 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3239 if (rc) {
3240 cFYI(1, "Send error in QueryInfo = %d", rc);
3241 } else if (pFinfo) {
3242 struct timespec ts;
3243 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3245 /* decode response */
3246 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3247 ts.tv_nsec = 0;
3248 ts.tv_sec = time;
3249 /* decode time fields */
3250 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3251 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3252 pFinfo->LastAccessTime = 0;
3253 pFinfo->AllocationSize =
3254 cpu_to_le64(le32_to_cpu(pSMBr->size));
3255 pFinfo->EndOfFile = pFinfo->AllocationSize;
3256 pFinfo->Attributes =
3257 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3258 } else
3259 rc = -EIO; /* bad buffer passed in */
3261 cifs_buf_release(pSMB);
3263 if (rc == -EAGAIN)
3264 goto QInfRetry;
3266 return rc;
3270 CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3271 u16 netfid, FILE_ALL_INFO *pFindData)
3273 struct smb_t2_qfi_req *pSMB = NULL;
3274 struct smb_t2_qfi_rsp *pSMBr = NULL;
3275 int rc = 0;
3276 int bytes_returned;
3277 __u16 params, byte_count;
3279 QFileInfoRetry:
3280 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3281 (void **) &pSMBr);
3282 if (rc)
3283 return rc;
3285 params = 2 /* level */ + 2 /* fid */;
3286 pSMB->t2.TotalDataCount = 0;
3287 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3288 /* BB find exact max data count below from sess structure BB */
3289 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3290 pSMB->t2.MaxSetupCount = 0;
3291 pSMB->t2.Reserved = 0;
3292 pSMB->t2.Flags = 0;
3293 pSMB->t2.Timeout = 0;
3294 pSMB->t2.Reserved2 = 0;
3295 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3296 Fid) - 4);
3297 pSMB->t2.DataCount = 0;
3298 pSMB->t2.DataOffset = 0;
3299 pSMB->t2.SetupCount = 1;
3300 pSMB->t2.Reserved3 = 0;
3301 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3302 byte_count = params + 1 /* pad */ ;
3303 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3304 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3305 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3306 pSMB->Pad = 0;
3307 pSMB->Fid = netfid;
3308 pSMB->hdr.smb_buf_length += byte_count;
3310 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3311 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3312 if (rc) {
3313 cFYI(1, "Send error in QPathInfo = %d", rc);
3314 } else { /* decode response */
3315 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3317 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3318 rc = -EIO;
3319 else if (pSMBr->ByteCount < 40)
3320 rc = -EIO; /* bad smb */
3321 else if (pFindData) {
3322 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3323 memcpy((char *) pFindData,
3324 (char *) &pSMBr->hdr.Protocol +
3325 data_offset, sizeof(FILE_ALL_INFO));
3326 } else
3327 rc = -ENOMEM;
3329 cifs_buf_release(pSMB);
3330 if (rc == -EAGAIN)
3331 goto QFileInfoRetry;
3333 return rc;
3337 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3338 const unsigned char *searchName,
3339 FILE_ALL_INFO *pFindData,
3340 int legacy /* old style infolevel */,
3341 const struct nls_table *nls_codepage, int remap)
3343 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3344 TRANSACTION2_QPI_REQ *pSMB = NULL;
3345 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3346 int rc = 0;
3347 int bytes_returned;
3348 int name_len;
3349 __u16 params, byte_count;
3351 /* cFYI(1, "In QPathInfo path %s", searchName); */
3352 QPathInfoRetry:
3353 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3354 (void **) &pSMBr);
3355 if (rc)
3356 return rc;
3358 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3359 name_len =
3360 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3361 PATH_MAX, nls_codepage, remap);
3362 name_len++; /* trailing null */
3363 name_len *= 2;
3364 } else { /* BB improve the check for buffer overruns BB */
3365 name_len = strnlen(searchName, PATH_MAX);
3366 name_len++; /* trailing null */
3367 strncpy(pSMB->FileName, searchName, name_len);
3370 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3371 pSMB->TotalDataCount = 0;
3372 pSMB->MaxParameterCount = cpu_to_le16(2);
3373 /* BB find exact max SMB PDU from sess structure BB */
3374 pSMB->MaxDataCount = cpu_to_le16(4000);
3375 pSMB->MaxSetupCount = 0;
3376 pSMB->Reserved = 0;
3377 pSMB->Flags = 0;
3378 pSMB->Timeout = 0;
3379 pSMB->Reserved2 = 0;
3380 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3381 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3382 pSMB->DataCount = 0;
3383 pSMB->DataOffset = 0;
3384 pSMB->SetupCount = 1;
3385 pSMB->Reserved3 = 0;
3386 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3387 byte_count = params + 1 /* pad */ ;
3388 pSMB->TotalParameterCount = cpu_to_le16(params);
3389 pSMB->ParameterCount = pSMB->TotalParameterCount;
3390 if (legacy)
3391 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3392 else
3393 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3394 pSMB->Reserved4 = 0;
3395 pSMB->hdr.smb_buf_length += byte_count;
3396 pSMB->ByteCount = cpu_to_le16(byte_count);
3398 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3399 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3400 if (rc) {
3401 cFYI(1, "Send error in QPathInfo = %d", rc);
3402 } else { /* decode response */
3403 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3405 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3406 rc = -EIO;
3407 else if (!legacy && (pSMBr->ByteCount < 40))
3408 rc = -EIO; /* bad smb */
3409 else if (legacy && (pSMBr->ByteCount < 24))
3410 rc = -EIO; /* 24 or 26 expected but we do not read
3411 last field */
3412 else if (pFindData) {
3413 int size;
3414 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3416 /* On legacy responses we do not read the last field,
3417 EAsize, fortunately since it varies by subdialect and
3418 also note it differs on Set vs. Get, ie two bytes or 4
3419 bytes depending but we don't care here */
3420 if (legacy)
3421 size = sizeof(FILE_INFO_STANDARD);
3422 else
3423 size = sizeof(FILE_ALL_INFO);
3424 memcpy((char *) pFindData,
3425 (char *) &pSMBr->hdr.Protocol +
3426 data_offset, size);
3427 } else
3428 rc = -ENOMEM;
3430 cifs_buf_release(pSMB);
3431 if (rc == -EAGAIN)
3432 goto QPathInfoRetry;
3434 return rc;
3438 CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3439 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3441 struct smb_t2_qfi_req *pSMB = NULL;
3442 struct smb_t2_qfi_rsp *pSMBr = NULL;
3443 int rc = 0;
3444 int bytes_returned;
3445 __u16 params, byte_count;
3447 UnixQFileInfoRetry:
3448 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3449 (void **) &pSMBr);
3450 if (rc)
3451 return rc;
3453 params = 2 /* level */ + 2 /* fid */;
3454 pSMB->t2.TotalDataCount = 0;
3455 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3456 /* BB find exact max data count below from sess structure BB */
3457 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3458 pSMB->t2.MaxSetupCount = 0;
3459 pSMB->t2.Reserved = 0;
3460 pSMB->t2.Flags = 0;
3461 pSMB->t2.Timeout = 0;
3462 pSMB->t2.Reserved2 = 0;
3463 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3464 Fid) - 4);
3465 pSMB->t2.DataCount = 0;
3466 pSMB->t2.DataOffset = 0;
3467 pSMB->t2.SetupCount = 1;
3468 pSMB->t2.Reserved3 = 0;
3469 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3470 byte_count = params + 1 /* pad */ ;
3471 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3472 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3473 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3474 pSMB->Pad = 0;
3475 pSMB->Fid = netfid;
3476 pSMB->hdr.smb_buf_length += byte_count;
3478 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3479 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3480 if (rc) {
3481 cFYI(1, "Send error in QPathInfo = %d", rc);
3482 } else { /* decode response */
3483 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3485 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3486 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
3487 "Unix Extensions can be disabled on mount "
3488 "by specifying the nosfu mount option.");
3489 rc = -EIO; /* bad smb */
3490 } else {
3491 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3492 memcpy((char *) pFindData,
3493 (char *) &pSMBr->hdr.Protocol +
3494 data_offset,
3495 sizeof(FILE_UNIX_BASIC_INFO));
3499 cifs_buf_release(pSMB);
3500 if (rc == -EAGAIN)
3501 goto UnixQFileInfoRetry;
3503 return rc;
3507 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3508 const unsigned char *searchName,
3509 FILE_UNIX_BASIC_INFO *pFindData,
3510 const struct nls_table *nls_codepage, int remap)
3512 /* SMB_QUERY_FILE_UNIX_BASIC */
3513 TRANSACTION2_QPI_REQ *pSMB = NULL;
3514 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3515 int rc = 0;
3516 int bytes_returned = 0;
3517 int name_len;
3518 __u16 params, byte_count;
3520 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
3521 UnixQPathInfoRetry:
3522 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3523 (void **) &pSMBr);
3524 if (rc)
3525 return rc;
3527 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3528 name_len =
3529 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3530 PATH_MAX, nls_codepage, remap);
3531 name_len++; /* trailing null */
3532 name_len *= 2;
3533 } else { /* BB improve the check for buffer overruns BB */
3534 name_len = strnlen(searchName, PATH_MAX);
3535 name_len++; /* trailing null */
3536 strncpy(pSMB->FileName, searchName, name_len);
3539 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3540 pSMB->TotalDataCount = 0;
3541 pSMB->MaxParameterCount = cpu_to_le16(2);
3542 /* BB find exact max SMB PDU from sess structure BB */
3543 pSMB->MaxDataCount = cpu_to_le16(4000);
3544 pSMB->MaxSetupCount = 0;
3545 pSMB->Reserved = 0;
3546 pSMB->Flags = 0;
3547 pSMB->Timeout = 0;
3548 pSMB->Reserved2 = 0;
3549 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3550 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3551 pSMB->DataCount = 0;
3552 pSMB->DataOffset = 0;
3553 pSMB->SetupCount = 1;
3554 pSMB->Reserved3 = 0;
3555 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3556 byte_count = params + 1 /* pad */ ;
3557 pSMB->TotalParameterCount = cpu_to_le16(params);
3558 pSMB->ParameterCount = pSMB->TotalParameterCount;
3559 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3560 pSMB->Reserved4 = 0;
3561 pSMB->hdr.smb_buf_length += byte_count;
3562 pSMB->ByteCount = cpu_to_le16(byte_count);
3564 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3565 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3566 if (rc) {
3567 cFYI(1, "Send error in QPathInfo = %d", rc);
3568 } else { /* decode response */
3569 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3571 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3572 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
3573 "Unix Extensions can be disabled on mount "
3574 "by specifying the nosfu mount option.");
3575 rc = -EIO; /* bad smb */
3576 } else {
3577 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3578 memcpy((char *) pFindData,
3579 (char *) &pSMBr->hdr.Protocol +
3580 data_offset,
3581 sizeof(FILE_UNIX_BASIC_INFO));
3584 cifs_buf_release(pSMB);
3585 if (rc == -EAGAIN)
3586 goto UnixQPathInfoRetry;
3588 return rc;
3591 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3593 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3594 const char *searchName,
3595 const struct nls_table *nls_codepage,
3596 __u16 *pnetfid,
3597 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3599 /* level 257 SMB_ */
3600 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3601 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3602 T2_FFIRST_RSP_PARMS *parms;
3603 int rc = 0;
3604 int bytes_returned = 0;
3605 int name_len;
3606 __u16 params, byte_count;
3608 cFYI(1, "In FindFirst for %s", searchName);
3610 findFirstRetry:
3611 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3612 (void **) &pSMBr);
3613 if (rc)
3614 return rc;
3616 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3617 name_len =
3618 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3619 PATH_MAX, nls_codepage, remap);
3620 /* We can not add the asterik earlier in case
3621 it got remapped to 0xF03A as if it were part of the
3622 directory name instead of a wildcard */
3623 name_len *= 2;
3624 pSMB->FileName[name_len] = dirsep;
3625 pSMB->FileName[name_len+1] = 0;
3626 pSMB->FileName[name_len+2] = '*';
3627 pSMB->FileName[name_len+3] = 0;
3628 name_len += 4; /* now the trailing null */
3629 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3630 pSMB->FileName[name_len+1] = 0;
3631 name_len += 2;
3632 } else { /* BB add check for overrun of SMB buf BB */
3633 name_len = strnlen(searchName, PATH_MAX);
3634 /* BB fix here and in unicode clause above ie
3635 if (name_len > buffersize-header)
3636 free buffer exit; BB */
3637 strncpy(pSMB->FileName, searchName, name_len);
3638 pSMB->FileName[name_len] = dirsep;
3639 pSMB->FileName[name_len+1] = '*';
3640 pSMB->FileName[name_len+2] = 0;
3641 name_len += 3;
3644 params = 12 + name_len /* includes null */ ;
3645 pSMB->TotalDataCount = 0; /* no EAs */
3646 pSMB->MaxParameterCount = cpu_to_le16(10);
3647 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3648 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3649 pSMB->MaxSetupCount = 0;
3650 pSMB->Reserved = 0;
3651 pSMB->Flags = 0;
3652 pSMB->Timeout = 0;
3653 pSMB->Reserved2 = 0;
3654 byte_count = params + 1 /* pad */ ;
3655 pSMB->TotalParameterCount = cpu_to_le16(params);
3656 pSMB->ParameterCount = pSMB->TotalParameterCount;
3657 pSMB->ParameterOffset = cpu_to_le16(
3658 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3659 - 4);
3660 pSMB->DataCount = 0;
3661 pSMB->DataOffset = 0;
3662 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3663 pSMB->Reserved3 = 0;
3664 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3665 pSMB->SearchAttributes =
3666 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3667 ATTR_DIRECTORY);
3668 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3669 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3670 CIFS_SEARCH_RETURN_RESUME);
3671 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3673 /* BB what should we set StorageType to? Does it matter? BB */
3674 pSMB->SearchStorageType = 0;
3675 pSMB->hdr.smb_buf_length += byte_count;
3676 pSMB->ByteCount = cpu_to_le16(byte_count);
3678 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3679 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3680 cifs_stats_inc(&tcon->num_ffirst);
3682 if (rc) {/* BB add logic to retry regular search if Unix search
3683 rejected unexpectedly by server */
3684 /* BB Add code to handle unsupported level rc */
3685 cFYI(1, "Error in FindFirst = %d", rc);
3687 cifs_buf_release(pSMB);
3689 /* BB eventually could optimize out free and realloc of buf */
3690 /* for this case */
3691 if (rc == -EAGAIN)
3692 goto findFirstRetry;
3693 } else { /* decode response */
3694 /* BB remember to free buffer if error BB */
3695 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3696 if (rc == 0) {
3697 unsigned int lnoff;
3699 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3700 psrch_inf->unicode = true;
3701 else
3702 psrch_inf->unicode = false;
3704 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3705 psrch_inf->smallBuf = 0;
3706 psrch_inf->srch_entries_start =
3707 (char *) &pSMBr->hdr.Protocol +
3708 le16_to_cpu(pSMBr->t2.DataOffset);
3709 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3710 le16_to_cpu(pSMBr->t2.ParameterOffset));
3712 if (parms->EndofSearch)
3713 psrch_inf->endOfSearch = true;
3714 else
3715 psrch_inf->endOfSearch = false;
3717 psrch_inf->entries_in_buffer =
3718 le16_to_cpu(parms->SearchCount);
3719 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3720 psrch_inf->entries_in_buffer;
3721 lnoff = le16_to_cpu(parms->LastNameOffset);
3722 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3723 lnoff) {
3724 cERROR(1, "ignoring corrupt resume name");
3725 psrch_inf->last_entry = NULL;
3726 return rc;
3729 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3730 lnoff;
3732 *pnetfid = parms->SearchHandle;
3733 } else {
3734 cifs_buf_release(pSMB);
3738 return rc;
3741 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3742 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3744 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3745 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3746 T2_FNEXT_RSP_PARMS *parms;
3747 char *response_data;
3748 int rc = 0;
3749 int bytes_returned, name_len;
3750 __u16 params, byte_count;
3752 cFYI(1, "In FindNext");
3754 if (psrch_inf->endOfSearch)
3755 return -ENOENT;
3757 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3758 (void **) &pSMBr);
3759 if (rc)
3760 return rc;
3762 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3763 byte_count = 0;
3764 pSMB->TotalDataCount = 0; /* no EAs */
3765 pSMB->MaxParameterCount = cpu_to_le16(8);
3766 pSMB->MaxDataCount =
3767 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3768 0xFFFFFF00);
3769 pSMB->MaxSetupCount = 0;
3770 pSMB->Reserved = 0;
3771 pSMB->Flags = 0;
3772 pSMB->Timeout = 0;
3773 pSMB->Reserved2 = 0;
3774 pSMB->ParameterOffset = cpu_to_le16(
3775 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3776 pSMB->DataCount = 0;
3777 pSMB->DataOffset = 0;
3778 pSMB->SetupCount = 1;
3779 pSMB->Reserved3 = 0;
3780 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3781 pSMB->SearchHandle = searchHandle; /* always kept as le */
3782 pSMB->SearchCount =
3783 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3784 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3785 pSMB->ResumeKey = psrch_inf->resume_key;
3786 pSMB->SearchFlags =
3787 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3789 name_len = psrch_inf->resume_name_len;
3790 params += name_len;
3791 if (name_len < PATH_MAX) {
3792 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3793 byte_count += name_len;
3794 /* 14 byte parm len above enough for 2 byte null terminator */
3795 pSMB->ResumeFileName[name_len] = 0;
3796 pSMB->ResumeFileName[name_len+1] = 0;
3797 } else {
3798 rc = -EINVAL;
3799 goto FNext2_err_exit;
3801 byte_count = params + 1 /* pad */ ;
3802 pSMB->TotalParameterCount = cpu_to_le16(params);
3803 pSMB->ParameterCount = pSMB->TotalParameterCount;
3804 pSMB->hdr.smb_buf_length += byte_count;
3805 pSMB->ByteCount = cpu_to_le16(byte_count);
3807 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3808 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3809 cifs_stats_inc(&tcon->num_fnext);
3810 if (rc) {
3811 if (rc == -EBADF) {
3812 psrch_inf->endOfSearch = true;
3813 cifs_buf_release(pSMB);
3814 rc = 0; /* search probably was closed at end of search*/
3815 } else
3816 cFYI(1, "FindNext returned = %d", rc);
3817 } else { /* decode response */
3818 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3820 if (rc == 0) {
3821 unsigned int lnoff;
3823 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3824 psrch_inf->unicode = true;
3825 else
3826 psrch_inf->unicode = false;
3827 response_data = (char *) &pSMBr->hdr.Protocol +
3828 le16_to_cpu(pSMBr->t2.ParameterOffset);
3829 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3830 response_data = (char *)&pSMBr->hdr.Protocol +
3831 le16_to_cpu(pSMBr->t2.DataOffset);
3832 if (psrch_inf->smallBuf)
3833 cifs_small_buf_release(
3834 psrch_inf->ntwrk_buf_start);
3835 else
3836 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3837 psrch_inf->srch_entries_start = response_data;
3838 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3839 psrch_inf->smallBuf = 0;
3840 if (parms->EndofSearch)
3841 psrch_inf->endOfSearch = true;
3842 else
3843 psrch_inf->endOfSearch = false;
3844 psrch_inf->entries_in_buffer =
3845 le16_to_cpu(parms->SearchCount);
3846 psrch_inf->index_of_last_entry +=
3847 psrch_inf->entries_in_buffer;
3848 lnoff = le16_to_cpu(parms->LastNameOffset);
3849 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3850 lnoff) {
3851 cERROR(1, "ignoring corrupt resume name");
3852 psrch_inf->last_entry = NULL;
3853 return rc;
3854 } else
3855 psrch_inf->last_entry =
3856 psrch_inf->srch_entries_start + lnoff;
3858 /* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3859 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
3865 /* BB On error, should we leave previous search buf (and count and
3866 last entry fields) intact or free the previous one? */
3868 /* Note: On -EAGAIN error only caller can retry on handle based calls
3869 since file handle passed in no longer valid */
3870 FNext2_err_exit:
3871 if (rc != 0)
3872 cifs_buf_release(pSMB);
3873 return rc;
3877 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3878 const __u16 searchHandle)
3880 int rc = 0;
3881 FINDCLOSE_REQ *pSMB = NULL;
3883 cFYI(1, "In CIFSSMBFindClose");
3884 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3886 /* no sense returning error if session restarted
3887 as file handle has been closed */
3888 if (rc == -EAGAIN)
3889 return 0;
3890 if (rc)
3891 return rc;
3893 pSMB->FileID = searchHandle;
3894 pSMB->ByteCount = 0;
3895 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3896 if (rc)
3897 cERROR(1, "Send error in FindClose = %d", rc);
3899 cifs_stats_inc(&tcon->num_fclose);
3901 /* Since session is dead, search handle closed on server already */
3902 if (rc == -EAGAIN)
3903 rc = 0;
3905 return rc;
3909 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3910 const unsigned char *searchName,
3911 __u64 *inode_number,
3912 const struct nls_table *nls_codepage, int remap)
3914 int rc = 0;
3915 TRANSACTION2_QPI_REQ *pSMB = NULL;
3916 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3917 int name_len, bytes_returned;
3918 __u16 params, byte_count;
3920 cFYI(1, "In GetSrvInodeNum for %s", searchName);
3921 if (tcon == NULL)
3922 return -ENODEV;
3924 GetInodeNumberRetry:
3925 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3926 (void **) &pSMBr);
3927 if (rc)
3928 return rc;
3930 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3931 name_len =
3932 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3933 PATH_MAX, nls_codepage, remap);
3934 name_len++; /* trailing null */
3935 name_len *= 2;
3936 } else { /* BB improve the check for buffer overruns BB */
3937 name_len = strnlen(searchName, PATH_MAX);
3938 name_len++; /* trailing null */
3939 strncpy(pSMB->FileName, searchName, name_len);
3942 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3943 pSMB->TotalDataCount = 0;
3944 pSMB->MaxParameterCount = cpu_to_le16(2);
3945 /* BB find exact max data count below from sess structure BB */
3946 pSMB->MaxDataCount = cpu_to_le16(4000);
3947 pSMB->MaxSetupCount = 0;
3948 pSMB->Reserved = 0;
3949 pSMB->Flags = 0;
3950 pSMB->Timeout = 0;
3951 pSMB->Reserved2 = 0;
3952 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3953 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3954 pSMB->DataCount = 0;
3955 pSMB->DataOffset = 0;
3956 pSMB->SetupCount = 1;
3957 pSMB->Reserved3 = 0;
3958 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3959 byte_count = params + 1 /* pad */ ;
3960 pSMB->TotalParameterCount = cpu_to_le16(params);
3961 pSMB->ParameterCount = pSMB->TotalParameterCount;
3962 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3963 pSMB->Reserved4 = 0;
3964 pSMB->hdr.smb_buf_length += byte_count;
3965 pSMB->ByteCount = cpu_to_le16(byte_count);
3967 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3968 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3969 if (rc) {
3970 cFYI(1, "error %d in QueryInternalInfo", rc);
3971 } else {
3972 /* decode response */
3973 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3974 if (rc || (pSMBr->ByteCount < 2))
3975 /* BB also check enough total bytes returned */
3976 /* If rc should we check for EOPNOSUPP and
3977 disable the srvino flag? or in caller? */
3978 rc = -EIO; /* bad smb */
3979 else {
3980 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3981 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3982 struct file_internal_info *pfinfo;
3983 /* BB Do we need a cast or hash here ? */
3984 if (count < 8) {
3985 cFYI(1, "Illegal size ret in QryIntrnlInf");
3986 rc = -EIO;
3987 goto GetInodeNumOut;
3989 pfinfo = (struct file_internal_info *)
3990 (data_offset + (char *) &pSMBr->hdr.Protocol);
3991 *inode_number = le64_to_cpu(pfinfo->UniqueId);
3994 GetInodeNumOut:
3995 cifs_buf_release(pSMB);
3996 if (rc == -EAGAIN)
3997 goto GetInodeNumberRetry;
3998 return rc;
4001 /* parses DFS refferal V3 structure
4002 * caller is responsible for freeing target_nodes
4003 * returns:
4004 * on success - 0
4005 * on failure - errno
4007 static int
4008 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
4009 unsigned int *num_of_nodes,
4010 struct dfs_info3_param **target_nodes,
4011 const struct nls_table *nls_codepage, int remap,
4012 const char *searchName)
4014 int i, rc = 0;
4015 char *data_end;
4016 bool is_unicode;
4017 struct dfs_referral_level_3 *ref;
4019 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4020 is_unicode = true;
4021 else
4022 is_unicode = false;
4023 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4025 if (*num_of_nodes < 1) {
4026 cERROR(1, "num_referrals: must be at least > 0,"
4027 "but we get num_referrals = %d\n", *num_of_nodes);
4028 rc = -EINVAL;
4029 goto parse_DFS_referrals_exit;
4032 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
4033 if (ref->VersionNumber != cpu_to_le16(3)) {
4034 cERROR(1, "Referrals of V%d version are not supported,"
4035 "should be V3", le16_to_cpu(ref->VersionNumber));
4036 rc = -EINVAL;
4037 goto parse_DFS_referrals_exit;
4040 /* get the upper boundary of the resp buffer */
4041 data_end = (char *)(&(pSMBr->PathConsumed)) +
4042 le16_to_cpu(pSMBr->t2.DataCount);
4044 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
4045 *num_of_nodes,
4046 le32_to_cpu(pSMBr->DFSFlags));
4048 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4049 *num_of_nodes, GFP_KERNEL);
4050 if (*target_nodes == NULL) {
4051 cERROR(1, "Failed to allocate buffer for target_nodes\n");
4052 rc = -ENOMEM;
4053 goto parse_DFS_referrals_exit;
4056 /* collect necessary data from referrals */
4057 for (i = 0; i < *num_of_nodes; i++) {
4058 char *temp;
4059 int max_len;
4060 struct dfs_info3_param *node = (*target_nodes)+i;
4062 node->flags = le32_to_cpu(pSMBr->DFSFlags);
4063 if (is_unicode) {
4064 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4065 GFP_KERNEL);
4066 if (tmp == NULL) {
4067 rc = -ENOMEM;
4068 goto parse_DFS_referrals_exit;
4070 cifsConvertToUCS((__le16 *) tmp, searchName,
4071 PATH_MAX, nls_codepage, remap);
4072 node->path_consumed = cifs_ucs2_bytes(tmp,
4073 le16_to_cpu(pSMBr->PathConsumed),
4074 nls_codepage);
4075 kfree(tmp);
4076 } else
4077 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4079 node->server_type = le16_to_cpu(ref->ServerType);
4080 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4082 /* copy DfsPath */
4083 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4084 max_len = data_end - temp;
4085 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4086 is_unicode, nls_codepage);
4087 if (!node->path_name) {
4088 rc = -ENOMEM;
4089 goto parse_DFS_referrals_exit;
4092 /* copy link target UNC */
4093 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4094 max_len = data_end - temp;
4095 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4096 is_unicode, nls_codepage);
4097 if (!node->node_name)
4098 rc = -ENOMEM;
4101 parse_DFS_referrals_exit:
4102 if (rc) {
4103 free_dfs_info_array(*target_nodes, *num_of_nodes);
4104 *target_nodes = NULL;
4105 *num_of_nodes = 0;
4107 return rc;
4111 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4112 const unsigned char *searchName,
4113 struct dfs_info3_param **target_nodes,
4114 unsigned int *num_of_nodes,
4115 const struct nls_table *nls_codepage, int remap)
4117 /* TRANS2_GET_DFS_REFERRAL */
4118 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4119 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4120 int rc = 0;
4121 int bytes_returned;
4122 int name_len;
4123 __u16 params, byte_count;
4124 *num_of_nodes = 0;
4125 *target_nodes = NULL;
4127 cFYI(1, "In GetDFSRefer the path %s", searchName);
4128 if (ses == NULL)
4129 return -ENODEV;
4130 getDFSRetry:
4131 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4132 (void **) &pSMBr);
4133 if (rc)
4134 return rc;
4136 /* server pointer checked in called function,
4137 but should never be null here anyway */
4138 pSMB->hdr.Mid = GetNextMid(ses->server);
4139 pSMB->hdr.Tid = ses->ipc_tid;
4140 pSMB->hdr.Uid = ses->Suid;
4141 if (ses->capabilities & CAP_STATUS32)
4142 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4143 if (ses->capabilities & CAP_DFS)
4144 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4146 if (ses->capabilities & CAP_UNICODE) {
4147 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4148 name_len =
4149 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4150 searchName, PATH_MAX, nls_codepage, remap);
4151 name_len++; /* trailing null */
4152 name_len *= 2;
4153 } else { /* BB improve the check for buffer overruns BB */
4154 name_len = strnlen(searchName, PATH_MAX);
4155 name_len++; /* trailing null */
4156 strncpy(pSMB->RequestFileName, searchName, name_len);
4159 if (ses->server) {
4160 if (ses->server->secMode &
4161 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4162 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4165 pSMB->hdr.Uid = ses->Suid;
4167 params = 2 /* level */ + name_len /*includes null */ ;
4168 pSMB->TotalDataCount = 0;
4169 pSMB->DataCount = 0;
4170 pSMB->DataOffset = 0;
4171 pSMB->MaxParameterCount = 0;
4172 /* BB find exact max SMB PDU from sess structure BB */
4173 pSMB->MaxDataCount = cpu_to_le16(4000);
4174 pSMB->MaxSetupCount = 0;
4175 pSMB->Reserved = 0;
4176 pSMB->Flags = 0;
4177 pSMB->Timeout = 0;
4178 pSMB->Reserved2 = 0;
4179 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4180 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4181 pSMB->SetupCount = 1;
4182 pSMB->Reserved3 = 0;
4183 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4184 byte_count = params + 3 /* pad */ ;
4185 pSMB->ParameterCount = cpu_to_le16(params);
4186 pSMB->TotalParameterCount = pSMB->ParameterCount;
4187 pSMB->MaxReferralLevel = cpu_to_le16(3);
4188 pSMB->hdr.smb_buf_length += byte_count;
4189 pSMB->ByteCount = cpu_to_le16(byte_count);
4191 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4192 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4193 if (rc) {
4194 cFYI(1, "Send error in GetDFSRefer = %d", rc);
4195 goto GetDFSRefExit;
4197 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4199 /* BB Also check if enough total bytes returned? */
4200 if (rc || (pSMBr->ByteCount < 17)) {
4201 rc = -EIO; /* bad smb */
4202 goto GetDFSRefExit;
4205 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
4206 pSMBr->ByteCount,
4207 le16_to_cpu(pSMBr->t2.DataOffset));
4209 /* parse returned result into more usable form */
4210 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4211 target_nodes, nls_codepage, remap,
4212 searchName);
4214 GetDFSRefExit:
4215 cifs_buf_release(pSMB);
4217 if (rc == -EAGAIN)
4218 goto getDFSRetry;
4220 return rc;
4223 /* Query File System Info such as free space to old servers such as Win 9x */
4225 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4227 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4228 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4229 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4230 FILE_SYSTEM_ALLOC_INFO *response_data;
4231 int rc = 0;
4232 int bytes_returned = 0;
4233 __u16 params, byte_count;
4235 cFYI(1, "OldQFSInfo");
4236 oldQFSInfoRetry:
4237 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4238 (void **) &pSMBr);
4239 if (rc)
4240 return rc;
4242 params = 2; /* level */
4243 pSMB->TotalDataCount = 0;
4244 pSMB->MaxParameterCount = cpu_to_le16(2);
4245 pSMB->MaxDataCount = cpu_to_le16(1000);
4246 pSMB->MaxSetupCount = 0;
4247 pSMB->Reserved = 0;
4248 pSMB->Flags = 0;
4249 pSMB->Timeout = 0;
4250 pSMB->Reserved2 = 0;
4251 byte_count = params + 1 /* pad */ ;
4252 pSMB->TotalParameterCount = cpu_to_le16(params);
4253 pSMB->ParameterCount = pSMB->TotalParameterCount;
4254 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4255 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4256 pSMB->DataCount = 0;
4257 pSMB->DataOffset = 0;
4258 pSMB->SetupCount = 1;
4259 pSMB->Reserved3 = 0;
4260 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4261 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4262 pSMB->hdr.smb_buf_length += byte_count;
4263 pSMB->ByteCount = cpu_to_le16(byte_count);
4265 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4266 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4267 if (rc) {
4268 cFYI(1, "Send error in QFSInfo = %d", rc);
4269 } else { /* decode response */
4270 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4272 if (rc || (pSMBr->ByteCount < 18))
4273 rc = -EIO; /* bad smb */
4274 else {
4275 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4276 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4277 pSMBr->ByteCount, data_offset);
4279 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4280 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4281 FSData->f_bsize =
4282 le16_to_cpu(response_data->BytesPerSector) *
4283 le32_to_cpu(response_data->
4284 SectorsPerAllocationUnit);
4285 FSData->f_blocks =
4286 le32_to_cpu(response_data->TotalAllocationUnits);
4287 FSData->f_bfree = FSData->f_bavail =
4288 le32_to_cpu(response_data->FreeAllocationUnits);
4289 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4290 (unsigned long long)FSData->f_blocks,
4291 (unsigned long long)FSData->f_bfree,
4292 FSData->f_bsize);
4295 cifs_buf_release(pSMB);
4297 if (rc == -EAGAIN)
4298 goto oldQFSInfoRetry;
4300 return rc;
4304 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4306 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4307 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4308 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4309 FILE_SYSTEM_INFO *response_data;
4310 int rc = 0;
4311 int bytes_returned = 0;
4312 __u16 params, byte_count;
4314 cFYI(1, "In QFSInfo");
4315 QFSInfoRetry:
4316 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4317 (void **) &pSMBr);
4318 if (rc)
4319 return rc;
4321 params = 2; /* level */
4322 pSMB->TotalDataCount = 0;
4323 pSMB->MaxParameterCount = cpu_to_le16(2);
4324 pSMB->MaxDataCount = cpu_to_le16(1000);
4325 pSMB->MaxSetupCount = 0;
4326 pSMB->Reserved = 0;
4327 pSMB->Flags = 0;
4328 pSMB->Timeout = 0;
4329 pSMB->Reserved2 = 0;
4330 byte_count = params + 1 /* pad */ ;
4331 pSMB->TotalParameterCount = cpu_to_le16(params);
4332 pSMB->ParameterCount = pSMB->TotalParameterCount;
4333 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4334 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4335 pSMB->DataCount = 0;
4336 pSMB->DataOffset = 0;
4337 pSMB->SetupCount = 1;
4338 pSMB->Reserved3 = 0;
4339 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4340 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4341 pSMB->hdr.smb_buf_length += byte_count;
4342 pSMB->ByteCount = cpu_to_le16(byte_count);
4344 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4345 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4346 if (rc) {
4347 cFYI(1, "Send error in QFSInfo = %d", rc);
4348 } else { /* decode response */
4349 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4351 if (rc || (pSMBr->ByteCount < 24))
4352 rc = -EIO; /* bad smb */
4353 else {
4354 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4356 response_data =
4357 (FILE_SYSTEM_INFO
4358 *) (((char *) &pSMBr->hdr.Protocol) +
4359 data_offset);
4360 FSData->f_bsize =
4361 le32_to_cpu(response_data->BytesPerSector) *
4362 le32_to_cpu(response_data->
4363 SectorsPerAllocationUnit);
4364 FSData->f_blocks =
4365 le64_to_cpu(response_data->TotalAllocationUnits);
4366 FSData->f_bfree = FSData->f_bavail =
4367 le64_to_cpu(response_data->FreeAllocationUnits);
4368 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4369 (unsigned long long)FSData->f_blocks,
4370 (unsigned long long)FSData->f_bfree,
4371 FSData->f_bsize);
4374 cifs_buf_release(pSMB);
4376 if (rc == -EAGAIN)
4377 goto QFSInfoRetry;
4379 return rc;
4383 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4385 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4386 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4387 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4388 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4389 int rc = 0;
4390 int bytes_returned = 0;
4391 __u16 params, byte_count;
4393 cFYI(1, "In QFSAttributeInfo");
4394 QFSAttributeRetry:
4395 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4396 (void **) &pSMBr);
4397 if (rc)
4398 return rc;
4400 params = 2; /* level */
4401 pSMB->TotalDataCount = 0;
4402 pSMB->MaxParameterCount = cpu_to_le16(2);
4403 /* BB find exact max SMB PDU from sess structure BB */
4404 pSMB->MaxDataCount = cpu_to_le16(1000);
4405 pSMB->MaxSetupCount = 0;
4406 pSMB->Reserved = 0;
4407 pSMB->Flags = 0;
4408 pSMB->Timeout = 0;
4409 pSMB->Reserved2 = 0;
4410 byte_count = params + 1 /* pad */ ;
4411 pSMB->TotalParameterCount = cpu_to_le16(params);
4412 pSMB->ParameterCount = pSMB->TotalParameterCount;
4413 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4414 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4415 pSMB->DataCount = 0;
4416 pSMB->DataOffset = 0;
4417 pSMB->SetupCount = 1;
4418 pSMB->Reserved3 = 0;
4419 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4420 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4421 pSMB->hdr.smb_buf_length += byte_count;
4422 pSMB->ByteCount = cpu_to_le16(byte_count);
4424 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4425 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4426 if (rc) {
4427 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
4428 } else { /* decode response */
4429 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4431 if (rc || (pSMBr->ByteCount < 13)) {
4432 /* BB also check if enough bytes returned */
4433 rc = -EIO; /* bad smb */
4434 } else {
4435 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4436 response_data =
4437 (FILE_SYSTEM_ATTRIBUTE_INFO
4438 *) (((char *) &pSMBr->hdr.Protocol) +
4439 data_offset);
4440 memcpy(&tcon->fsAttrInfo, response_data,
4441 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4444 cifs_buf_release(pSMB);
4446 if (rc == -EAGAIN)
4447 goto QFSAttributeRetry;
4449 return rc;
4453 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4455 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4456 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4457 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4458 FILE_SYSTEM_DEVICE_INFO *response_data;
4459 int rc = 0;
4460 int bytes_returned = 0;
4461 __u16 params, byte_count;
4463 cFYI(1, "In QFSDeviceInfo");
4464 QFSDeviceRetry:
4465 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4466 (void **) &pSMBr);
4467 if (rc)
4468 return rc;
4470 params = 2; /* level */
4471 pSMB->TotalDataCount = 0;
4472 pSMB->MaxParameterCount = cpu_to_le16(2);
4473 /* BB find exact max SMB PDU from sess structure BB */
4474 pSMB->MaxDataCount = cpu_to_le16(1000);
4475 pSMB->MaxSetupCount = 0;
4476 pSMB->Reserved = 0;
4477 pSMB->Flags = 0;
4478 pSMB->Timeout = 0;
4479 pSMB->Reserved2 = 0;
4480 byte_count = params + 1 /* pad */ ;
4481 pSMB->TotalParameterCount = cpu_to_le16(params);
4482 pSMB->ParameterCount = pSMB->TotalParameterCount;
4483 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4484 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4486 pSMB->DataCount = 0;
4487 pSMB->DataOffset = 0;
4488 pSMB->SetupCount = 1;
4489 pSMB->Reserved3 = 0;
4490 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4491 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4492 pSMB->hdr.smb_buf_length += byte_count;
4493 pSMB->ByteCount = cpu_to_le16(byte_count);
4495 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4496 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4497 if (rc) {
4498 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
4499 } else { /* decode response */
4500 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4502 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4503 rc = -EIO; /* bad smb */
4504 else {
4505 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4506 response_data =
4507 (FILE_SYSTEM_DEVICE_INFO *)
4508 (((char *) &pSMBr->hdr.Protocol) +
4509 data_offset);
4510 memcpy(&tcon->fsDevInfo, response_data,
4511 sizeof(FILE_SYSTEM_DEVICE_INFO));
4514 cifs_buf_release(pSMB);
4516 if (rc == -EAGAIN)
4517 goto QFSDeviceRetry;
4519 return rc;
4523 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4525 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4526 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4527 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4528 FILE_SYSTEM_UNIX_INFO *response_data;
4529 int rc = 0;
4530 int bytes_returned = 0;
4531 __u16 params, byte_count;
4533 cFYI(1, "In QFSUnixInfo");
4534 QFSUnixRetry:
4535 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4536 (void **) &pSMB, (void **) &pSMBr);
4537 if (rc)
4538 return rc;
4540 params = 2; /* level */
4541 pSMB->TotalDataCount = 0;
4542 pSMB->DataCount = 0;
4543 pSMB->DataOffset = 0;
4544 pSMB->MaxParameterCount = cpu_to_le16(2);
4545 /* BB find exact max SMB PDU from sess structure BB */
4546 pSMB->MaxDataCount = cpu_to_le16(100);
4547 pSMB->MaxSetupCount = 0;
4548 pSMB->Reserved = 0;
4549 pSMB->Flags = 0;
4550 pSMB->Timeout = 0;
4551 pSMB->Reserved2 = 0;
4552 byte_count = params + 1 /* pad */ ;
4553 pSMB->ParameterCount = cpu_to_le16(params);
4554 pSMB->TotalParameterCount = pSMB->ParameterCount;
4555 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4556 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4557 pSMB->SetupCount = 1;
4558 pSMB->Reserved3 = 0;
4559 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4560 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4561 pSMB->hdr.smb_buf_length += byte_count;
4562 pSMB->ByteCount = cpu_to_le16(byte_count);
4564 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4565 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4566 if (rc) {
4567 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
4568 } else { /* decode response */
4569 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4571 if (rc || (pSMBr->ByteCount < 13)) {
4572 rc = -EIO; /* bad smb */
4573 } else {
4574 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4575 response_data =
4576 (FILE_SYSTEM_UNIX_INFO
4577 *) (((char *) &pSMBr->hdr.Protocol) +
4578 data_offset);
4579 memcpy(&tcon->fsUnixInfo, response_data,
4580 sizeof(FILE_SYSTEM_UNIX_INFO));
4583 cifs_buf_release(pSMB);
4585 if (rc == -EAGAIN)
4586 goto QFSUnixRetry;
4589 return rc;
4593 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4595 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4596 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4597 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4598 int rc = 0;
4599 int bytes_returned = 0;
4600 __u16 params, param_offset, offset, byte_count;
4602 cFYI(1, "In SETFSUnixInfo");
4603 SETFSUnixRetry:
4604 /* BB switch to small buf init to save memory */
4605 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4606 (void **) &pSMB, (void **) &pSMBr);
4607 if (rc)
4608 return rc;
4610 params = 4; /* 2 bytes zero followed by info level. */
4611 pSMB->MaxSetupCount = 0;
4612 pSMB->Reserved = 0;
4613 pSMB->Flags = 0;
4614 pSMB->Timeout = 0;
4615 pSMB->Reserved2 = 0;
4616 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4617 - 4;
4618 offset = param_offset + params;
4620 pSMB->MaxParameterCount = cpu_to_le16(4);
4621 /* BB find exact max SMB PDU from sess structure BB */
4622 pSMB->MaxDataCount = cpu_to_le16(100);
4623 pSMB->SetupCount = 1;
4624 pSMB->Reserved3 = 0;
4625 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4626 byte_count = 1 /* pad */ + params + 12;
4628 pSMB->DataCount = cpu_to_le16(12);
4629 pSMB->ParameterCount = cpu_to_le16(params);
4630 pSMB->TotalDataCount = pSMB->DataCount;
4631 pSMB->TotalParameterCount = pSMB->ParameterCount;
4632 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4633 pSMB->DataOffset = cpu_to_le16(offset);
4635 /* Params. */
4636 pSMB->FileNum = 0;
4637 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4639 /* Data. */
4640 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4641 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4642 pSMB->ClientUnixCap = cpu_to_le64(cap);
4644 pSMB->hdr.smb_buf_length += byte_count;
4645 pSMB->ByteCount = cpu_to_le16(byte_count);
4647 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4648 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4649 if (rc) {
4650 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
4651 } else { /* decode response */
4652 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4653 if (rc)
4654 rc = -EIO; /* bad smb */
4656 cifs_buf_release(pSMB);
4658 if (rc == -EAGAIN)
4659 goto SETFSUnixRetry;
4661 return rc;
4667 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4668 struct kstatfs *FSData)
4670 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4671 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4672 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4673 FILE_SYSTEM_POSIX_INFO *response_data;
4674 int rc = 0;
4675 int bytes_returned = 0;
4676 __u16 params, byte_count;
4678 cFYI(1, "In QFSPosixInfo");
4679 QFSPosixRetry:
4680 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4681 (void **) &pSMBr);
4682 if (rc)
4683 return rc;
4685 params = 2; /* level */
4686 pSMB->TotalDataCount = 0;
4687 pSMB->DataCount = 0;
4688 pSMB->DataOffset = 0;
4689 pSMB->MaxParameterCount = cpu_to_le16(2);
4690 /* BB find exact max SMB PDU from sess structure BB */
4691 pSMB->MaxDataCount = cpu_to_le16(100);
4692 pSMB->MaxSetupCount = 0;
4693 pSMB->Reserved = 0;
4694 pSMB->Flags = 0;
4695 pSMB->Timeout = 0;
4696 pSMB->Reserved2 = 0;
4697 byte_count = params + 1 /* pad */ ;
4698 pSMB->ParameterCount = cpu_to_le16(params);
4699 pSMB->TotalParameterCount = pSMB->ParameterCount;
4700 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4701 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4702 pSMB->SetupCount = 1;
4703 pSMB->Reserved3 = 0;
4704 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4705 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4706 pSMB->hdr.smb_buf_length += byte_count;
4707 pSMB->ByteCount = cpu_to_le16(byte_count);
4709 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4710 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4711 if (rc) {
4712 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
4713 } else { /* decode response */
4714 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4716 if (rc || (pSMBr->ByteCount < 13)) {
4717 rc = -EIO; /* bad smb */
4718 } else {
4719 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4720 response_data =
4721 (FILE_SYSTEM_POSIX_INFO
4722 *) (((char *) &pSMBr->hdr.Protocol) +
4723 data_offset);
4724 FSData->f_bsize =
4725 le32_to_cpu(response_data->BlockSize);
4726 FSData->f_blocks =
4727 le64_to_cpu(response_data->TotalBlocks);
4728 FSData->f_bfree =
4729 le64_to_cpu(response_data->BlocksAvail);
4730 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4731 FSData->f_bavail = FSData->f_bfree;
4732 } else {
4733 FSData->f_bavail =
4734 le64_to_cpu(response_data->UserBlocksAvail);
4736 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4737 FSData->f_files =
4738 le64_to_cpu(response_data->TotalFileNodes);
4739 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4740 FSData->f_ffree =
4741 le64_to_cpu(response_data->FreeFileNodes);
4744 cifs_buf_release(pSMB);
4746 if (rc == -EAGAIN)
4747 goto QFSPosixRetry;
4749 return rc;
4755 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4756 __u64 size, bool SetAllocation,
4757 const struct nls_table *nls_codepage, int remap)
4759 struct smb_com_transaction2_spi_req *pSMB = NULL;
4760 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4761 struct file_end_of_file_info *parm_data;
4762 int name_len;
4763 int rc = 0;
4764 int bytes_returned = 0;
4765 __u16 params, byte_count, data_count, param_offset, offset;
4767 cFYI(1, "In SetEOF");
4768 SetEOFRetry:
4769 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4770 (void **) &pSMBr);
4771 if (rc)
4772 return rc;
4774 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4775 name_len =
4776 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4777 PATH_MAX, nls_codepage, remap);
4778 name_len++; /* trailing null */
4779 name_len *= 2;
4780 } else { /* BB improve the check for buffer overruns BB */
4781 name_len = strnlen(fileName, PATH_MAX);
4782 name_len++; /* trailing null */
4783 strncpy(pSMB->FileName, fileName, name_len);
4785 params = 6 + name_len;
4786 data_count = sizeof(struct file_end_of_file_info);
4787 pSMB->MaxParameterCount = cpu_to_le16(2);
4788 pSMB->MaxDataCount = cpu_to_le16(4100);
4789 pSMB->MaxSetupCount = 0;
4790 pSMB->Reserved = 0;
4791 pSMB->Flags = 0;
4792 pSMB->Timeout = 0;
4793 pSMB->Reserved2 = 0;
4794 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4795 InformationLevel) - 4;
4796 offset = param_offset + params;
4797 if (SetAllocation) {
4798 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4799 pSMB->InformationLevel =
4800 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4801 else
4802 pSMB->InformationLevel =
4803 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4804 } else /* Set File Size */ {
4805 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4806 pSMB->InformationLevel =
4807 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4808 else
4809 pSMB->InformationLevel =
4810 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4813 parm_data =
4814 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4815 offset);
4816 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4817 pSMB->DataOffset = cpu_to_le16(offset);
4818 pSMB->SetupCount = 1;
4819 pSMB->Reserved3 = 0;
4820 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4821 byte_count = 3 /* pad */ + params + data_count;
4822 pSMB->DataCount = cpu_to_le16(data_count);
4823 pSMB->TotalDataCount = pSMB->DataCount;
4824 pSMB->ParameterCount = cpu_to_le16(params);
4825 pSMB->TotalParameterCount = pSMB->ParameterCount;
4826 pSMB->Reserved4 = 0;
4827 pSMB->hdr.smb_buf_length += byte_count;
4828 parm_data->FileSize = cpu_to_le64(size);
4829 pSMB->ByteCount = cpu_to_le16(byte_count);
4830 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4831 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4832 if (rc)
4833 cFYI(1, "SetPathInfo (file size) returned %d", rc);
4835 cifs_buf_release(pSMB);
4837 if (rc == -EAGAIN)
4838 goto SetEOFRetry;
4840 return rc;
4844 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4845 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4847 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4848 char *data_offset;
4849 struct file_end_of_file_info *parm_data;
4850 int rc = 0;
4851 __u16 params, param_offset, offset, byte_count, count;
4853 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4854 (long long)size);
4855 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4857 if (rc)
4858 return rc;
4860 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4861 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4863 params = 6;
4864 pSMB->MaxSetupCount = 0;
4865 pSMB->Reserved = 0;
4866 pSMB->Flags = 0;
4867 pSMB->Timeout = 0;
4868 pSMB->Reserved2 = 0;
4869 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4870 offset = param_offset + params;
4872 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4874 count = sizeof(struct file_end_of_file_info);
4875 pSMB->MaxParameterCount = cpu_to_le16(2);
4876 /* BB find exact max SMB PDU from sess structure BB */
4877 pSMB->MaxDataCount = cpu_to_le16(1000);
4878 pSMB->SetupCount = 1;
4879 pSMB->Reserved3 = 0;
4880 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4881 byte_count = 3 /* pad */ + params + count;
4882 pSMB->DataCount = cpu_to_le16(count);
4883 pSMB->ParameterCount = cpu_to_le16(params);
4884 pSMB->TotalDataCount = pSMB->DataCount;
4885 pSMB->TotalParameterCount = pSMB->ParameterCount;
4886 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4887 parm_data =
4888 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4889 + offset);
4890 pSMB->DataOffset = cpu_to_le16(offset);
4891 parm_data->FileSize = cpu_to_le64(size);
4892 pSMB->Fid = fid;
4893 if (SetAllocation) {
4894 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4895 pSMB->InformationLevel =
4896 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4897 else
4898 pSMB->InformationLevel =
4899 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4900 } else /* Set File Size */ {
4901 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4902 pSMB->InformationLevel =
4903 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4904 else
4905 pSMB->InformationLevel =
4906 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4908 pSMB->Reserved4 = 0;
4909 pSMB->hdr.smb_buf_length += byte_count;
4910 pSMB->ByteCount = cpu_to_le16(byte_count);
4911 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4912 if (rc) {
4913 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
4916 /* Note: On -EAGAIN error only caller can retry on handle based calls
4917 since file handle passed in no longer valid */
4919 return rc;
4922 /* Some legacy servers such as NT4 require that the file times be set on
4923 an open handle, rather than by pathname - this is awkward due to
4924 potential access conflicts on the open, but it is unavoidable for these
4925 old servers since the only other choice is to go from 100 nanosecond DCE
4926 time and resort to the original setpathinfo level which takes the ancient
4927 DOS time format with 2 second granularity */
4929 CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4930 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4932 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4933 char *data_offset;
4934 int rc = 0;
4935 __u16 params, param_offset, offset, byte_count, count;
4937 cFYI(1, "Set Times (via SetFileInfo)");
4938 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4940 if (rc)
4941 return rc;
4943 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4944 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4946 params = 6;
4947 pSMB->MaxSetupCount = 0;
4948 pSMB->Reserved = 0;
4949 pSMB->Flags = 0;
4950 pSMB->Timeout = 0;
4951 pSMB->Reserved2 = 0;
4952 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4953 offset = param_offset + params;
4955 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4957 count = sizeof(FILE_BASIC_INFO);
4958 pSMB->MaxParameterCount = cpu_to_le16(2);
4959 /* BB find max SMB PDU from sess */
4960 pSMB->MaxDataCount = cpu_to_le16(1000);
4961 pSMB->SetupCount = 1;
4962 pSMB->Reserved3 = 0;
4963 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4964 byte_count = 3 /* pad */ + params + count;
4965 pSMB->DataCount = cpu_to_le16(count);
4966 pSMB->ParameterCount = cpu_to_le16(params);
4967 pSMB->TotalDataCount = pSMB->DataCount;
4968 pSMB->TotalParameterCount = pSMB->ParameterCount;
4969 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4970 pSMB->DataOffset = cpu_to_le16(offset);
4971 pSMB->Fid = fid;
4972 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4973 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4974 else
4975 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4976 pSMB->Reserved4 = 0;
4977 pSMB->hdr.smb_buf_length += byte_count;
4978 pSMB->ByteCount = cpu_to_le16(byte_count);
4979 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4980 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4981 if (rc)
4982 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
4984 /* Note: On -EAGAIN error only caller can retry on handle based calls
4985 since file handle passed in no longer valid */
4987 return rc;
4991 CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4992 bool delete_file, __u16 fid, __u32 pid_of_opener)
4994 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4995 char *data_offset;
4996 int rc = 0;
4997 __u16 params, param_offset, offset, byte_count, count;
4999 cFYI(1, "Set File Disposition (via SetFileInfo)");
5000 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5002 if (rc)
5003 return rc;
5005 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5006 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5008 params = 6;
5009 pSMB->MaxSetupCount = 0;
5010 pSMB->Reserved = 0;
5011 pSMB->Flags = 0;
5012 pSMB->Timeout = 0;
5013 pSMB->Reserved2 = 0;
5014 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5015 offset = param_offset + params;
5017 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5019 count = 1;
5020 pSMB->MaxParameterCount = cpu_to_le16(2);
5021 /* BB find max SMB PDU from sess */
5022 pSMB->MaxDataCount = cpu_to_le16(1000);
5023 pSMB->SetupCount = 1;
5024 pSMB->Reserved3 = 0;
5025 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5026 byte_count = 3 /* pad */ + params + count;
5027 pSMB->DataCount = cpu_to_le16(count);
5028 pSMB->ParameterCount = cpu_to_le16(params);
5029 pSMB->TotalDataCount = pSMB->DataCount;
5030 pSMB->TotalParameterCount = pSMB->ParameterCount;
5031 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5032 pSMB->DataOffset = cpu_to_le16(offset);
5033 pSMB->Fid = fid;
5034 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5035 pSMB->Reserved4 = 0;
5036 pSMB->hdr.smb_buf_length += byte_count;
5037 pSMB->ByteCount = cpu_to_le16(byte_count);
5038 *data_offset = delete_file ? 1 : 0;
5039 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5040 if (rc)
5041 cFYI(1, "Send error in SetFileDisposition = %d", rc);
5043 return rc;
5047 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5048 const char *fileName, const FILE_BASIC_INFO *data,
5049 const struct nls_table *nls_codepage, int remap)
5051 TRANSACTION2_SPI_REQ *pSMB = NULL;
5052 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5053 int name_len;
5054 int rc = 0;
5055 int bytes_returned = 0;
5056 char *data_offset;
5057 __u16 params, param_offset, offset, byte_count, count;
5059 cFYI(1, "In SetTimes");
5061 SetTimesRetry:
5062 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5063 (void **) &pSMBr);
5064 if (rc)
5065 return rc;
5067 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5068 name_len =
5069 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5070 PATH_MAX, nls_codepage, remap);
5071 name_len++; /* trailing null */
5072 name_len *= 2;
5073 } else { /* BB improve the check for buffer overruns BB */
5074 name_len = strnlen(fileName, PATH_MAX);
5075 name_len++; /* trailing null */
5076 strncpy(pSMB->FileName, fileName, name_len);
5079 params = 6 + name_len;
5080 count = sizeof(FILE_BASIC_INFO);
5081 pSMB->MaxParameterCount = cpu_to_le16(2);
5082 /* BB find max SMB PDU from sess structure BB */
5083 pSMB->MaxDataCount = cpu_to_le16(1000);
5084 pSMB->MaxSetupCount = 0;
5085 pSMB->Reserved = 0;
5086 pSMB->Flags = 0;
5087 pSMB->Timeout = 0;
5088 pSMB->Reserved2 = 0;
5089 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5090 InformationLevel) - 4;
5091 offset = param_offset + params;
5092 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5093 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5094 pSMB->DataOffset = cpu_to_le16(offset);
5095 pSMB->SetupCount = 1;
5096 pSMB->Reserved3 = 0;
5097 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5098 byte_count = 3 /* pad */ + params + count;
5100 pSMB->DataCount = cpu_to_le16(count);
5101 pSMB->ParameterCount = cpu_to_le16(params);
5102 pSMB->TotalDataCount = pSMB->DataCount;
5103 pSMB->TotalParameterCount = pSMB->ParameterCount;
5104 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5105 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5106 else
5107 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5108 pSMB->Reserved4 = 0;
5109 pSMB->hdr.smb_buf_length += byte_count;
5110 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5111 pSMB->ByteCount = cpu_to_le16(byte_count);
5112 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5113 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5114 if (rc)
5115 cFYI(1, "SetPathInfo (times) returned %d", rc);
5117 cifs_buf_release(pSMB);
5119 if (rc == -EAGAIN)
5120 goto SetTimesRetry;
5122 return rc;
5125 /* Can not be used to set time stamps yet (due to old DOS time format) */
5126 /* Can be used to set attributes */
5127 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5128 handling it anyway and NT4 was what we thought it would be needed for
5129 Do not delete it until we prove whether needed for Win9x though */
5131 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5132 __u16 dos_attrs, const struct nls_table *nls_codepage)
5134 SETATTR_REQ *pSMB = NULL;
5135 SETATTR_RSP *pSMBr = NULL;
5136 int rc = 0;
5137 int bytes_returned;
5138 int name_len;
5140 cFYI(1, "In SetAttrLegacy");
5142 SetAttrLgcyRetry:
5143 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5144 (void **) &pSMBr);
5145 if (rc)
5146 return rc;
5148 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5149 name_len =
5150 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
5151 PATH_MAX, nls_codepage);
5152 name_len++; /* trailing null */
5153 name_len *= 2;
5154 } else { /* BB improve the check for buffer overruns BB */
5155 name_len = strnlen(fileName, PATH_MAX);
5156 name_len++; /* trailing null */
5157 strncpy(pSMB->fileName, fileName, name_len);
5159 pSMB->attr = cpu_to_le16(dos_attrs);
5160 pSMB->BufferFormat = 0x04;
5161 pSMB->hdr.smb_buf_length += name_len + 1;
5162 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5163 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5164 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5165 if (rc)
5166 cFYI(1, "Error in LegacySetAttr = %d", rc);
5168 cifs_buf_release(pSMB);
5170 if (rc == -EAGAIN)
5171 goto SetAttrLgcyRetry;
5173 return rc;
5175 #endif /* temporarily unneeded SetAttr legacy function */
5177 static void
5178 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5179 const struct cifs_unix_set_info_args *args)
5181 u64 mode = args->mode;
5184 * Samba server ignores set of file size to zero due to bugs in some
5185 * older clients, but we should be precise - we use SetFileSize to
5186 * set file size and do not want to truncate file size to zero
5187 * accidently as happened on one Samba server beta by putting
5188 * zero instead of -1 here
5190 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5191 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5192 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5193 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5194 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5195 data_offset->Uid = cpu_to_le64(args->uid);
5196 data_offset->Gid = cpu_to_le64(args->gid);
5197 /* better to leave device as zero when it is */
5198 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5199 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5200 data_offset->Permissions = cpu_to_le64(mode);
5202 if (S_ISREG(mode))
5203 data_offset->Type = cpu_to_le32(UNIX_FILE);
5204 else if (S_ISDIR(mode))
5205 data_offset->Type = cpu_to_le32(UNIX_DIR);
5206 else if (S_ISLNK(mode))
5207 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5208 else if (S_ISCHR(mode))
5209 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5210 else if (S_ISBLK(mode))
5211 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5212 else if (S_ISFIFO(mode))
5213 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5214 else if (S_ISSOCK(mode))
5215 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5219 CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5220 const struct cifs_unix_set_info_args *args,
5221 u16 fid, u32 pid_of_opener)
5223 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5224 FILE_UNIX_BASIC_INFO *data_offset;
5225 int rc = 0;
5226 u16 params, param_offset, offset, byte_count, count;
5228 cFYI(1, "Set Unix Info (via SetFileInfo)");
5229 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5231 if (rc)
5232 return rc;
5234 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5235 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5237 params = 6;
5238 pSMB->MaxSetupCount = 0;
5239 pSMB->Reserved = 0;
5240 pSMB->Flags = 0;
5241 pSMB->Timeout = 0;
5242 pSMB->Reserved2 = 0;
5243 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5244 offset = param_offset + params;
5246 data_offset = (FILE_UNIX_BASIC_INFO *)
5247 ((char *)(&pSMB->hdr.Protocol) + offset);
5248 count = sizeof(FILE_UNIX_BASIC_INFO);
5250 pSMB->MaxParameterCount = cpu_to_le16(2);
5251 /* BB find max SMB PDU from sess */
5252 pSMB->MaxDataCount = cpu_to_le16(1000);
5253 pSMB->SetupCount = 1;
5254 pSMB->Reserved3 = 0;
5255 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5256 byte_count = 3 /* pad */ + params + count;
5257 pSMB->DataCount = cpu_to_le16(count);
5258 pSMB->ParameterCount = cpu_to_le16(params);
5259 pSMB->TotalDataCount = pSMB->DataCount;
5260 pSMB->TotalParameterCount = pSMB->ParameterCount;
5261 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5262 pSMB->DataOffset = cpu_to_le16(offset);
5263 pSMB->Fid = fid;
5264 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5265 pSMB->Reserved4 = 0;
5266 pSMB->hdr.smb_buf_length += byte_count;
5267 pSMB->ByteCount = cpu_to_le16(byte_count);
5269 cifs_fill_unix_set_info(data_offset, args);
5271 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5272 if (rc)
5273 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
5275 /* Note: On -EAGAIN error only caller can retry on handle based calls
5276 since file handle passed in no longer valid */
5278 return rc;
5282 CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5283 const struct cifs_unix_set_info_args *args,
5284 const struct nls_table *nls_codepage, int remap)
5286 TRANSACTION2_SPI_REQ *pSMB = NULL;
5287 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5288 int name_len;
5289 int rc = 0;
5290 int bytes_returned = 0;
5291 FILE_UNIX_BASIC_INFO *data_offset;
5292 __u16 params, param_offset, offset, count, byte_count;
5294 cFYI(1, "In SetUID/GID/Mode");
5295 setPermsRetry:
5296 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5297 (void **) &pSMBr);
5298 if (rc)
5299 return rc;
5301 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5302 name_len =
5303 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5304 PATH_MAX, nls_codepage, remap);
5305 name_len++; /* trailing null */
5306 name_len *= 2;
5307 } else { /* BB improve the check for buffer overruns BB */
5308 name_len = strnlen(fileName, PATH_MAX);
5309 name_len++; /* trailing null */
5310 strncpy(pSMB->FileName, fileName, name_len);
5313 params = 6 + name_len;
5314 count = sizeof(FILE_UNIX_BASIC_INFO);
5315 pSMB->MaxParameterCount = cpu_to_le16(2);
5316 /* BB find max SMB PDU from sess structure BB */
5317 pSMB->MaxDataCount = cpu_to_le16(1000);
5318 pSMB->MaxSetupCount = 0;
5319 pSMB->Reserved = 0;
5320 pSMB->Flags = 0;
5321 pSMB->Timeout = 0;
5322 pSMB->Reserved2 = 0;
5323 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5324 InformationLevel) - 4;
5325 offset = param_offset + params;
5326 data_offset =
5327 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5328 offset);
5329 memset(data_offset, 0, count);
5330 pSMB->DataOffset = cpu_to_le16(offset);
5331 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5332 pSMB->SetupCount = 1;
5333 pSMB->Reserved3 = 0;
5334 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5335 byte_count = 3 /* pad */ + params + count;
5336 pSMB->ParameterCount = cpu_to_le16(params);
5337 pSMB->DataCount = cpu_to_le16(count);
5338 pSMB->TotalParameterCount = pSMB->ParameterCount;
5339 pSMB->TotalDataCount = pSMB->DataCount;
5340 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5341 pSMB->Reserved4 = 0;
5342 pSMB->hdr.smb_buf_length += byte_count;
5344 cifs_fill_unix_set_info(data_offset, args);
5346 pSMB->ByteCount = cpu_to_le16(byte_count);
5347 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5348 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5349 if (rc)
5350 cFYI(1, "SetPathInfo (perms) returned %d", rc);
5352 cifs_buf_release(pSMB);
5353 if (rc == -EAGAIN)
5354 goto setPermsRetry;
5355 return rc;
5358 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5359 const int notify_subdirs, const __u16 netfid,
5360 __u32 filter, struct file *pfile, int multishot,
5361 const struct nls_table *nls_codepage)
5363 int rc = 0;
5364 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5365 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5366 struct dir_notify_req *dnotify_req;
5367 int bytes_returned;
5369 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
5370 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5371 (void **) &pSMBr);
5372 if (rc)
5373 return rc;
5375 pSMB->TotalParameterCount = 0 ;
5376 pSMB->TotalDataCount = 0;
5377 pSMB->MaxParameterCount = cpu_to_le32(2);
5378 /* BB find exact data count max from sess structure BB */
5379 pSMB->MaxDataCount = 0; /* same in little endian or be */
5380 /* BB VERIFY verify which is correct for above BB */
5381 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5382 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5384 pSMB->MaxSetupCount = 4;
5385 pSMB->Reserved = 0;
5386 pSMB->ParameterOffset = 0;
5387 pSMB->DataCount = 0;
5388 pSMB->DataOffset = 0;
5389 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5390 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5391 pSMB->ParameterCount = pSMB->TotalParameterCount;
5392 if (notify_subdirs)
5393 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5394 pSMB->Reserved2 = 0;
5395 pSMB->CompletionFilter = cpu_to_le32(filter);
5396 pSMB->Fid = netfid; /* file handle always le */
5397 pSMB->ByteCount = 0;
5399 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5400 (struct smb_hdr *)pSMBr, &bytes_returned,
5401 CIFS_ASYNC_OP);
5402 if (rc) {
5403 cFYI(1, "Error in Notify = %d", rc);
5404 } else {
5405 /* Add file to outstanding requests */
5406 /* BB change to kmem cache alloc */
5407 dnotify_req = kmalloc(
5408 sizeof(struct dir_notify_req),
5409 GFP_KERNEL);
5410 if (dnotify_req) {
5411 dnotify_req->Pid = pSMB->hdr.Pid;
5412 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5413 dnotify_req->Mid = pSMB->hdr.Mid;
5414 dnotify_req->Tid = pSMB->hdr.Tid;
5415 dnotify_req->Uid = pSMB->hdr.Uid;
5416 dnotify_req->netfid = netfid;
5417 dnotify_req->pfile = pfile;
5418 dnotify_req->filter = filter;
5419 dnotify_req->multishot = multishot;
5420 spin_lock(&GlobalMid_Lock);
5421 list_add_tail(&dnotify_req->lhead,
5422 &GlobalDnotifyReqList);
5423 spin_unlock(&GlobalMid_Lock);
5424 } else
5425 rc = -ENOMEM;
5427 cifs_buf_release(pSMB);
5428 return rc;
5431 #ifdef CONFIG_CIFS_XATTR
5433 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5434 * function used by listxattr and getxattr type calls. When ea_name is set,
5435 * it looks for that attribute name and stuffs that value into the EAData
5436 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5437 * buffer. In both cases, the return value is either the length of the
5438 * resulting data or a negative error code. If EAData is a NULL pointer then
5439 * the data isn't copied to it, but the length is returned.
5441 ssize_t
5442 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5443 const unsigned char *searchName, const unsigned char *ea_name,
5444 char *EAData, size_t buf_size,
5445 const struct nls_table *nls_codepage, int remap)
5447 /* BB assumes one setup word */
5448 TRANSACTION2_QPI_REQ *pSMB = NULL;
5449 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5450 int rc = 0;
5451 int bytes_returned;
5452 int list_len;
5453 struct fealist *ea_response_data;
5454 struct fea *temp_fea;
5455 char *temp_ptr;
5456 char *end_of_smb;
5457 __u16 params, byte_count, data_offset;
5459 cFYI(1, "In Query All EAs path %s", searchName);
5460 QAllEAsRetry:
5461 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5462 (void **) &pSMBr);
5463 if (rc)
5464 return rc;
5466 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5467 list_len =
5468 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5469 PATH_MAX, nls_codepage, remap);
5470 list_len++; /* trailing null */
5471 list_len *= 2;
5472 } else { /* BB improve the check for buffer overruns BB */
5473 list_len = strnlen(searchName, PATH_MAX);
5474 list_len++; /* trailing null */
5475 strncpy(pSMB->FileName, searchName, list_len);
5478 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
5479 pSMB->TotalDataCount = 0;
5480 pSMB->MaxParameterCount = cpu_to_le16(2);
5481 /* BB find exact max SMB PDU from sess structure BB */
5482 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
5483 pSMB->MaxSetupCount = 0;
5484 pSMB->Reserved = 0;
5485 pSMB->Flags = 0;
5486 pSMB->Timeout = 0;
5487 pSMB->Reserved2 = 0;
5488 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5489 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5490 pSMB->DataCount = 0;
5491 pSMB->DataOffset = 0;
5492 pSMB->SetupCount = 1;
5493 pSMB->Reserved3 = 0;
5494 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5495 byte_count = params + 1 /* pad */ ;
5496 pSMB->TotalParameterCount = cpu_to_le16(params);
5497 pSMB->ParameterCount = pSMB->TotalParameterCount;
5498 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5499 pSMB->Reserved4 = 0;
5500 pSMB->hdr.smb_buf_length += byte_count;
5501 pSMB->ByteCount = cpu_to_le16(byte_count);
5503 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5504 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5505 if (rc) {
5506 cFYI(1, "Send error in QueryAllEAs = %d", rc);
5507 goto QAllEAsOut;
5511 /* BB also check enough total bytes returned */
5512 /* BB we need to improve the validity checking
5513 of these trans2 responses */
5515 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5516 if (rc || (pSMBr->ByteCount < 4)) {
5517 rc = -EIO; /* bad smb */
5518 goto QAllEAsOut;
5521 /* check that length of list is not more than bcc */
5522 /* check that each entry does not go beyond length
5523 of list */
5524 /* check that each element of each entry does not
5525 go beyond end of list */
5526 /* validate_trans2_offsets() */
5527 /* BB check if start of smb + data_offset > &bcc+ bcc */
5529 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5530 ea_response_data = (struct fealist *)
5531 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5533 list_len = le32_to_cpu(ea_response_data->list_len);
5534 cFYI(1, "ea length %d", list_len);
5535 if (list_len <= 8) {
5536 cFYI(1, "empty EA list returned from server");
5537 goto QAllEAsOut;
5540 /* make sure list_len doesn't go past end of SMB */
5541 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5542 if ((char *)ea_response_data + list_len > end_of_smb) {
5543 cFYI(1, "EA list appears to go beyond SMB");
5544 rc = -EIO;
5545 goto QAllEAsOut;
5548 /* account for ea list len */
5549 list_len -= 4;
5550 temp_fea = ea_response_data->list;
5551 temp_ptr = (char *)temp_fea;
5552 while (list_len > 0) {
5553 unsigned int name_len;
5554 __u16 value_len;
5556 list_len -= 4;
5557 temp_ptr += 4;
5558 /* make sure we can read name_len and value_len */
5559 if (list_len < 0) {
5560 cFYI(1, "EA entry goes beyond length of list");
5561 rc = -EIO;
5562 goto QAllEAsOut;
5565 name_len = temp_fea->name_len;
5566 value_len = le16_to_cpu(temp_fea->value_len);
5567 list_len -= name_len + 1 + value_len;
5568 if (list_len < 0) {
5569 cFYI(1, "EA entry goes beyond length of list");
5570 rc = -EIO;
5571 goto QAllEAsOut;
5574 if (ea_name) {
5575 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5576 temp_ptr += name_len + 1;
5577 rc = value_len;
5578 if (buf_size == 0)
5579 goto QAllEAsOut;
5580 if ((size_t)value_len > buf_size) {
5581 rc = -ERANGE;
5582 goto QAllEAsOut;
5584 memcpy(EAData, temp_ptr, value_len);
5585 goto QAllEAsOut;
5587 } else {
5588 /* account for prefix user. and trailing null */
5589 rc += (5 + 1 + name_len);
5590 if (rc < (int) buf_size) {
5591 memcpy(EAData, "user.", 5);
5592 EAData += 5;
5593 memcpy(EAData, temp_ptr, name_len);
5594 EAData += name_len;
5595 /* null terminate name */
5596 *EAData = 0;
5597 ++EAData;
5598 } else if (buf_size == 0) {
5599 /* skip copy - calc size only */
5600 } else {
5601 /* stop before overrun buffer */
5602 rc = -ERANGE;
5603 break;
5606 temp_ptr += name_len + 1 + value_len;
5607 temp_fea = (struct fea *)temp_ptr;
5610 /* didn't find the named attribute */
5611 if (ea_name)
5612 rc = -ENODATA;
5614 QAllEAsOut:
5615 cifs_buf_release(pSMB);
5616 if (rc == -EAGAIN)
5617 goto QAllEAsRetry;
5619 return (ssize_t)rc;
5623 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5624 const char *ea_name, const void *ea_value,
5625 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5626 int remap)
5628 struct smb_com_transaction2_spi_req *pSMB = NULL;
5629 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5630 struct fealist *parm_data;
5631 int name_len;
5632 int rc = 0;
5633 int bytes_returned = 0;
5634 __u16 params, param_offset, byte_count, offset, count;
5636 cFYI(1, "In SetEA");
5637 SetEARetry:
5638 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5639 (void **) &pSMBr);
5640 if (rc)
5641 return rc;
5643 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5644 name_len =
5645 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5646 PATH_MAX, nls_codepage, remap);
5647 name_len++; /* trailing null */
5648 name_len *= 2;
5649 } else { /* BB improve the check for buffer overruns BB */
5650 name_len = strnlen(fileName, PATH_MAX);
5651 name_len++; /* trailing null */
5652 strncpy(pSMB->FileName, fileName, name_len);
5655 params = 6 + name_len;
5657 /* done calculating parms using name_len of file name,
5658 now use name_len to calculate length of ea name
5659 we are going to create in the inode xattrs */
5660 if (ea_name == NULL)
5661 name_len = 0;
5662 else
5663 name_len = strnlen(ea_name, 255);
5665 count = sizeof(*parm_data) + ea_value_len + name_len;
5666 pSMB->MaxParameterCount = cpu_to_le16(2);
5667 /* BB find max SMB PDU from sess */
5668 pSMB->MaxDataCount = cpu_to_le16(1000);
5669 pSMB->MaxSetupCount = 0;
5670 pSMB->Reserved = 0;
5671 pSMB->Flags = 0;
5672 pSMB->Timeout = 0;
5673 pSMB->Reserved2 = 0;
5674 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5675 InformationLevel) - 4;
5676 offset = param_offset + params;
5677 pSMB->InformationLevel =
5678 cpu_to_le16(SMB_SET_FILE_EA);
5680 parm_data =
5681 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5682 offset);
5683 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5684 pSMB->DataOffset = cpu_to_le16(offset);
5685 pSMB->SetupCount = 1;
5686 pSMB->Reserved3 = 0;
5687 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5688 byte_count = 3 /* pad */ + params + count;
5689 pSMB->DataCount = cpu_to_le16(count);
5690 parm_data->list_len = cpu_to_le32(count);
5691 parm_data->list[0].EA_flags = 0;
5692 /* we checked above that name len is less than 255 */
5693 parm_data->list[0].name_len = (__u8)name_len;
5694 /* EA names are always ASCII */
5695 if (ea_name)
5696 strncpy(parm_data->list[0].name, ea_name, name_len);
5697 parm_data->list[0].name[name_len] = 0;
5698 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5699 /* caller ensures that ea_value_len is less than 64K but
5700 we need to ensure that it fits within the smb */
5702 /*BB add length check to see if it would fit in
5703 negotiated SMB buffer size BB */
5704 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5705 if (ea_value_len)
5706 memcpy(parm_data->list[0].name+name_len+1,
5707 ea_value, ea_value_len);
5709 pSMB->TotalDataCount = pSMB->DataCount;
5710 pSMB->ParameterCount = cpu_to_le16(params);
5711 pSMB->TotalParameterCount = pSMB->ParameterCount;
5712 pSMB->Reserved4 = 0;
5713 pSMB->hdr.smb_buf_length += byte_count;
5714 pSMB->ByteCount = cpu_to_le16(byte_count);
5715 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5716 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5717 if (rc)
5718 cFYI(1, "SetPathInfo (EA) returned %d", rc);
5720 cifs_buf_release(pSMB);
5722 if (rc == -EAGAIN)
5723 goto SetEARetry;
5725 return rc;
5728 #endif