sierra: add new ID for Airprime/Sierra USB IP modem
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / cifs / cifssmb.c
blob0fa5c1f8a8c211ce4f7a21f3e710b883c3b133b3
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 spin_lock(&cifs_file_list_lock);
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 spin_unlock(&cifs_file_list_lock);
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;
194 * FIXME: check if wsize needs updated due to negotiated smb buffer
195 * size shrinking
197 atomic_inc(&tconInfoReconnectCount);
199 /* tell server Unix caps we support */
200 if (ses->capabilities & CAP_UNIX)
201 reset_cifs_unix_caps(0, tcon, NULL, NULL);
204 * Removed call to reopen open files here. It is safer (and faster) to
205 * reopen files one at a time as needed in read and write.
207 * FIXME: what about file locks? don't we need to reclaim them ASAP?
210 out:
212 * Check if handle based operation so we know whether we can continue
213 * or not without returning to caller to reset file handle
215 switch (smb_command) {
216 case SMB_COM_READ_ANDX:
217 case SMB_COM_WRITE_ANDX:
218 case SMB_COM_CLOSE:
219 case SMB_COM_FIND_CLOSE2:
220 case SMB_COM_LOCKING_ANDX:
221 rc = -EAGAIN;
224 unload_nls(nls_codepage);
225 return rc;
228 /* Allocate and return pointer to an SMB request buffer, and set basic
229 SMB information in the SMB header. If the return code is zero, this
230 function must have filled in request_buf pointer */
231 static int
232 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
233 void **request_buf)
235 int rc;
237 rc = cifs_reconnect_tcon(tcon, smb_command);
238 if (rc)
239 return rc;
241 *request_buf = cifs_small_buf_get();
242 if (*request_buf == NULL) {
243 /* BB should we add a retry in here if not a writepage? */
244 return -ENOMEM;
247 header_assemble((struct smb_hdr *) *request_buf, smb_command,
248 tcon, wct);
250 if (tcon != NULL)
251 cifs_stats_inc(&tcon->num_smbs_sent);
253 return 0;
257 small_smb_init_no_tc(const int smb_command, const int wct,
258 struct cifsSesInfo *ses, void **request_buf)
260 int rc;
261 struct smb_hdr *buffer;
263 rc = small_smb_init(smb_command, wct, NULL, request_buf);
264 if (rc)
265 return rc;
267 buffer = (struct smb_hdr *)*request_buf;
268 buffer->Mid = GetNextMid(ses->server);
269 if (ses->capabilities & CAP_UNICODE)
270 buffer->Flags2 |= SMBFLG2_UNICODE;
271 if (ses->capabilities & CAP_STATUS32)
272 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
274 /* uid, tid can stay at zero as set in header assemble */
276 /* BB add support for turning on the signing when
277 this function is used after 1st of session setup requests */
279 return rc;
282 /* If the return code is zero, this function must fill in request_buf pointer */
283 static int
284 __smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
285 void **request_buf, void **response_buf)
287 *request_buf = cifs_buf_get();
288 if (*request_buf == NULL) {
289 /* BB should we add a retry in here if not a writepage? */
290 return -ENOMEM;
292 /* Although the original thought was we needed the response buf for */
293 /* potential retries of smb operations it turns out we can determine */
294 /* from the mid flags when the request buffer can be resent without */
295 /* having to use a second distinct buffer for the response */
296 if (response_buf)
297 *response_buf = *request_buf;
299 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
300 wct);
302 if (tcon != NULL)
303 cifs_stats_inc(&tcon->num_smbs_sent);
305 return 0;
308 /* If the return code is zero, this function must fill in request_buf pointer */
309 static int
310 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
311 void **request_buf, void **response_buf)
313 int rc;
315 rc = cifs_reconnect_tcon(tcon, smb_command);
316 if (rc)
317 return rc;
319 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
322 static int
323 smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
324 void **request_buf, void **response_buf)
326 if (tcon->ses->need_reconnect || tcon->need_reconnect)
327 return -EHOSTDOWN;
329 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
332 static int validate_t2(struct smb_t2_rsp *pSMB)
334 int rc = -EINVAL;
335 int total_size;
336 char *pBCC;
338 /* check for plausible wct, bcc and t2 data and parm sizes */
339 /* check for parm and data offset going beyond end of smb */
340 if (pSMB->hdr.WordCount >= 10) {
341 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
342 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
343 /* check that bcc is at least as big as parms + data */
344 /* check that bcc is less than negotiated smb buffer */
345 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
346 if (total_size < 512) {
347 total_size +=
348 le16_to_cpu(pSMB->t2_rsp.DataCount);
349 /* BCC le converted in SendReceive */
350 pBCC = (pSMB->hdr.WordCount * 2) +
351 sizeof(struct smb_hdr) +
352 (char *)pSMB;
353 if ((total_size <= (*(u16 *)pBCC)) &&
354 (total_size <
355 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
356 return 0;
361 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
362 sizeof(struct smb_t2_rsp) + 16);
363 return rc;
366 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
368 NEGOTIATE_REQ *pSMB;
369 NEGOTIATE_RSP *pSMBr;
370 int rc = 0;
371 int bytes_returned;
372 int i;
373 struct TCP_Server_Info *server;
374 u16 count;
375 unsigned int secFlags;
377 if (ses->server)
378 server = ses->server;
379 else {
380 rc = -EIO;
381 return rc;
383 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
384 (void **) &pSMB, (void **) &pSMBr);
385 if (rc)
386 return rc;
388 /* if any of auth flags (ie not sign or seal) are overriden use them */
389 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
390 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
391 else /* if override flags set only sign/seal OR them with global auth */
392 secFlags = global_secflags | ses->overrideSecFlg;
394 cFYI(1, "secFlags 0x%x", secFlags);
396 pSMB->hdr.Mid = GetNextMid(server);
397 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
399 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
400 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
401 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
402 cFYI(1, "Kerberos only mechanism, enable extended security");
403 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
405 #ifdef CONFIG_CIFS_EXPERIMENTAL
406 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
407 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
408 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
409 cFYI(1, "NTLMSSP only mechanism, enable extended security");
410 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
412 #endif
414 count = 0;
415 for (i = 0; i < CIFS_NUM_PROT; i++) {
416 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
417 count += strlen(protocols[i].name) + 1;
418 /* null at end of source and target buffers anyway */
420 pSMB->hdr.smb_buf_length += count;
421 pSMB->ByteCount = cpu_to_le16(count);
423 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
424 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
425 if (rc != 0)
426 goto neg_err_exit;
428 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
429 cFYI(1, "Dialect: %d", server->dialect);
430 /* Check wct = 1 error case */
431 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
432 /* core returns wct = 1, but we do not ask for core - otherwise
433 small wct just comes when dialect index is -1 indicating we
434 could not negotiate a common dialect */
435 rc = -EOPNOTSUPP;
436 goto neg_err_exit;
437 #ifdef CONFIG_CIFS_WEAK_PW_HASH
438 } else if ((pSMBr->hdr.WordCount == 13)
439 && ((server->dialect == LANMAN_PROT)
440 || (server->dialect == LANMAN2_PROT))) {
441 __s16 tmp;
442 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
444 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
445 (secFlags & CIFSSEC_MAY_PLNTXT))
446 server->secType = LANMAN;
447 else {
448 cERROR(1, "mount failed weak security disabled"
449 " in /proc/fs/cifs/SecurityFlags");
450 rc = -EOPNOTSUPP;
451 goto neg_err_exit;
453 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
454 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
455 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
456 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
457 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
458 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
459 /* even though we do not use raw we might as well set this
460 accurately, in case we ever find a need for it */
461 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
462 server->max_rw = 0xFF00;
463 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
464 } else {
465 server->max_rw = 0;/* do not need to use raw anyway */
466 server->capabilities = CAP_MPX_MODE;
468 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
469 if (tmp == -1) {
470 /* OS/2 often does not set timezone therefore
471 * we must use server time to calc time zone.
472 * Could deviate slightly from the right zone.
473 * Smallest defined timezone difference is 15 minutes
474 * (i.e. Nepal). Rounding up/down is done to match
475 * this requirement.
477 int val, seconds, remain, result;
478 struct timespec ts, utc;
479 utc = CURRENT_TIME;
480 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
481 rsp->SrvTime.Time, 0);
482 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
483 (int)ts.tv_sec, (int)utc.tv_sec,
484 (int)(utc.tv_sec - ts.tv_sec));
485 val = (int)(utc.tv_sec - ts.tv_sec);
486 seconds = abs(val);
487 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
488 remain = seconds % MIN_TZ_ADJ;
489 if (remain >= (MIN_TZ_ADJ / 2))
490 result += MIN_TZ_ADJ;
491 if (val < 0)
492 result = -result;
493 server->timeAdj = result;
494 } else {
495 server->timeAdj = (int)tmp;
496 server->timeAdj *= 60; /* also in seconds */
498 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
501 /* BB get server time for time conversions and add
502 code to use it and timezone since this is not UTC */
504 if (rsp->EncryptionKeyLength ==
505 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
506 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
507 CIFS_CRYPTO_KEY_SIZE);
508 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
509 rc = -EIO; /* need cryptkey unless plain text */
510 goto neg_err_exit;
513 cFYI(1, "LANMAN negotiated");
514 /* we will not end up setting signing flags - as no signing
515 was in LANMAN and server did not return the flags on */
516 goto signing_check;
517 #else /* weak security disabled */
518 } else if (pSMBr->hdr.WordCount == 13) {
519 cERROR(1, "mount failed, cifs module not built "
520 "with CIFS_WEAK_PW_HASH support");
521 rc = -EOPNOTSUPP;
522 #endif /* WEAK_PW_HASH */
523 goto neg_err_exit;
524 } else if (pSMBr->hdr.WordCount != 17) {
525 /* unknown wct */
526 rc = -EOPNOTSUPP;
527 goto neg_err_exit;
529 /* else wct == 17 NTLM */
530 server->secMode = pSMBr->SecurityMode;
531 if ((server->secMode & SECMODE_USER) == 0)
532 cFYI(1, "share mode security");
534 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
535 #ifdef CONFIG_CIFS_WEAK_PW_HASH
536 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
537 #endif /* CIFS_WEAK_PW_HASH */
538 cERROR(1, "Server requests plain text password"
539 " but client support disabled");
541 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
542 server->secType = NTLMv2;
543 else if (secFlags & CIFSSEC_MAY_NTLM)
544 server->secType = NTLM;
545 else if (secFlags & CIFSSEC_MAY_NTLMV2)
546 server->secType = NTLMv2;
547 else if (secFlags & CIFSSEC_MAY_KRB5)
548 server->secType = Kerberos;
549 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
550 server->secType = RawNTLMSSP;
551 else if (secFlags & CIFSSEC_MAY_LANMAN)
552 server->secType = LANMAN;
553 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
554 else if (secFlags & CIFSSEC_MAY_PLNTXT)
555 server->secType = ??
556 #endif */
557 else {
558 rc = -EOPNOTSUPP;
559 cERROR(1, "Invalid security type");
560 goto neg_err_exit;
562 /* else ... any others ...? */
564 /* one byte, so no need to convert this or EncryptionKeyLen from
565 little endian */
566 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
567 /* probably no need to store and check maxvcs */
568 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
569 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
570 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
571 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
572 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
573 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
574 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
575 server->timeAdj *= 60;
576 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
577 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
578 CIFS_CRYPTO_KEY_SIZE);
579 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
580 && (pSMBr->EncryptionKeyLength == 0)) {
581 /* decode security blob */
582 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
583 rc = -EIO; /* no crypt key only if plain text pwd */
584 goto neg_err_exit;
587 /* BB might be helpful to save off the domain of server here */
589 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
590 (server->capabilities & CAP_EXTENDED_SECURITY)) {
591 count = pSMBr->ByteCount;
592 if (count < 16) {
593 rc = -EIO;
594 goto neg_err_exit;
596 spin_lock(&cifs_tcp_ses_lock);
597 if (server->srv_count > 1) {
598 spin_unlock(&cifs_tcp_ses_lock);
599 if (memcmp(server->server_GUID,
600 pSMBr->u.extended_response.
601 GUID, 16) != 0) {
602 cFYI(1, "server UID changed");
603 memcpy(server->server_GUID,
604 pSMBr->u.extended_response.GUID,
605 16);
607 } else {
608 spin_unlock(&cifs_tcp_ses_lock);
609 memcpy(server->server_GUID,
610 pSMBr->u.extended_response.GUID, 16);
613 if (count == 16) {
614 server->secType = RawNTLMSSP;
615 } else {
616 rc = decode_negTokenInit(pSMBr->u.extended_response.
617 SecurityBlob, count - 16,
618 server);
619 if (rc == 1)
620 rc = 0;
621 else
622 rc = -EINVAL;
623 if (server->secType == Kerberos) {
624 if (!server->sec_kerberos &&
625 !server->sec_mskerberos)
626 rc = -EOPNOTSUPP;
627 } else if (server->secType == RawNTLMSSP) {
628 if (!server->sec_ntlmssp)
629 rc = -EOPNOTSUPP;
630 } else
631 rc = -EOPNOTSUPP;
633 } else
634 server->capabilities &= ~CAP_EXTENDED_SECURITY;
636 #ifdef CONFIG_CIFS_WEAK_PW_HASH
637 signing_check:
638 #endif
639 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
640 /* MUST_SIGN already includes the MAY_SIGN FLAG
641 so if this is zero it means that signing is disabled */
642 cFYI(1, "Signing disabled");
643 if (server->secMode & SECMODE_SIGN_REQUIRED) {
644 cERROR(1, "Server requires "
645 "packet signing to be enabled in "
646 "/proc/fs/cifs/SecurityFlags.");
647 rc = -EOPNOTSUPP;
649 server->secMode &=
650 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
651 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
652 /* signing required */
653 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
654 if ((server->secMode &
655 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
656 cERROR(1, "signing required but server lacks support");
657 rc = -EOPNOTSUPP;
658 } else
659 server->secMode |= SECMODE_SIGN_REQUIRED;
660 } else {
661 /* signing optional ie CIFSSEC_MAY_SIGN */
662 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
663 server->secMode &=
664 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
667 neg_err_exit:
668 cifs_buf_release(pSMB);
670 cFYI(1, "negprot rc %d", rc);
671 return rc;
675 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
677 struct smb_hdr *smb_buffer;
678 int rc = 0;
680 cFYI(1, "In tree disconnect");
682 /* BB: do we need to check this? These should never be NULL. */
683 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
684 return -EIO;
687 * No need to return error on this operation if tid invalidated and
688 * closed on server already e.g. due to tcp session crashing. Also,
689 * the tcon is no longer on the list, so no need to take lock before
690 * checking this.
692 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
693 return 0;
695 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
696 (void **)&smb_buffer);
697 if (rc)
698 return rc;
700 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
701 if (rc)
702 cFYI(1, "Tree disconnect failed %d", rc);
704 /* No need to return error on this operation if tid invalidated and
705 closed on server already e.g. due to tcp session crashing */
706 if (rc == -EAGAIN)
707 rc = 0;
709 return rc;
713 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
715 LOGOFF_ANDX_REQ *pSMB;
716 int rc = 0;
718 cFYI(1, "In SMBLogoff for session disconnect");
721 * BB: do we need to check validity of ses and server? They should
722 * always be valid since we have an active reference. If not, that
723 * should probably be a BUG()
725 if (!ses || !ses->server)
726 return -EIO;
728 mutex_lock(&ses->session_mutex);
729 if (ses->need_reconnect)
730 goto session_already_dead; /* no need to send SMBlogoff if uid
731 already closed due to reconnect */
732 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
733 if (rc) {
734 mutex_unlock(&ses->session_mutex);
735 return rc;
738 pSMB->hdr.Mid = GetNextMid(ses->server);
740 if (ses->server->secMode &
741 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
742 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
744 pSMB->hdr.Uid = ses->Suid;
746 pSMB->AndXCommand = 0xFF;
747 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
748 session_already_dead:
749 mutex_unlock(&ses->session_mutex);
751 /* if session dead then we do not need to do ulogoff,
752 since server closed smb session, no sense reporting
753 error */
754 if (rc == -EAGAIN)
755 rc = 0;
756 return rc;
760 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
761 __u16 type, const struct nls_table *nls_codepage, int remap)
763 TRANSACTION2_SPI_REQ *pSMB = NULL;
764 TRANSACTION2_SPI_RSP *pSMBr = NULL;
765 struct unlink_psx_rq *pRqD;
766 int name_len;
767 int rc = 0;
768 int bytes_returned = 0;
769 __u16 params, param_offset, offset, byte_count;
771 cFYI(1, "In POSIX delete");
772 PsxDelete:
773 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
774 (void **) &pSMBr);
775 if (rc)
776 return rc;
778 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
779 name_len =
780 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
781 PATH_MAX, nls_codepage, remap);
782 name_len++; /* trailing null */
783 name_len *= 2;
784 } else { /* BB add path length overrun check */
785 name_len = strnlen(fileName, PATH_MAX);
786 name_len++; /* trailing null */
787 strncpy(pSMB->FileName, fileName, name_len);
790 params = 6 + name_len;
791 pSMB->MaxParameterCount = cpu_to_le16(2);
792 pSMB->MaxDataCount = 0; /* BB double check this with jra */
793 pSMB->MaxSetupCount = 0;
794 pSMB->Reserved = 0;
795 pSMB->Flags = 0;
796 pSMB->Timeout = 0;
797 pSMB->Reserved2 = 0;
798 param_offset = offsetof(struct smb_com_transaction2_spi_req,
799 InformationLevel) - 4;
800 offset = param_offset + params;
802 /* Setup pointer to Request Data (inode type) */
803 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
804 pRqD->type = cpu_to_le16(type);
805 pSMB->ParameterOffset = cpu_to_le16(param_offset);
806 pSMB->DataOffset = cpu_to_le16(offset);
807 pSMB->SetupCount = 1;
808 pSMB->Reserved3 = 0;
809 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
810 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
812 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
813 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
814 pSMB->ParameterCount = cpu_to_le16(params);
815 pSMB->TotalParameterCount = pSMB->ParameterCount;
816 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
817 pSMB->Reserved4 = 0;
818 pSMB->hdr.smb_buf_length += byte_count;
819 pSMB->ByteCount = cpu_to_le16(byte_count);
820 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
821 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
822 if (rc)
823 cFYI(1, "Posix delete returned %d", rc);
824 cifs_buf_release(pSMB);
826 cifs_stats_inc(&tcon->num_deletes);
828 if (rc == -EAGAIN)
829 goto PsxDelete;
831 return rc;
835 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
836 const struct nls_table *nls_codepage, int remap)
838 DELETE_FILE_REQ *pSMB = NULL;
839 DELETE_FILE_RSP *pSMBr = NULL;
840 int rc = 0;
841 int bytes_returned;
842 int name_len;
844 DelFileRetry:
845 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
846 (void **) &pSMBr);
847 if (rc)
848 return rc;
850 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
851 name_len =
852 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
853 PATH_MAX, nls_codepage, remap);
854 name_len++; /* trailing null */
855 name_len *= 2;
856 } else { /* BB improve check for buffer overruns BB */
857 name_len = strnlen(fileName, PATH_MAX);
858 name_len++; /* trailing null */
859 strncpy(pSMB->fileName, fileName, name_len);
861 pSMB->SearchAttributes =
862 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
863 pSMB->BufferFormat = 0x04;
864 pSMB->hdr.smb_buf_length += name_len + 1;
865 pSMB->ByteCount = cpu_to_le16(name_len + 1);
866 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
867 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
868 cifs_stats_inc(&tcon->num_deletes);
869 if (rc)
870 cFYI(1, "Error in RMFile = %d", rc);
872 cifs_buf_release(pSMB);
873 if (rc == -EAGAIN)
874 goto DelFileRetry;
876 return rc;
880 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
881 const struct nls_table *nls_codepage, int remap)
883 DELETE_DIRECTORY_REQ *pSMB = NULL;
884 DELETE_DIRECTORY_RSP *pSMBr = NULL;
885 int rc = 0;
886 int bytes_returned;
887 int name_len;
889 cFYI(1, "In CIFSSMBRmDir");
890 RmDirRetry:
891 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
892 (void **) &pSMBr);
893 if (rc)
894 return rc;
896 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
897 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
898 PATH_MAX, nls_codepage, remap);
899 name_len++; /* trailing null */
900 name_len *= 2;
901 } else { /* BB improve check for buffer overruns BB */
902 name_len = strnlen(dirName, PATH_MAX);
903 name_len++; /* trailing null */
904 strncpy(pSMB->DirName, dirName, name_len);
907 pSMB->BufferFormat = 0x04;
908 pSMB->hdr.smb_buf_length += name_len + 1;
909 pSMB->ByteCount = cpu_to_le16(name_len + 1);
910 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
911 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
912 cifs_stats_inc(&tcon->num_rmdirs);
913 if (rc)
914 cFYI(1, "Error in RMDir = %d", rc);
916 cifs_buf_release(pSMB);
917 if (rc == -EAGAIN)
918 goto RmDirRetry;
919 return rc;
923 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
924 const char *name, const struct nls_table *nls_codepage, int remap)
926 int rc = 0;
927 CREATE_DIRECTORY_REQ *pSMB = NULL;
928 CREATE_DIRECTORY_RSP *pSMBr = NULL;
929 int bytes_returned;
930 int name_len;
932 cFYI(1, "In CIFSSMBMkDir");
933 MkDirRetry:
934 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
935 (void **) &pSMBr);
936 if (rc)
937 return rc;
939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
940 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
941 PATH_MAX, nls_codepage, remap);
942 name_len++; /* trailing null */
943 name_len *= 2;
944 } else { /* BB improve check for buffer overruns BB */
945 name_len = strnlen(name, PATH_MAX);
946 name_len++; /* trailing null */
947 strncpy(pSMB->DirName, name, name_len);
950 pSMB->BufferFormat = 0x04;
951 pSMB->hdr.smb_buf_length += name_len + 1;
952 pSMB->ByteCount = cpu_to_le16(name_len + 1);
953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
955 cifs_stats_inc(&tcon->num_mkdirs);
956 if (rc)
957 cFYI(1, "Error in Mkdir = %d", rc);
959 cifs_buf_release(pSMB);
960 if (rc == -EAGAIN)
961 goto MkDirRetry;
962 return rc;
966 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
967 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
968 __u32 *pOplock, const char *name,
969 const struct nls_table *nls_codepage, int remap)
971 TRANSACTION2_SPI_REQ *pSMB = NULL;
972 TRANSACTION2_SPI_RSP *pSMBr = NULL;
973 int name_len;
974 int rc = 0;
975 int bytes_returned = 0;
976 __u16 params, param_offset, offset, byte_count, count;
977 OPEN_PSX_REQ *pdata;
978 OPEN_PSX_RSP *psx_rsp;
980 cFYI(1, "In POSIX Create");
981 PsxCreat:
982 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
983 (void **) &pSMBr);
984 if (rc)
985 return rc;
987 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
988 name_len =
989 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
990 PATH_MAX, nls_codepage, remap);
991 name_len++; /* trailing null */
992 name_len *= 2;
993 } else { /* BB improve the check for buffer overruns BB */
994 name_len = strnlen(name, PATH_MAX);
995 name_len++; /* trailing null */
996 strncpy(pSMB->FileName, name, name_len);
999 params = 6 + name_len;
1000 count = sizeof(OPEN_PSX_REQ);
1001 pSMB->MaxParameterCount = cpu_to_le16(2);
1002 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1003 pSMB->MaxSetupCount = 0;
1004 pSMB->Reserved = 0;
1005 pSMB->Flags = 0;
1006 pSMB->Timeout = 0;
1007 pSMB->Reserved2 = 0;
1008 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1009 InformationLevel) - 4;
1010 offset = param_offset + params;
1011 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1012 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1013 pdata->Permissions = cpu_to_le64(mode);
1014 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1015 pdata->OpenFlags = cpu_to_le32(*pOplock);
1016 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1017 pSMB->DataOffset = cpu_to_le16(offset);
1018 pSMB->SetupCount = 1;
1019 pSMB->Reserved3 = 0;
1020 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1021 byte_count = 3 /* pad */ + params + count;
1023 pSMB->DataCount = cpu_to_le16(count);
1024 pSMB->ParameterCount = cpu_to_le16(params);
1025 pSMB->TotalDataCount = pSMB->DataCount;
1026 pSMB->TotalParameterCount = pSMB->ParameterCount;
1027 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1028 pSMB->Reserved4 = 0;
1029 pSMB->hdr.smb_buf_length += byte_count;
1030 pSMB->ByteCount = cpu_to_le16(byte_count);
1031 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1032 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1033 if (rc) {
1034 cFYI(1, "Posix create returned %d", rc);
1035 goto psx_create_err;
1038 cFYI(1, "copying inode info");
1039 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1041 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1042 rc = -EIO; /* bad smb */
1043 goto psx_create_err;
1046 /* copy return information to pRetData */
1047 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1048 + le16_to_cpu(pSMBr->t2.DataOffset));
1050 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1051 if (netfid)
1052 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1053 /* Let caller know file was created so we can set the mode. */
1054 /* Do we care about the CreateAction in any other cases? */
1055 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1056 *pOplock |= CIFS_CREATE_ACTION;
1057 /* check to make sure response data is there */
1058 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1059 pRetData->Type = cpu_to_le32(-1); /* unknown */
1060 cFYI(DBG2, "unknown type");
1061 } else {
1062 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1063 + sizeof(FILE_UNIX_BASIC_INFO)) {
1064 cERROR(1, "Open response data too small");
1065 pRetData->Type = cpu_to_le32(-1);
1066 goto psx_create_err;
1068 memcpy((char *) pRetData,
1069 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1070 sizeof(FILE_UNIX_BASIC_INFO));
1073 psx_create_err:
1074 cifs_buf_release(pSMB);
1076 if (posix_flags & SMB_O_DIRECTORY)
1077 cifs_stats_inc(&tcon->num_posixmkdirs);
1078 else
1079 cifs_stats_inc(&tcon->num_posixopens);
1081 if (rc == -EAGAIN)
1082 goto PsxCreat;
1084 return rc;
1087 static __u16 convert_disposition(int disposition)
1089 __u16 ofun = 0;
1091 switch (disposition) {
1092 case FILE_SUPERSEDE:
1093 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1094 break;
1095 case FILE_OPEN:
1096 ofun = SMBOPEN_OAPPEND;
1097 break;
1098 case FILE_CREATE:
1099 ofun = SMBOPEN_OCREATE;
1100 break;
1101 case FILE_OPEN_IF:
1102 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1103 break;
1104 case FILE_OVERWRITE:
1105 ofun = SMBOPEN_OTRUNC;
1106 break;
1107 case FILE_OVERWRITE_IF:
1108 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1109 break;
1110 default:
1111 cFYI(1, "unknown disposition %d", disposition);
1112 ofun = SMBOPEN_OAPPEND; /* regular open */
1114 return ofun;
1117 static int
1118 access_flags_to_smbopen_mode(const int access_flags)
1120 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1122 if (masked_flags == GENERIC_READ)
1123 return SMBOPEN_READ;
1124 else if (masked_flags == GENERIC_WRITE)
1125 return SMBOPEN_WRITE;
1127 /* just go for read/write */
1128 return SMBOPEN_READWRITE;
1132 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1133 const char *fileName, const int openDisposition,
1134 const int access_flags, const int create_options, __u16 *netfid,
1135 int *pOplock, FILE_ALL_INFO *pfile_info,
1136 const struct nls_table *nls_codepage, int remap)
1138 int rc = -EACCES;
1139 OPENX_REQ *pSMB = NULL;
1140 OPENX_RSP *pSMBr = NULL;
1141 int bytes_returned;
1142 int name_len;
1143 __u16 count;
1145 OldOpenRetry:
1146 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1147 (void **) &pSMBr);
1148 if (rc)
1149 return rc;
1151 pSMB->AndXCommand = 0xFF; /* none */
1153 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1154 count = 1; /* account for one byte pad to word boundary */
1155 name_len =
1156 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1157 fileName, PATH_MAX, nls_codepage, remap);
1158 name_len++; /* trailing null */
1159 name_len *= 2;
1160 } else { /* BB improve check for buffer overruns BB */
1161 count = 0; /* no pad */
1162 name_len = strnlen(fileName, PATH_MAX);
1163 name_len++; /* trailing null */
1164 strncpy(pSMB->fileName, fileName, name_len);
1166 if (*pOplock & REQ_OPLOCK)
1167 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1168 else if (*pOplock & REQ_BATCHOPLOCK)
1169 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1171 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1172 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1173 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1174 /* set file as system file if special file such
1175 as fifo and server expecting SFU style and
1176 no Unix extensions */
1178 if (create_options & CREATE_OPTION_SPECIAL)
1179 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1180 else /* BB FIXME BB */
1181 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1183 if (create_options & CREATE_OPTION_READONLY)
1184 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1186 /* BB FIXME BB */
1187 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1188 CREATE_OPTIONS_MASK); */
1189 /* BB FIXME END BB */
1191 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1192 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1193 count += name_len;
1194 pSMB->hdr.smb_buf_length += count;
1196 pSMB->ByteCount = cpu_to_le16(count);
1197 /* long_op set to 1 to allow for oplock break timeouts */
1198 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1199 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1200 cifs_stats_inc(&tcon->num_opens);
1201 if (rc) {
1202 cFYI(1, "Error in Open = %d", rc);
1203 } else {
1204 /* BB verify if wct == 15 */
1206 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1208 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1209 /* Let caller know file was created so we can set the mode. */
1210 /* Do we care about the CreateAction in any other cases? */
1211 /* BB FIXME BB */
1212 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1213 *pOplock |= CIFS_CREATE_ACTION; */
1214 /* BB FIXME END */
1216 if (pfile_info) {
1217 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1218 pfile_info->LastAccessTime = 0; /* BB fixme */
1219 pfile_info->LastWriteTime = 0; /* BB fixme */
1220 pfile_info->ChangeTime = 0; /* BB fixme */
1221 pfile_info->Attributes =
1222 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1223 /* the file_info buf is endian converted by caller */
1224 pfile_info->AllocationSize =
1225 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1226 pfile_info->EndOfFile = pfile_info->AllocationSize;
1227 pfile_info->NumberOfLinks = cpu_to_le32(1);
1228 pfile_info->DeletePending = 0;
1232 cifs_buf_release(pSMB);
1233 if (rc == -EAGAIN)
1234 goto OldOpenRetry;
1235 return rc;
1239 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1240 const char *fileName, const int openDisposition,
1241 const int access_flags, const int create_options, __u16 *netfid,
1242 int *pOplock, FILE_ALL_INFO *pfile_info,
1243 const struct nls_table *nls_codepage, int remap)
1245 int rc = -EACCES;
1246 OPEN_REQ *pSMB = NULL;
1247 OPEN_RSP *pSMBr = NULL;
1248 int bytes_returned;
1249 int name_len;
1250 __u16 count;
1252 openRetry:
1253 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1254 (void **) &pSMBr);
1255 if (rc)
1256 return rc;
1258 pSMB->AndXCommand = 0xFF; /* none */
1260 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1261 count = 1; /* account for one byte pad to word boundary */
1262 name_len =
1263 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1264 fileName, PATH_MAX, nls_codepage, remap);
1265 name_len++; /* trailing null */
1266 name_len *= 2;
1267 pSMB->NameLength = cpu_to_le16(name_len);
1268 } else { /* BB improve check for buffer overruns BB */
1269 count = 0; /* no pad */
1270 name_len = strnlen(fileName, PATH_MAX);
1271 name_len++; /* trailing null */
1272 pSMB->NameLength = cpu_to_le16(name_len);
1273 strncpy(pSMB->fileName, fileName, name_len);
1275 if (*pOplock & REQ_OPLOCK)
1276 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1277 else if (*pOplock & REQ_BATCHOPLOCK)
1278 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1279 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1280 pSMB->AllocationSize = 0;
1281 /* set file as system file if special file such
1282 as fifo and server expecting SFU style and
1283 no Unix extensions */
1284 if (create_options & CREATE_OPTION_SPECIAL)
1285 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1286 else
1287 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1289 /* XP does not handle ATTR_POSIX_SEMANTICS */
1290 /* but it helps speed up case sensitive checks for other
1291 servers such as Samba */
1292 if (tcon->ses->capabilities & CAP_UNIX)
1293 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1295 if (create_options & CREATE_OPTION_READONLY)
1296 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1298 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1299 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1300 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1301 /* BB Expirement with various impersonation levels and verify */
1302 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1303 pSMB->SecurityFlags =
1304 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1306 count += name_len;
1307 pSMB->hdr.smb_buf_length += count;
1309 pSMB->ByteCount = cpu_to_le16(count);
1310 /* long_op set to 1 to allow for oplock break timeouts */
1311 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1312 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1313 cifs_stats_inc(&tcon->num_opens);
1314 if (rc) {
1315 cFYI(1, "Error in Open = %d", rc);
1316 } else {
1317 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1318 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1319 /* Let caller know file was created so we can set the mode. */
1320 /* Do we care about the CreateAction in any other cases? */
1321 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1322 *pOplock |= CIFS_CREATE_ACTION;
1323 if (pfile_info) {
1324 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1325 36 /* CreationTime to Attributes */);
1326 /* the file_info buf is endian converted by caller */
1327 pfile_info->AllocationSize = pSMBr->AllocationSize;
1328 pfile_info->EndOfFile = pSMBr->EndOfFile;
1329 pfile_info->NumberOfLinks = cpu_to_le32(1);
1330 pfile_info->DeletePending = 0;
1334 cifs_buf_release(pSMB);
1335 if (rc == -EAGAIN)
1336 goto openRetry;
1337 return rc;
1341 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1342 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1343 char **buf, int *pbuf_type)
1345 int rc = -EACCES;
1346 READ_REQ *pSMB = NULL;
1347 READ_RSP *pSMBr = NULL;
1348 char *pReadData = NULL;
1349 int wct;
1350 int resp_buf_type = 0;
1351 struct kvec iov[1];
1353 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
1354 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1355 wct = 12;
1356 else {
1357 wct = 10; /* old style read */
1358 if ((lseek >> 32) > 0) {
1359 /* can not handle this big offset for old */
1360 return -EIO;
1364 *nbytes = 0;
1365 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1366 if (rc)
1367 return rc;
1369 /* tcon and ses pointer are checked in smb_init */
1370 if (tcon->ses->server == NULL)
1371 return -ECONNABORTED;
1373 pSMB->AndXCommand = 0xFF; /* none */
1374 pSMB->Fid = netfid;
1375 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1376 if (wct == 12)
1377 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1379 pSMB->Remaining = 0;
1380 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1381 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1382 if (wct == 12)
1383 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1384 else {
1385 /* old style read */
1386 struct smb_com_readx_req *pSMBW =
1387 (struct smb_com_readx_req *)pSMB;
1388 pSMBW->ByteCount = 0;
1391 iov[0].iov_base = (char *)pSMB;
1392 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1393 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1394 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1395 cifs_stats_inc(&tcon->num_reads);
1396 pSMBr = (READ_RSP *)iov[0].iov_base;
1397 if (rc) {
1398 cERROR(1, "Send error in read = %d", rc);
1399 } else {
1400 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1401 data_length = data_length << 16;
1402 data_length += le16_to_cpu(pSMBr->DataLength);
1403 *nbytes = data_length;
1405 /*check that DataLength would not go beyond end of SMB */
1406 if ((data_length > CIFSMaxBufSize)
1407 || (data_length > count)) {
1408 cFYI(1, "bad length %d for count %d",
1409 data_length, count);
1410 rc = -EIO;
1411 *nbytes = 0;
1412 } else {
1413 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1414 le16_to_cpu(pSMBr->DataOffset);
1415 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1416 cERROR(1, "Faulting on read rc = %d",rc);
1417 rc = -EFAULT;
1418 }*/ /* can not use copy_to_user when using page cache*/
1419 if (*buf)
1420 memcpy(*buf, pReadData, data_length);
1424 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1425 if (*buf) {
1426 if (resp_buf_type == CIFS_SMALL_BUFFER)
1427 cifs_small_buf_release(iov[0].iov_base);
1428 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1429 cifs_buf_release(iov[0].iov_base);
1430 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1431 /* return buffer to caller to free */
1432 *buf = iov[0].iov_base;
1433 if (resp_buf_type == CIFS_SMALL_BUFFER)
1434 *pbuf_type = CIFS_SMALL_BUFFER;
1435 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1436 *pbuf_type = CIFS_LARGE_BUFFER;
1437 } /* else no valid buffer on return - leave as null */
1439 /* Note: On -EAGAIN error only caller can retry on handle based calls
1440 since file handle passed in no longer valid */
1441 return rc;
1446 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1447 const int netfid, const unsigned int count,
1448 const __u64 offset, unsigned int *nbytes, const char *buf,
1449 const char __user *ubuf, const int long_op)
1451 int rc = -EACCES;
1452 WRITE_REQ *pSMB = NULL;
1453 WRITE_RSP *pSMBr = NULL;
1454 int bytes_returned, wct;
1455 __u32 bytes_sent;
1456 __u16 byte_count;
1458 *nbytes = 0;
1460 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
1461 if (tcon->ses == NULL)
1462 return -ECONNABORTED;
1464 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1465 wct = 14;
1466 else {
1467 wct = 12;
1468 if ((offset >> 32) > 0) {
1469 /* can not handle big offset for old srv */
1470 return -EIO;
1474 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1475 (void **) &pSMBr);
1476 if (rc)
1477 return rc;
1478 /* tcon and ses pointer are checked in smb_init */
1479 if (tcon->ses->server == NULL)
1480 return -ECONNABORTED;
1482 pSMB->AndXCommand = 0xFF; /* none */
1483 pSMB->Fid = netfid;
1484 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1485 if (wct == 14)
1486 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1488 pSMB->Reserved = 0xFFFFFFFF;
1489 pSMB->WriteMode = 0;
1490 pSMB->Remaining = 0;
1492 /* Can increase buffer size if buffer is big enough in some cases ie we
1493 can send more if LARGE_WRITE_X capability returned by the server and if
1494 our buffer is big enough or if we convert to iovecs on socket writes
1495 and eliminate the copy to the CIFS buffer */
1496 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1497 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1498 } else {
1499 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1500 & ~0xFF;
1503 if (bytes_sent > count)
1504 bytes_sent = count;
1505 pSMB->DataOffset =
1506 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1507 if (buf)
1508 memcpy(pSMB->Data, buf, bytes_sent);
1509 else if (ubuf) {
1510 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1511 cifs_buf_release(pSMB);
1512 return -EFAULT;
1514 } else if (count != 0) {
1515 /* No buffer */
1516 cifs_buf_release(pSMB);
1517 return -EINVAL;
1518 } /* else setting file size with write of zero bytes */
1519 if (wct == 14)
1520 byte_count = bytes_sent + 1; /* pad */
1521 else /* wct == 12 */
1522 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1524 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1525 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1526 pSMB->hdr.smb_buf_length += byte_count;
1528 if (wct == 14)
1529 pSMB->ByteCount = cpu_to_le16(byte_count);
1530 else { /* old style write has byte count 4 bytes earlier
1531 so 4 bytes pad */
1532 struct smb_com_writex_req *pSMBW =
1533 (struct smb_com_writex_req *)pSMB;
1534 pSMBW->ByteCount = cpu_to_le16(byte_count);
1537 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1538 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1539 cifs_stats_inc(&tcon->num_writes);
1540 if (rc) {
1541 cFYI(1, "Send error in write = %d", rc);
1542 } else {
1543 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1544 *nbytes = (*nbytes) << 16;
1545 *nbytes += le16_to_cpu(pSMBr->Count);
1548 * Mask off high 16 bits when bytes written as returned by the
1549 * server is greater than bytes requested by the client. Some
1550 * OS/2 servers are known to set incorrect CountHigh values.
1552 if (*nbytes > count)
1553 *nbytes &= 0xFFFF;
1556 cifs_buf_release(pSMB);
1558 /* Note: On -EAGAIN error only caller can retry on handle based calls
1559 since file handle passed in no longer valid */
1561 return rc;
1565 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1566 const int netfid, const unsigned int count,
1567 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1568 int n_vec, const int long_op)
1570 int rc = -EACCES;
1571 WRITE_REQ *pSMB = NULL;
1572 int wct;
1573 int smb_hdr_len;
1574 int resp_buf_type = 0;
1576 *nbytes = 0;
1578 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
1580 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1581 wct = 14;
1582 } else {
1583 wct = 12;
1584 if ((offset >> 32) > 0) {
1585 /* can not handle big offset for old srv */
1586 return -EIO;
1589 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1590 if (rc)
1591 return rc;
1592 /* tcon and ses pointer are checked in smb_init */
1593 if (tcon->ses->server == NULL)
1594 return -ECONNABORTED;
1596 pSMB->AndXCommand = 0xFF; /* none */
1597 pSMB->Fid = netfid;
1598 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1599 if (wct == 14)
1600 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1601 pSMB->Reserved = 0xFFFFFFFF;
1602 pSMB->WriteMode = 0;
1603 pSMB->Remaining = 0;
1605 pSMB->DataOffset =
1606 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1608 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1609 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1610 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1611 if (wct == 14)
1612 pSMB->hdr.smb_buf_length += count+1;
1613 else /* wct == 12 */
1614 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1615 if (wct == 14)
1616 pSMB->ByteCount = cpu_to_le16(count + 1);
1617 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1618 struct smb_com_writex_req *pSMBW =
1619 (struct smb_com_writex_req *)pSMB;
1620 pSMBW->ByteCount = cpu_to_le16(count + 5);
1622 iov[0].iov_base = pSMB;
1623 if (wct == 14)
1624 iov[0].iov_len = smb_hdr_len + 4;
1625 else /* wct == 12 pad bigger by four bytes */
1626 iov[0].iov_len = smb_hdr_len + 8;
1629 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1630 long_op);
1631 cifs_stats_inc(&tcon->num_writes);
1632 if (rc) {
1633 cFYI(1, "Send error Write2 = %d", rc);
1634 } else if (resp_buf_type == 0) {
1635 /* presumably this can not happen, but best to be safe */
1636 rc = -EIO;
1637 } else {
1638 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1639 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1640 *nbytes = (*nbytes) << 16;
1641 *nbytes += le16_to_cpu(pSMBr->Count);
1644 * Mask off high 16 bits when bytes written as returned by the
1645 * server is greater than bytes requested by the client. OS/2
1646 * servers are known to set incorrect CountHigh values.
1648 if (*nbytes > count)
1649 *nbytes &= 0xFFFF;
1652 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1653 if (resp_buf_type == CIFS_SMALL_BUFFER)
1654 cifs_small_buf_release(iov[0].iov_base);
1655 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1656 cifs_buf_release(iov[0].iov_base);
1658 /* Note: On -EAGAIN error only caller can retry on handle based calls
1659 since file handle passed in no longer valid */
1661 return rc;
1666 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1667 const __u16 smb_file_id, const __u64 len,
1668 const __u64 offset, const __u32 numUnlock,
1669 const __u32 numLock, const __u8 lockType,
1670 const bool waitFlag, const __u8 oplock_level)
1672 int rc = 0;
1673 LOCK_REQ *pSMB = NULL;
1674 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1675 int bytes_returned;
1676 int timeout = 0;
1677 __u16 count;
1679 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
1680 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1682 if (rc)
1683 return rc;
1685 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1686 timeout = CIFS_ASYNC_OP; /* no response expected */
1687 pSMB->Timeout = 0;
1688 } else if (waitFlag) {
1689 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1690 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1691 } else {
1692 pSMB->Timeout = 0;
1695 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1696 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1697 pSMB->LockType = lockType;
1698 pSMB->OplockLevel = oplock_level;
1699 pSMB->AndXCommand = 0xFF; /* none */
1700 pSMB->Fid = smb_file_id; /* netfid stays le */
1702 if ((numLock != 0) || (numUnlock != 0)) {
1703 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1704 /* BB where to store pid high? */
1705 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1706 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1707 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1708 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1709 count = sizeof(LOCKING_ANDX_RANGE);
1710 } else {
1711 /* oplock break */
1712 count = 0;
1714 pSMB->hdr.smb_buf_length += count;
1715 pSMB->ByteCount = cpu_to_le16(count);
1717 if (waitFlag) {
1718 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1719 (struct smb_hdr *) pSMB, &bytes_returned);
1720 cifs_small_buf_release(pSMB);
1721 } else {
1722 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1723 timeout);
1724 /* SMB buffer freed by function above */
1726 cifs_stats_inc(&tcon->num_locks);
1727 if (rc)
1728 cFYI(1, "Send error in Lock = %d", rc);
1730 /* Note: On -EAGAIN error only caller can retry on handle based calls
1731 since file handle passed in no longer valid */
1732 return rc;
1736 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1737 const __u16 smb_file_id, const int get_flag, const __u64 len,
1738 struct file_lock *pLockData, const __u16 lock_type,
1739 const bool waitFlag)
1741 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1742 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1743 struct cifs_posix_lock *parm_data;
1744 int rc = 0;
1745 int timeout = 0;
1746 int bytes_returned = 0;
1747 int resp_buf_type = 0;
1748 __u16 params, param_offset, offset, byte_count, count;
1749 struct kvec iov[1];
1751 cFYI(1, "Posix Lock");
1753 if (pLockData == NULL)
1754 return -EINVAL;
1756 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1758 if (rc)
1759 return rc;
1761 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1763 params = 6;
1764 pSMB->MaxSetupCount = 0;
1765 pSMB->Reserved = 0;
1766 pSMB->Flags = 0;
1767 pSMB->Reserved2 = 0;
1768 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1769 offset = param_offset + params;
1771 count = sizeof(struct cifs_posix_lock);
1772 pSMB->MaxParameterCount = cpu_to_le16(2);
1773 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1774 pSMB->SetupCount = 1;
1775 pSMB->Reserved3 = 0;
1776 if (get_flag)
1777 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1778 else
1779 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1780 byte_count = 3 /* pad */ + params + count;
1781 pSMB->DataCount = cpu_to_le16(count);
1782 pSMB->ParameterCount = cpu_to_le16(params);
1783 pSMB->TotalDataCount = pSMB->DataCount;
1784 pSMB->TotalParameterCount = pSMB->ParameterCount;
1785 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1786 parm_data = (struct cifs_posix_lock *)
1787 (((char *) &pSMB->hdr.Protocol) + offset);
1789 parm_data->lock_type = cpu_to_le16(lock_type);
1790 if (waitFlag) {
1791 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1792 parm_data->lock_flags = cpu_to_le16(1);
1793 pSMB->Timeout = cpu_to_le32(-1);
1794 } else
1795 pSMB->Timeout = 0;
1797 parm_data->pid = cpu_to_le32(current->tgid);
1798 parm_data->start = cpu_to_le64(pLockData->fl_start);
1799 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1801 pSMB->DataOffset = cpu_to_le16(offset);
1802 pSMB->Fid = smb_file_id;
1803 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1804 pSMB->Reserved4 = 0;
1805 pSMB->hdr.smb_buf_length += byte_count;
1806 pSMB->ByteCount = cpu_to_le16(byte_count);
1807 if (waitFlag) {
1808 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1809 (struct smb_hdr *) pSMBr, &bytes_returned);
1810 } else {
1811 iov[0].iov_base = (char *)pSMB;
1812 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1813 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1814 &resp_buf_type, timeout);
1815 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1816 not try to free it twice below on exit */
1817 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1820 if (rc) {
1821 cFYI(1, "Send error in Posix Lock = %d", rc);
1822 } else if (get_flag) {
1823 /* lock structure can be returned on get */
1824 __u16 data_offset;
1825 __u16 data_count;
1826 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1828 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1829 rc = -EIO; /* bad smb */
1830 goto plk_err_exit;
1832 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1833 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1834 if (data_count < sizeof(struct cifs_posix_lock)) {
1835 rc = -EIO;
1836 goto plk_err_exit;
1838 parm_data = (struct cifs_posix_lock *)
1839 ((char *)&pSMBr->hdr.Protocol + data_offset);
1840 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
1841 pLockData->fl_type = F_UNLCK;
1842 else {
1843 if (parm_data->lock_type ==
1844 __constant_cpu_to_le16(CIFS_RDLCK))
1845 pLockData->fl_type = F_RDLCK;
1846 else if (parm_data->lock_type ==
1847 __constant_cpu_to_le16(CIFS_WRLCK))
1848 pLockData->fl_type = F_WRLCK;
1850 pLockData->fl_start = parm_data->start;
1851 pLockData->fl_end = parm_data->start +
1852 parm_data->length - 1;
1853 pLockData->fl_pid = parm_data->pid;
1857 plk_err_exit:
1858 if (pSMB)
1859 cifs_small_buf_release(pSMB);
1861 if (resp_buf_type == CIFS_SMALL_BUFFER)
1862 cifs_small_buf_release(iov[0].iov_base);
1863 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1864 cifs_buf_release(iov[0].iov_base);
1866 /* Note: On -EAGAIN error only caller can retry on handle based calls
1867 since file handle passed in no longer valid */
1869 return rc;
1874 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1876 int rc = 0;
1877 CLOSE_REQ *pSMB = NULL;
1878 cFYI(1, "In CIFSSMBClose");
1880 /* do not retry on dead session on close */
1881 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1882 if (rc == -EAGAIN)
1883 return 0;
1884 if (rc)
1885 return rc;
1887 pSMB->FileID = (__u16) smb_file_id;
1888 pSMB->LastWriteTime = 0xFFFFFFFF;
1889 pSMB->ByteCount = 0;
1890 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1891 cifs_stats_inc(&tcon->num_closes);
1892 if (rc) {
1893 if (rc != -EINTR) {
1894 /* EINTR is expected when user ctl-c to kill app */
1895 cERROR(1, "Send error in Close = %d", rc);
1899 /* Since session is dead, file will be closed on server already */
1900 if (rc == -EAGAIN)
1901 rc = 0;
1903 return rc;
1907 CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1909 int rc = 0;
1910 FLUSH_REQ *pSMB = NULL;
1911 cFYI(1, "In CIFSSMBFlush");
1913 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1914 if (rc)
1915 return rc;
1917 pSMB->FileID = (__u16) smb_file_id;
1918 pSMB->ByteCount = 0;
1919 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1920 cifs_stats_inc(&tcon->num_flushes);
1921 if (rc)
1922 cERROR(1, "Send error in Flush = %d", rc);
1924 return rc;
1928 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1929 const char *fromName, const char *toName,
1930 const struct nls_table *nls_codepage, int remap)
1932 int rc = 0;
1933 RENAME_REQ *pSMB = NULL;
1934 RENAME_RSP *pSMBr = NULL;
1935 int bytes_returned;
1936 int name_len, name_len2;
1937 __u16 count;
1939 cFYI(1, "In CIFSSMBRename");
1940 renameRetry:
1941 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1942 (void **) &pSMBr);
1943 if (rc)
1944 return rc;
1946 pSMB->BufferFormat = 0x04;
1947 pSMB->SearchAttributes =
1948 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1949 ATTR_DIRECTORY);
1951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1952 name_len =
1953 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1954 PATH_MAX, nls_codepage, remap);
1955 name_len++; /* trailing null */
1956 name_len *= 2;
1957 pSMB->OldFileName[name_len] = 0x04; /* pad */
1958 /* protocol requires ASCII signature byte on Unicode string */
1959 pSMB->OldFileName[name_len + 1] = 0x00;
1960 name_len2 =
1961 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1962 toName, PATH_MAX, nls_codepage, remap);
1963 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1964 name_len2 *= 2; /* convert to bytes */
1965 } else { /* BB improve the check for buffer overruns BB */
1966 name_len = strnlen(fromName, PATH_MAX);
1967 name_len++; /* trailing null */
1968 strncpy(pSMB->OldFileName, fromName, name_len);
1969 name_len2 = strnlen(toName, PATH_MAX);
1970 name_len2++; /* trailing null */
1971 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1972 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1973 name_len2++; /* trailing null */
1974 name_len2++; /* signature byte */
1977 count = 1 /* 1st signature byte */ + name_len + name_len2;
1978 pSMB->hdr.smb_buf_length += count;
1979 pSMB->ByteCount = cpu_to_le16(count);
1981 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1982 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1983 cifs_stats_inc(&tcon->num_renames);
1984 if (rc)
1985 cFYI(1, "Send error in rename = %d", rc);
1987 cifs_buf_release(pSMB);
1989 if (rc == -EAGAIN)
1990 goto renameRetry;
1992 return rc;
1995 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1996 int netfid, const char *target_name,
1997 const struct nls_table *nls_codepage, int remap)
1999 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2000 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2001 struct set_file_rename *rename_info;
2002 char *data_offset;
2003 char dummy_string[30];
2004 int rc = 0;
2005 int bytes_returned = 0;
2006 int len_of_str;
2007 __u16 params, param_offset, offset, count, byte_count;
2009 cFYI(1, "Rename to File by handle");
2010 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2011 (void **) &pSMBr);
2012 if (rc)
2013 return rc;
2015 params = 6;
2016 pSMB->MaxSetupCount = 0;
2017 pSMB->Reserved = 0;
2018 pSMB->Flags = 0;
2019 pSMB->Timeout = 0;
2020 pSMB->Reserved2 = 0;
2021 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2022 offset = param_offset + params;
2024 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2025 rename_info = (struct set_file_rename *) data_offset;
2026 pSMB->MaxParameterCount = cpu_to_le16(2);
2027 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2028 pSMB->SetupCount = 1;
2029 pSMB->Reserved3 = 0;
2030 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2031 byte_count = 3 /* pad */ + params;
2032 pSMB->ParameterCount = cpu_to_le16(params);
2033 pSMB->TotalParameterCount = pSMB->ParameterCount;
2034 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2035 pSMB->DataOffset = cpu_to_le16(offset);
2036 /* construct random name ".cifs_tmp<inodenum><mid>" */
2037 rename_info->overwrite = cpu_to_le32(1);
2038 rename_info->root_fid = 0;
2039 /* unicode only call */
2040 if (target_name == NULL) {
2041 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2042 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2043 dummy_string, 24, nls_codepage, remap);
2044 } else {
2045 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2046 target_name, PATH_MAX, nls_codepage,
2047 remap);
2049 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2050 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2051 byte_count += count;
2052 pSMB->DataCount = cpu_to_le16(count);
2053 pSMB->TotalDataCount = pSMB->DataCount;
2054 pSMB->Fid = netfid;
2055 pSMB->InformationLevel =
2056 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2057 pSMB->Reserved4 = 0;
2058 pSMB->hdr.smb_buf_length += byte_count;
2059 pSMB->ByteCount = cpu_to_le16(byte_count);
2060 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2061 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2062 cifs_stats_inc(&pTcon->num_t2renames);
2063 if (rc)
2064 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
2066 cifs_buf_release(pSMB);
2068 /* Note: On -EAGAIN error only caller can retry on handle based calls
2069 since file handle passed in no longer valid */
2071 return rc;
2075 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2076 const __u16 target_tid, const char *toName, const int flags,
2077 const struct nls_table *nls_codepage, int remap)
2079 int rc = 0;
2080 COPY_REQ *pSMB = NULL;
2081 COPY_RSP *pSMBr = NULL;
2082 int bytes_returned;
2083 int name_len, name_len2;
2084 __u16 count;
2086 cFYI(1, "In CIFSSMBCopy");
2087 copyRetry:
2088 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2089 (void **) &pSMBr);
2090 if (rc)
2091 return rc;
2093 pSMB->BufferFormat = 0x04;
2094 pSMB->Tid2 = target_tid;
2096 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2098 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2099 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2100 fromName, PATH_MAX, nls_codepage,
2101 remap);
2102 name_len++; /* trailing null */
2103 name_len *= 2;
2104 pSMB->OldFileName[name_len] = 0x04; /* pad */
2105 /* protocol requires ASCII signature byte on Unicode string */
2106 pSMB->OldFileName[name_len + 1] = 0x00;
2107 name_len2 =
2108 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2109 toName, PATH_MAX, nls_codepage, remap);
2110 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2111 name_len2 *= 2; /* convert to bytes */
2112 } else { /* BB improve the check for buffer overruns BB */
2113 name_len = strnlen(fromName, PATH_MAX);
2114 name_len++; /* trailing null */
2115 strncpy(pSMB->OldFileName, fromName, name_len);
2116 name_len2 = strnlen(toName, PATH_MAX);
2117 name_len2++; /* trailing null */
2118 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2119 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2120 name_len2++; /* trailing null */
2121 name_len2++; /* signature byte */
2124 count = 1 /* 1st signature byte */ + name_len + name_len2;
2125 pSMB->hdr.smb_buf_length += count;
2126 pSMB->ByteCount = cpu_to_le16(count);
2128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2129 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2130 if (rc) {
2131 cFYI(1, "Send error in copy = %d with %d files copied",
2132 rc, le16_to_cpu(pSMBr->CopyCount));
2134 cifs_buf_release(pSMB);
2136 if (rc == -EAGAIN)
2137 goto copyRetry;
2139 return rc;
2143 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2144 const char *fromName, const char *toName,
2145 const struct nls_table *nls_codepage)
2147 TRANSACTION2_SPI_REQ *pSMB = NULL;
2148 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2149 char *data_offset;
2150 int name_len;
2151 int name_len_target;
2152 int rc = 0;
2153 int bytes_returned = 0;
2154 __u16 params, param_offset, offset, byte_count;
2156 cFYI(1, "In Symlink Unix style");
2157 createSymLinkRetry:
2158 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2159 (void **) &pSMBr);
2160 if (rc)
2161 return rc;
2163 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2164 name_len =
2165 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2166 /* find define for this maxpathcomponent */
2167 , nls_codepage);
2168 name_len++; /* trailing null */
2169 name_len *= 2;
2171 } else { /* BB improve the check for buffer overruns BB */
2172 name_len = strnlen(fromName, PATH_MAX);
2173 name_len++; /* trailing null */
2174 strncpy(pSMB->FileName, fromName, name_len);
2176 params = 6 + name_len;
2177 pSMB->MaxSetupCount = 0;
2178 pSMB->Reserved = 0;
2179 pSMB->Flags = 0;
2180 pSMB->Timeout = 0;
2181 pSMB->Reserved2 = 0;
2182 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2183 InformationLevel) - 4;
2184 offset = param_offset + params;
2186 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2187 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2188 name_len_target =
2189 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2190 /* find define for this maxpathcomponent */
2191 , nls_codepage);
2192 name_len_target++; /* trailing null */
2193 name_len_target *= 2;
2194 } else { /* BB improve the check for buffer overruns BB */
2195 name_len_target = strnlen(toName, PATH_MAX);
2196 name_len_target++; /* trailing null */
2197 strncpy(data_offset, toName, name_len_target);
2200 pSMB->MaxParameterCount = cpu_to_le16(2);
2201 /* BB find exact max on data count below from sess */
2202 pSMB->MaxDataCount = cpu_to_le16(1000);
2203 pSMB->SetupCount = 1;
2204 pSMB->Reserved3 = 0;
2205 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2206 byte_count = 3 /* pad */ + params + name_len_target;
2207 pSMB->DataCount = cpu_to_le16(name_len_target);
2208 pSMB->ParameterCount = cpu_to_le16(params);
2209 pSMB->TotalDataCount = pSMB->DataCount;
2210 pSMB->TotalParameterCount = pSMB->ParameterCount;
2211 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2212 pSMB->DataOffset = cpu_to_le16(offset);
2213 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2214 pSMB->Reserved4 = 0;
2215 pSMB->hdr.smb_buf_length += byte_count;
2216 pSMB->ByteCount = cpu_to_le16(byte_count);
2217 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2218 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2219 cifs_stats_inc(&tcon->num_symlinks);
2220 if (rc)
2221 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
2223 cifs_buf_release(pSMB);
2225 if (rc == -EAGAIN)
2226 goto createSymLinkRetry;
2228 return rc;
2232 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2233 const char *fromName, const char *toName,
2234 const struct nls_table *nls_codepage, int remap)
2236 TRANSACTION2_SPI_REQ *pSMB = NULL;
2237 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2238 char *data_offset;
2239 int name_len;
2240 int name_len_target;
2241 int rc = 0;
2242 int bytes_returned = 0;
2243 __u16 params, param_offset, offset, byte_count;
2245 cFYI(1, "In Create Hard link Unix style");
2246 createHardLinkRetry:
2247 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2248 (void **) &pSMBr);
2249 if (rc)
2250 return rc;
2252 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2253 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2254 PATH_MAX, nls_codepage, remap);
2255 name_len++; /* trailing null */
2256 name_len *= 2;
2258 } else { /* BB improve the check for buffer overruns BB */
2259 name_len = strnlen(toName, PATH_MAX);
2260 name_len++; /* trailing null */
2261 strncpy(pSMB->FileName, toName, name_len);
2263 params = 6 + name_len;
2264 pSMB->MaxSetupCount = 0;
2265 pSMB->Reserved = 0;
2266 pSMB->Flags = 0;
2267 pSMB->Timeout = 0;
2268 pSMB->Reserved2 = 0;
2269 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2270 InformationLevel) - 4;
2271 offset = param_offset + params;
2273 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2274 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2275 name_len_target =
2276 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2277 nls_codepage, remap);
2278 name_len_target++; /* trailing null */
2279 name_len_target *= 2;
2280 } else { /* BB improve the check for buffer overruns BB */
2281 name_len_target = strnlen(fromName, PATH_MAX);
2282 name_len_target++; /* trailing null */
2283 strncpy(data_offset, fromName, name_len_target);
2286 pSMB->MaxParameterCount = cpu_to_le16(2);
2287 /* BB find exact max on data count below from sess*/
2288 pSMB->MaxDataCount = cpu_to_le16(1000);
2289 pSMB->SetupCount = 1;
2290 pSMB->Reserved3 = 0;
2291 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2292 byte_count = 3 /* pad */ + params + name_len_target;
2293 pSMB->ParameterCount = cpu_to_le16(params);
2294 pSMB->TotalParameterCount = pSMB->ParameterCount;
2295 pSMB->DataCount = cpu_to_le16(name_len_target);
2296 pSMB->TotalDataCount = pSMB->DataCount;
2297 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2298 pSMB->DataOffset = cpu_to_le16(offset);
2299 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2300 pSMB->Reserved4 = 0;
2301 pSMB->hdr.smb_buf_length += byte_count;
2302 pSMB->ByteCount = cpu_to_le16(byte_count);
2303 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2304 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2305 cifs_stats_inc(&tcon->num_hardlinks);
2306 if (rc)
2307 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
2309 cifs_buf_release(pSMB);
2310 if (rc == -EAGAIN)
2311 goto createHardLinkRetry;
2313 return rc;
2317 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2318 const char *fromName, const char *toName,
2319 const struct nls_table *nls_codepage, int remap)
2321 int rc = 0;
2322 NT_RENAME_REQ *pSMB = NULL;
2323 RENAME_RSP *pSMBr = NULL;
2324 int bytes_returned;
2325 int name_len, name_len2;
2326 __u16 count;
2328 cFYI(1, "In CIFSCreateHardLink");
2329 winCreateHardLinkRetry:
2331 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2332 (void **) &pSMBr);
2333 if (rc)
2334 return rc;
2336 pSMB->SearchAttributes =
2337 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2338 ATTR_DIRECTORY);
2339 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2340 pSMB->ClusterCount = 0;
2342 pSMB->BufferFormat = 0x04;
2344 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2345 name_len =
2346 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2347 PATH_MAX, nls_codepage, remap);
2348 name_len++; /* trailing null */
2349 name_len *= 2;
2351 /* protocol specifies ASCII buffer format (0x04) for unicode */
2352 pSMB->OldFileName[name_len] = 0x04;
2353 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2354 name_len2 =
2355 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2356 toName, PATH_MAX, nls_codepage, remap);
2357 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2358 name_len2 *= 2; /* convert to bytes */
2359 } else { /* BB improve the check for buffer overruns BB */
2360 name_len = strnlen(fromName, PATH_MAX);
2361 name_len++; /* trailing null */
2362 strncpy(pSMB->OldFileName, fromName, name_len);
2363 name_len2 = strnlen(toName, PATH_MAX);
2364 name_len2++; /* trailing null */
2365 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2366 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2367 name_len2++; /* trailing null */
2368 name_len2++; /* signature byte */
2371 count = 1 /* string type byte */ + name_len + name_len2;
2372 pSMB->hdr.smb_buf_length += count;
2373 pSMB->ByteCount = cpu_to_le16(count);
2375 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2376 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2377 cifs_stats_inc(&tcon->num_hardlinks);
2378 if (rc)
2379 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
2381 cifs_buf_release(pSMB);
2382 if (rc == -EAGAIN)
2383 goto winCreateHardLinkRetry;
2385 return rc;
2389 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2390 const unsigned char *searchName, char **symlinkinfo,
2391 const struct nls_table *nls_codepage)
2393 /* SMB_QUERY_FILE_UNIX_LINK */
2394 TRANSACTION2_QPI_REQ *pSMB = NULL;
2395 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2396 int rc = 0;
2397 int bytes_returned;
2398 int name_len;
2399 __u16 params, byte_count;
2400 char *data_start;
2402 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
2404 querySymLinkRetry:
2405 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2406 (void **) &pSMBr);
2407 if (rc)
2408 return rc;
2410 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2411 name_len =
2412 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2413 PATH_MAX, nls_codepage);
2414 name_len++; /* trailing null */
2415 name_len *= 2;
2416 } else { /* BB improve the check for buffer overruns BB */
2417 name_len = strnlen(searchName, PATH_MAX);
2418 name_len++; /* trailing null */
2419 strncpy(pSMB->FileName, searchName, name_len);
2422 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2423 pSMB->TotalDataCount = 0;
2424 pSMB->MaxParameterCount = cpu_to_le16(2);
2425 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
2426 pSMB->MaxSetupCount = 0;
2427 pSMB->Reserved = 0;
2428 pSMB->Flags = 0;
2429 pSMB->Timeout = 0;
2430 pSMB->Reserved2 = 0;
2431 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2432 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2433 pSMB->DataCount = 0;
2434 pSMB->DataOffset = 0;
2435 pSMB->SetupCount = 1;
2436 pSMB->Reserved3 = 0;
2437 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2438 byte_count = params + 1 /* pad */ ;
2439 pSMB->TotalParameterCount = cpu_to_le16(params);
2440 pSMB->ParameterCount = pSMB->TotalParameterCount;
2441 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2442 pSMB->Reserved4 = 0;
2443 pSMB->hdr.smb_buf_length += byte_count;
2444 pSMB->ByteCount = cpu_to_le16(byte_count);
2446 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2447 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2448 if (rc) {
2449 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
2450 } else {
2451 /* decode response */
2453 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2454 /* BB also check enough total bytes returned */
2455 if (rc || (pSMBr->ByteCount < 2))
2456 rc = -EIO;
2457 else {
2458 bool is_unicode;
2459 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2461 data_start = ((char *) &pSMBr->hdr.Protocol) +
2462 le16_to_cpu(pSMBr->t2.DataOffset);
2464 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2465 is_unicode = true;
2466 else
2467 is_unicode = false;
2469 /* BB FIXME investigate remapping reserved chars here */
2470 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
2471 is_unicode, nls_codepage);
2472 if (!*symlinkinfo)
2473 rc = -ENOMEM;
2476 cifs_buf_release(pSMB);
2477 if (rc == -EAGAIN)
2478 goto querySymLinkRetry;
2479 return rc;
2482 #ifdef CONFIG_CIFS_EXPERIMENTAL
2484 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2485 const unsigned char *searchName,
2486 char *symlinkinfo, const int buflen, __u16 fid,
2487 const struct nls_table *nls_codepage)
2489 int rc = 0;
2490 int bytes_returned;
2491 struct smb_com_transaction_ioctl_req *pSMB;
2492 struct smb_com_transaction_ioctl_rsp *pSMBr;
2494 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
2495 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2496 (void **) &pSMBr);
2497 if (rc)
2498 return rc;
2500 pSMB->TotalParameterCount = 0 ;
2501 pSMB->TotalDataCount = 0;
2502 pSMB->MaxParameterCount = cpu_to_le32(2);
2503 /* BB find exact data count max from sess structure BB */
2504 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2505 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2506 pSMB->MaxSetupCount = 4;
2507 pSMB->Reserved = 0;
2508 pSMB->ParameterOffset = 0;
2509 pSMB->DataCount = 0;
2510 pSMB->DataOffset = 0;
2511 pSMB->SetupCount = 4;
2512 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2513 pSMB->ParameterCount = pSMB->TotalParameterCount;
2514 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2515 pSMB->IsFsctl = 1; /* FSCTL */
2516 pSMB->IsRootFlag = 0;
2517 pSMB->Fid = fid; /* file handle always le */
2518 pSMB->ByteCount = 0;
2520 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2521 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2522 if (rc) {
2523 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
2524 } else { /* decode response */
2525 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2526 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2527 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
2528 /* BB also check enough total bytes returned */
2529 rc = -EIO; /* bad smb */
2530 goto qreparse_out;
2532 if (data_count && (data_count < 2048)) {
2533 char *end_of_smb = 2 /* sizeof byte count */ +
2534 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
2536 struct reparse_data *reparse_buf =
2537 (struct reparse_data *)
2538 ((char *)&pSMBr->hdr.Protocol
2539 + data_offset);
2540 if ((char *)reparse_buf >= end_of_smb) {
2541 rc = -EIO;
2542 goto qreparse_out;
2544 if ((reparse_buf->LinkNamesBuf +
2545 reparse_buf->TargetNameOffset +
2546 reparse_buf->TargetNameLen) > end_of_smb) {
2547 cFYI(1, "reparse buf beyond SMB");
2548 rc = -EIO;
2549 goto qreparse_out;
2552 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2553 cifs_from_ucs2(symlinkinfo, (__le16 *)
2554 (reparse_buf->LinkNamesBuf +
2555 reparse_buf->TargetNameOffset),
2556 buflen,
2557 reparse_buf->TargetNameLen,
2558 nls_codepage, 0);
2559 } else { /* ASCII names */
2560 strncpy(symlinkinfo,
2561 reparse_buf->LinkNamesBuf +
2562 reparse_buf->TargetNameOffset,
2563 min_t(const int, buflen,
2564 reparse_buf->TargetNameLen));
2566 } else {
2567 rc = -EIO;
2568 cFYI(1, "Invalid return data count on "
2569 "get reparse info ioctl");
2571 symlinkinfo[buflen] = 0; /* just in case so the caller
2572 does not go off the end of the buffer */
2573 cFYI(1, "readlink result - %s", symlinkinfo);
2576 qreparse_out:
2577 cifs_buf_release(pSMB);
2579 /* Note: On -EAGAIN error only caller can retry on handle based calls
2580 since file handle passed in no longer valid */
2582 return rc;
2584 #endif /* CIFS_EXPERIMENTAL */
2586 #ifdef CONFIG_CIFS_POSIX
2588 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2589 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2590 struct cifs_posix_ace *cifs_ace)
2592 /* u8 cifs fields do not need le conversion */
2593 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2594 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2595 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2596 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
2598 return;
2601 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2602 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2603 const int acl_type, const int size_of_data_area)
2605 int size = 0;
2606 int i;
2607 __u16 count;
2608 struct cifs_posix_ace *pACE;
2609 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2610 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2612 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2613 return -EOPNOTSUPP;
2615 if (acl_type & ACL_TYPE_ACCESS) {
2616 count = le16_to_cpu(cifs_acl->access_entry_count);
2617 pACE = &cifs_acl->ace_array[0];
2618 size = sizeof(struct cifs_posix_acl);
2619 size += sizeof(struct cifs_posix_ace) * count;
2620 /* check if we would go beyond end of SMB */
2621 if (size_of_data_area < size) {
2622 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2623 size_of_data_area, size);
2624 return -EINVAL;
2626 } else if (acl_type & ACL_TYPE_DEFAULT) {
2627 count = le16_to_cpu(cifs_acl->access_entry_count);
2628 size = sizeof(struct cifs_posix_acl);
2629 size += sizeof(struct cifs_posix_ace) * count;
2630 /* skip past access ACEs to get to default ACEs */
2631 pACE = &cifs_acl->ace_array[count];
2632 count = le16_to_cpu(cifs_acl->default_entry_count);
2633 size += sizeof(struct cifs_posix_ace) * count;
2634 /* check if we would go beyond end of SMB */
2635 if (size_of_data_area < size)
2636 return -EINVAL;
2637 } else {
2638 /* illegal type */
2639 return -EINVAL;
2642 size = posix_acl_xattr_size(count);
2643 if ((buflen == 0) || (local_acl == NULL)) {
2644 /* used to query ACL EA size */
2645 } else if (size > buflen) {
2646 return -ERANGE;
2647 } else /* buffer big enough */ {
2648 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2649 for (i = 0; i < count ; i++) {
2650 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2651 pACE++;
2654 return size;
2657 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2658 const posix_acl_xattr_entry *local_ace)
2660 __u16 rc = 0; /* 0 = ACL converted ok */
2662 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2663 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2664 /* BB is there a better way to handle the large uid? */
2665 if (local_ace->e_id == cpu_to_le32(-1)) {
2666 /* Probably no need to le convert -1 on any arch but can not hurt */
2667 cifs_ace->cifs_uid = cpu_to_le64(-1);
2668 } else
2669 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2670 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
2671 return rc;
2674 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2675 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2676 const int buflen, const int acl_type)
2678 __u16 rc = 0;
2679 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2680 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2681 int count;
2682 int i;
2684 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2685 return 0;
2687 count = posix_acl_xattr_count((size_t)buflen);
2688 cFYI(1, "setting acl with %d entries from buf of length %d and "
2689 "version of %d",
2690 count, buflen, le32_to_cpu(local_acl->a_version));
2691 if (le32_to_cpu(local_acl->a_version) != 2) {
2692 cFYI(1, "unknown POSIX ACL version %d",
2693 le32_to_cpu(local_acl->a_version));
2694 return 0;
2696 cifs_acl->version = cpu_to_le16(1);
2697 if (acl_type == ACL_TYPE_ACCESS)
2698 cifs_acl->access_entry_count = cpu_to_le16(count);
2699 else if (acl_type == ACL_TYPE_DEFAULT)
2700 cifs_acl->default_entry_count = cpu_to_le16(count);
2701 else {
2702 cFYI(1, "unknown ACL type %d", acl_type);
2703 return 0;
2705 for (i = 0; i < count; i++) {
2706 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2707 &local_acl->a_entries[i]);
2708 if (rc != 0) {
2709 /* ACE not converted */
2710 break;
2713 if (rc == 0) {
2714 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2715 rc += sizeof(struct cifs_posix_acl);
2716 /* BB add check to make sure ACL does not overflow SMB */
2718 return rc;
2722 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2723 const unsigned char *searchName,
2724 char *acl_inf, const int buflen, const int acl_type,
2725 const struct nls_table *nls_codepage, int remap)
2727 /* SMB_QUERY_POSIX_ACL */
2728 TRANSACTION2_QPI_REQ *pSMB = NULL;
2729 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2730 int rc = 0;
2731 int bytes_returned;
2732 int name_len;
2733 __u16 params, byte_count;
2735 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
2737 queryAclRetry:
2738 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2739 (void **) &pSMBr);
2740 if (rc)
2741 return rc;
2743 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2744 name_len =
2745 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2746 PATH_MAX, nls_codepage, remap);
2747 name_len++; /* trailing null */
2748 name_len *= 2;
2749 pSMB->FileName[name_len] = 0;
2750 pSMB->FileName[name_len+1] = 0;
2751 } else { /* BB improve the check for buffer overruns BB */
2752 name_len = strnlen(searchName, PATH_MAX);
2753 name_len++; /* trailing null */
2754 strncpy(pSMB->FileName, searchName, name_len);
2757 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2758 pSMB->TotalDataCount = 0;
2759 pSMB->MaxParameterCount = cpu_to_le16(2);
2760 /* BB find exact max data count below from sess structure BB */
2761 pSMB->MaxDataCount = cpu_to_le16(4000);
2762 pSMB->MaxSetupCount = 0;
2763 pSMB->Reserved = 0;
2764 pSMB->Flags = 0;
2765 pSMB->Timeout = 0;
2766 pSMB->Reserved2 = 0;
2767 pSMB->ParameterOffset = cpu_to_le16(
2768 offsetof(struct smb_com_transaction2_qpi_req,
2769 InformationLevel) - 4);
2770 pSMB->DataCount = 0;
2771 pSMB->DataOffset = 0;
2772 pSMB->SetupCount = 1;
2773 pSMB->Reserved3 = 0;
2774 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2775 byte_count = params + 1 /* pad */ ;
2776 pSMB->TotalParameterCount = cpu_to_le16(params);
2777 pSMB->ParameterCount = pSMB->TotalParameterCount;
2778 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2779 pSMB->Reserved4 = 0;
2780 pSMB->hdr.smb_buf_length += byte_count;
2781 pSMB->ByteCount = cpu_to_le16(byte_count);
2783 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2784 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2785 cifs_stats_inc(&tcon->num_acl_get);
2786 if (rc) {
2787 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
2788 } else {
2789 /* decode response */
2791 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2792 if (rc || (pSMBr->ByteCount < 2))
2793 /* BB also check enough total bytes returned */
2794 rc = -EIO; /* bad smb */
2795 else {
2796 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2797 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2798 rc = cifs_copy_posix_acl(acl_inf,
2799 (char *)&pSMBr->hdr.Protocol+data_offset,
2800 buflen, acl_type, count);
2803 cifs_buf_release(pSMB);
2804 if (rc == -EAGAIN)
2805 goto queryAclRetry;
2806 return rc;
2810 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2811 const unsigned char *fileName,
2812 const char *local_acl, const int buflen,
2813 const int acl_type,
2814 const struct nls_table *nls_codepage, int remap)
2816 struct smb_com_transaction2_spi_req *pSMB = NULL;
2817 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2818 char *parm_data;
2819 int name_len;
2820 int rc = 0;
2821 int bytes_returned = 0;
2822 __u16 params, byte_count, data_count, param_offset, offset;
2824 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
2825 setAclRetry:
2826 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2827 (void **) &pSMBr);
2828 if (rc)
2829 return rc;
2830 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2831 name_len =
2832 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2833 PATH_MAX, nls_codepage, remap);
2834 name_len++; /* trailing null */
2835 name_len *= 2;
2836 } else { /* BB improve the check for buffer overruns BB */
2837 name_len = strnlen(fileName, PATH_MAX);
2838 name_len++; /* trailing null */
2839 strncpy(pSMB->FileName, fileName, name_len);
2841 params = 6 + name_len;
2842 pSMB->MaxParameterCount = cpu_to_le16(2);
2843 /* BB find max SMB size from sess */
2844 pSMB->MaxDataCount = cpu_to_le16(1000);
2845 pSMB->MaxSetupCount = 0;
2846 pSMB->Reserved = 0;
2847 pSMB->Flags = 0;
2848 pSMB->Timeout = 0;
2849 pSMB->Reserved2 = 0;
2850 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2851 InformationLevel) - 4;
2852 offset = param_offset + params;
2853 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2854 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2856 /* convert to on the wire format for POSIX ACL */
2857 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2859 if (data_count == 0) {
2860 rc = -EOPNOTSUPP;
2861 goto setACLerrorExit;
2863 pSMB->DataOffset = cpu_to_le16(offset);
2864 pSMB->SetupCount = 1;
2865 pSMB->Reserved3 = 0;
2866 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2867 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2868 byte_count = 3 /* pad */ + params + data_count;
2869 pSMB->DataCount = cpu_to_le16(data_count);
2870 pSMB->TotalDataCount = pSMB->DataCount;
2871 pSMB->ParameterCount = cpu_to_le16(params);
2872 pSMB->TotalParameterCount = pSMB->ParameterCount;
2873 pSMB->Reserved4 = 0;
2874 pSMB->hdr.smb_buf_length += byte_count;
2875 pSMB->ByteCount = cpu_to_le16(byte_count);
2876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2878 if (rc)
2879 cFYI(1, "Set POSIX ACL returned %d", rc);
2881 setACLerrorExit:
2882 cifs_buf_release(pSMB);
2883 if (rc == -EAGAIN)
2884 goto setAclRetry;
2885 return rc;
2888 /* BB fix tabs in this function FIXME BB */
2890 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2891 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2893 int rc = 0;
2894 struct smb_t2_qfi_req *pSMB = NULL;
2895 struct smb_t2_qfi_rsp *pSMBr = NULL;
2896 int bytes_returned;
2897 __u16 params, byte_count;
2899 cFYI(1, "In GetExtAttr");
2900 if (tcon == NULL)
2901 return -ENODEV;
2903 GetExtAttrRetry:
2904 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2905 (void **) &pSMBr);
2906 if (rc)
2907 return rc;
2909 params = 2 /* level */ + 2 /* fid */;
2910 pSMB->t2.TotalDataCount = 0;
2911 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2912 /* BB find exact max data count below from sess structure BB */
2913 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2914 pSMB->t2.MaxSetupCount = 0;
2915 pSMB->t2.Reserved = 0;
2916 pSMB->t2.Flags = 0;
2917 pSMB->t2.Timeout = 0;
2918 pSMB->t2.Reserved2 = 0;
2919 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2920 Fid) - 4);
2921 pSMB->t2.DataCount = 0;
2922 pSMB->t2.DataOffset = 0;
2923 pSMB->t2.SetupCount = 1;
2924 pSMB->t2.Reserved3 = 0;
2925 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2926 byte_count = params + 1 /* pad */ ;
2927 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2928 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2929 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2930 pSMB->Pad = 0;
2931 pSMB->Fid = netfid;
2932 pSMB->hdr.smb_buf_length += byte_count;
2933 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2935 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2936 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2937 if (rc) {
2938 cFYI(1, "error %d in GetExtAttr", rc);
2939 } else {
2940 /* decode response */
2941 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2942 if (rc || (pSMBr->ByteCount < 2))
2943 /* BB also check enough total bytes returned */
2944 /* If rc should we check for EOPNOSUPP and
2945 disable the srvino flag? or in caller? */
2946 rc = -EIO; /* bad smb */
2947 else {
2948 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2949 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2950 struct file_chattr_info *pfinfo;
2951 /* BB Do we need a cast or hash here ? */
2952 if (count != 16) {
2953 cFYI(1, "Illegal size ret in GetExtAttr");
2954 rc = -EIO;
2955 goto GetExtAttrOut;
2957 pfinfo = (struct file_chattr_info *)
2958 (data_offset + (char *) &pSMBr->hdr.Protocol);
2959 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2960 *pMask = le64_to_cpu(pfinfo->mask);
2963 GetExtAttrOut:
2964 cifs_buf_release(pSMB);
2965 if (rc == -EAGAIN)
2966 goto GetExtAttrRetry;
2967 return rc;
2970 #endif /* CONFIG_POSIX */
2972 #ifdef CONFIG_CIFS_ACL
2974 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
2975 * all NT TRANSACTS that we init here have total parm and data under about 400
2976 * bytes (to fit in small cifs buffer size), which is the case so far, it
2977 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
2978 * returned setup area) and MaxParameterCount (returned parms size) must be set
2979 * by caller
2981 static int
2982 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2983 const int parm_len, struct cifsTconInfo *tcon,
2984 void **ret_buf)
2986 int rc;
2987 __u32 temp_offset;
2988 struct smb_com_ntransact_req *pSMB;
2990 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2991 (void **)&pSMB);
2992 if (rc)
2993 return rc;
2994 *ret_buf = (void *)pSMB;
2995 pSMB->Reserved = 0;
2996 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2997 pSMB->TotalDataCount = 0;
2998 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2999 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3000 pSMB->ParameterCount = pSMB->TotalParameterCount;
3001 pSMB->DataCount = pSMB->TotalDataCount;
3002 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3003 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3004 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3005 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3006 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3007 pSMB->SubCommand = cpu_to_le16(sub_command);
3008 return 0;
3011 static int
3012 validate_ntransact(char *buf, char **ppparm, char **ppdata,
3013 __u32 *pparmlen, __u32 *pdatalen)
3015 char *end_of_smb;
3016 __u32 data_count, data_offset, parm_count, parm_offset;
3017 struct smb_com_ntransact_rsp *pSMBr;
3019 *pdatalen = 0;
3020 *pparmlen = 0;
3022 if (buf == NULL)
3023 return -EINVAL;
3025 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3027 /* ByteCount was converted from little endian in SendReceive */
3028 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
3029 (char *)&pSMBr->ByteCount;
3031 data_offset = le32_to_cpu(pSMBr->DataOffset);
3032 data_count = le32_to_cpu(pSMBr->DataCount);
3033 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3034 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3036 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3037 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3039 /* should we also check that parm and data areas do not overlap? */
3040 if (*ppparm > end_of_smb) {
3041 cFYI(1, "parms start after end of smb");
3042 return -EINVAL;
3043 } else if (parm_count + *ppparm > end_of_smb) {
3044 cFYI(1, "parm end after end of smb");
3045 return -EINVAL;
3046 } else if (*ppdata > end_of_smb) {
3047 cFYI(1, "data starts after end of smb");
3048 return -EINVAL;
3049 } else if (data_count + *ppdata > end_of_smb) {
3050 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3051 *ppdata, data_count, (data_count + *ppdata),
3052 end_of_smb, pSMBr);
3053 return -EINVAL;
3054 } else if (parm_count + data_count > pSMBr->ByteCount) {
3055 cFYI(1, "parm count and data count larger than SMB");
3056 return -EINVAL;
3058 *pdatalen = data_count;
3059 *pparmlen = parm_count;
3060 return 0;
3063 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3065 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3066 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3068 int rc = 0;
3069 int buf_type = 0;
3070 QUERY_SEC_DESC_REQ *pSMB;
3071 struct kvec iov[1];
3073 cFYI(1, "GetCifsACL");
3075 *pbuflen = 0;
3076 *acl_inf = NULL;
3078 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3079 8 /* parm len */, tcon, (void **) &pSMB);
3080 if (rc)
3081 return rc;
3083 pSMB->MaxParameterCount = cpu_to_le32(4);
3084 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3085 pSMB->MaxSetupCount = 0;
3086 pSMB->Fid = fid; /* file handle always le */
3087 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3088 CIFS_ACL_DACL);
3089 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3090 pSMB->hdr.smb_buf_length += 11;
3091 iov[0].iov_base = (char *)pSMB;
3092 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3094 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3095 CIFS_STD_OP);
3096 cifs_stats_inc(&tcon->num_acl_get);
3097 if (rc) {
3098 cFYI(1, "Send error in QuerySecDesc = %d", rc);
3099 } else { /* decode response */
3100 __le32 *parm;
3101 __u32 parm_len;
3102 __u32 acl_len;
3103 struct smb_com_ntransact_rsp *pSMBr;
3104 char *pdata;
3106 /* validate_nttransact */
3107 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3108 &pdata, &parm_len, pbuflen);
3109 if (rc)
3110 goto qsec_out;
3111 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3113 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
3115 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3116 rc = -EIO; /* bad smb */
3117 *pbuflen = 0;
3118 goto qsec_out;
3121 /* BB check that data area is minimum length and as big as acl_len */
3123 acl_len = le32_to_cpu(*parm);
3124 if (acl_len != *pbuflen) {
3125 cERROR(1, "acl length %d does not match %d",
3126 acl_len, *pbuflen);
3127 if (*pbuflen > acl_len)
3128 *pbuflen = acl_len;
3131 /* check if buffer is big enough for the acl
3132 header followed by the smallest SID */
3133 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3134 (*pbuflen >= 64 * 1024)) {
3135 cERROR(1, "bad acl length %d", *pbuflen);
3136 rc = -EINVAL;
3137 *pbuflen = 0;
3138 } else {
3139 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3140 if (*acl_inf == NULL) {
3141 *pbuflen = 0;
3142 rc = -ENOMEM;
3144 memcpy(*acl_inf, pdata, *pbuflen);
3147 qsec_out:
3148 if (buf_type == CIFS_SMALL_BUFFER)
3149 cifs_small_buf_release(iov[0].iov_base);
3150 else if (buf_type == CIFS_LARGE_BUFFER)
3151 cifs_buf_release(iov[0].iov_base);
3152 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3153 return rc;
3157 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3158 struct cifs_ntsd *pntsd, __u32 acllen)
3160 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3161 int rc = 0;
3162 int bytes_returned = 0;
3163 SET_SEC_DESC_REQ *pSMB = NULL;
3164 NTRANSACT_RSP *pSMBr = NULL;
3166 setCifsAclRetry:
3167 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3168 (void **) &pSMBr);
3169 if (rc)
3170 return (rc);
3172 pSMB->MaxSetupCount = 0;
3173 pSMB->Reserved = 0;
3175 param_count = 8;
3176 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3177 data_count = acllen;
3178 data_offset = param_offset + param_count;
3179 byte_count = 3 /* pad */ + param_count;
3181 pSMB->DataCount = cpu_to_le32(data_count);
3182 pSMB->TotalDataCount = pSMB->DataCount;
3183 pSMB->MaxParameterCount = cpu_to_le32(4);
3184 pSMB->MaxDataCount = cpu_to_le32(16384);
3185 pSMB->ParameterCount = cpu_to_le32(param_count);
3186 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3187 pSMB->TotalParameterCount = pSMB->ParameterCount;
3188 pSMB->DataOffset = cpu_to_le32(data_offset);
3189 pSMB->SetupCount = 0;
3190 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3191 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3193 pSMB->Fid = fid; /* file handle always le */
3194 pSMB->Reserved2 = 0;
3195 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3197 if (pntsd && acllen) {
3198 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3199 (char *) pntsd,
3200 acllen);
3201 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3203 } else
3204 pSMB->hdr.smb_buf_length += byte_count;
3206 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3207 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3209 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
3210 if (rc)
3211 cFYI(1, "Set CIFS ACL returned %d", rc);
3212 cifs_buf_release(pSMB);
3214 if (rc == -EAGAIN)
3215 goto setCifsAclRetry;
3217 return (rc);
3220 #endif /* CONFIG_CIFS_ACL */
3222 /* Legacy Query Path Information call for lookup to old servers such
3223 as Win9x/WinME */
3224 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3225 const unsigned char *searchName,
3226 FILE_ALL_INFO *pFinfo,
3227 const struct nls_table *nls_codepage, int remap)
3229 QUERY_INFORMATION_REQ *pSMB;
3230 QUERY_INFORMATION_RSP *pSMBr;
3231 int rc = 0;
3232 int bytes_returned;
3233 int name_len;
3235 cFYI(1, "In SMBQPath path %s", searchName);
3236 QInfRetry:
3237 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3238 (void **) &pSMBr);
3239 if (rc)
3240 return rc;
3242 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3243 name_len =
3244 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3245 PATH_MAX, nls_codepage, remap);
3246 name_len++; /* trailing null */
3247 name_len *= 2;
3248 } else {
3249 name_len = strnlen(searchName, PATH_MAX);
3250 name_len++; /* trailing null */
3251 strncpy(pSMB->FileName, searchName, name_len);
3253 pSMB->BufferFormat = 0x04;
3254 name_len++; /* account for buffer type byte */
3255 pSMB->hdr.smb_buf_length += (__u16) name_len;
3256 pSMB->ByteCount = cpu_to_le16(name_len);
3258 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3259 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3260 if (rc) {
3261 cFYI(1, "Send error in QueryInfo = %d", rc);
3262 } else if (pFinfo) {
3263 struct timespec ts;
3264 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3266 /* decode response */
3267 /* BB FIXME - add time zone adjustment BB */
3268 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3269 ts.tv_nsec = 0;
3270 ts.tv_sec = time;
3271 /* decode time fields */
3272 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3273 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3274 pFinfo->LastAccessTime = 0;
3275 pFinfo->AllocationSize =
3276 cpu_to_le64(le32_to_cpu(pSMBr->size));
3277 pFinfo->EndOfFile = pFinfo->AllocationSize;
3278 pFinfo->Attributes =
3279 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3280 } else
3281 rc = -EIO; /* bad buffer passed in */
3283 cifs_buf_release(pSMB);
3285 if (rc == -EAGAIN)
3286 goto QInfRetry;
3288 return rc;
3292 CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3293 u16 netfid, FILE_ALL_INFO *pFindData)
3295 struct smb_t2_qfi_req *pSMB = NULL;
3296 struct smb_t2_qfi_rsp *pSMBr = NULL;
3297 int rc = 0;
3298 int bytes_returned;
3299 __u16 params, byte_count;
3301 QFileInfoRetry:
3302 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3303 (void **) &pSMBr);
3304 if (rc)
3305 return rc;
3307 params = 2 /* level */ + 2 /* fid */;
3308 pSMB->t2.TotalDataCount = 0;
3309 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3310 /* BB find exact max data count below from sess structure BB */
3311 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3312 pSMB->t2.MaxSetupCount = 0;
3313 pSMB->t2.Reserved = 0;
3314 pSMB->t2.Flags = 0;
3315 pSMB->t2.Timeout = 0;
3316 pSMB->t2.Reserved2 = 0;
3317 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3318 Fid) - 4);
3319 pSMB->t2.DataCount = 0;
3320 pSMB->t2.DataOffset = 0;
3321 pSMB->t2.SetupCount = 1;
3322 pSMB->t2.Reserved3 = 0;
3323 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3324 byte_count = params + 1 /* pad */ ;
3325 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3326 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3327 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3328 pSMB->Pad = 0;
3329 pSMB->Fid = netfid;
3330 pSMB->hdr.smb_buf_length += byte_count;
3332 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3333 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3334 if (rc) {
3335 cFYI(1, "Send error in QPathInfo = %d", rc);
3336 } else { /* decode response */
3337 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3339 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3340 rc = -EIO;
3341 else if (pSMBr->ByteCount < 40)
3342 rc = -EIO; /* bad smb */
3343 else if (pFindData) {
3344 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3345 memcpy((char *) pFindData,
3346 (char *) &pSMBr->hdr.Protocol +
3347 data_offset, sizeof(FILE_ALL_INFO));
3348 } else
3349 rc = -ENOMEM;
3351 cifs_buf_release(pSMB);
3352 if (rc == -EAGAIN)
3353 goto QFileInfoRetry;
3355 return rc;
3359 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3360 const unsigned char *searchName,
3361 FILE_ALL_INFO *pFindData,
3362 int legacy /* old style infolevel */,
3363 const struct nls_table *nls_codepage, int remap)
3365 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3366 TRANSACTION2_QPI_REQ *pSMB = NULL;
3367 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3368 int rc = 0;
3369 int bytes_returned;
3370 int name_len;
3371 __u16 params, byte_count;
3373 /* cFYI(1, "In QPathInfo path %s", searchName); */
3374 QPathInfoRetry:
3375 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3376 (void **) &pSMBr);
3377 if (rc)
3378 return rc;
3380 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3381 name_len =
3382 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3383 PATH_MAX, nls_codepage, remap);
3384 name_len++; /* trailing null */
3385 name_len *= 2;
3386 } else { /* BB improve the check for buffer overruns BB */
3387 name_len = strnlen(searchName, PATH_MAX);
3388 name_len++; /* trailing null */
3389 strncpy(pSMB->FileName, searchName, name_len);
3392 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3393 pSMB->TotalDataCount = 0;
3394 pSMB->MaxParameterCount = cpu_to_le16(2);
3395 /* BB find exact max SMB PDU from sess structure BB */
3396 pSMB->MaxDataCount = cpu_to_le16(4000);
3397 pSMB->MaxSetupCount = 0;
3398 pSMB->Reserved = 0;
3399 pSMB->Flags = 0;
3400 pSMB->Timeout = 0;
3401 pSMB->Reserved2 = 0;
3402 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3403 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3404 pSMB->DataCount = 0;
3405 pSMB->DataOffset = 0;
3406 pSMB->SetupCount = 1;
3407 pSMB->Reserved3 = 0;
3408 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3409 byte_count = params + 1 /* pad */ ;
3410 pSMB->TotalParameterCount = cpu_to_le16(params);
3411 pSMB->ParameterCount = pSMB->TotalParameterCount;
3412 if (legacy)
3413 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3414 else
3415 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3416 pSMB->Reserved4 = 0;
3417 pSMB->hdr.smb_buf_length += byte_count;
3418 pSMB->ByteCount = cpu_to_le16(byte_count);
3420 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3421 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3422 if (rc) {
3423 cFYI(1, "Send error in QPathInfo = %d", rc);
3424 } else { /* decode response */
3425 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3427 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3428 rc = -EIO;
3429 else if (!legacy && (pSMBr->ByteCount < 40))
3430 rc = -EIO; /* bad smb */
3431 else if (legacy && (pSMBr->ByteCount < 24))
3432 rc = -EIO; /* 24 or 26 expected but we do not read
3433 last field */
3434 else if (pFindData) {
3435 int size;
3436 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3438 /* On legacy responses we do not read the last field,
3439 EAsize, fortunately since it varies by subdialect and
3440 also note it differs on Set vs. Get, ie two bytes or 4
3441 bytes depending but we don't care here */
3442 if (legacy)
3443 size = sizeof(FILE_INFO_STANDARD);
3444 else
3445 size = sizeof(FILE_ALL_INFO);
3446 memcpy((char *) pFindData,
3447 (char *) &pSMBr->hdr.Protocol +
3448 data_offset, size);
3449 } else
3450 rc = -ENOMEM;
3452 cifs_buf_release(pSMB);
3453 if (rc == -EAGAIN)
3454 goto QPathInfoRetry;
3456 return rc;
3460 CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3461 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3463 struct smb_t2_qfi_req *pSMB = NULL;
3464 struct smb_t2_qfi_rsp *pSMBr = NULL;
3465 int rc = 0;
3466 int bytes_returned;
3467 __u16 params, byte_count;
3469 UnixQFileInfoRetry:
3470 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3471 (void **) &pSMBr);
3472 if (rc)
3473 return rc;
3475 params = 2 /* level */ + 2 /* fid */;
3476 pSMB->t2.TotalDataCount = 0;
3477 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3478 /* BB find exact max data count below from sess structure BB */
3479 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3480 pSMB->t2.MaxSetupCount = 0;
3481 pSMB->t2.Reserved = 0;
3482 pSMB->t2.Flags = 0;
3483 pSMB->t2.Timeout = 0;
3484 pSMB->t2.Reserved2 = 0;
3485 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3486 Fid) - 4);
3487 pSMB->t2.DataCount = 0;
3488 pSMB->t2.DataOffset = 0;
3489 pSMB->t2.SetupCount = 1;
3490 pSMB->t2.Reserved3 = 0;
3491 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3492 byte_count = params + 1 /* pad */ ;
3493 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3494 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3495 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3496 pSMB->Pad = 0;
3497 pSMB->Fid = netfid;
3498 pSMB->hdr.smb_buf_length += byte_count;
3500 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3501 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3502 if (rc) {
3503 cFYI(1, "Send error in QPathInfo = %d", rc);
3504 } else { /* decode response */
3505 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3507 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3508 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
3509 "Unix Extensions can be disabled on mount "
3510 "by specifying the nosfu mount option.");
3511 rc = -EIO; /* bad smb */
3512 } else {
3513 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3514 memcpy((char *) pFindData,
3515 (char *) &pSMBr->hdr.Protocol +
3516 data_offset,
3517 sizeof(FILE_UNIX_BASIC_INFO));
3521 cifs_buf_release(pSMB);
3522 if (rc == -EAGAIN)
3523 goto UnixQFileInfoRetry;
3525 return rc;
3529 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3530 const unsigned char *searchName,
3531 FILE_UNIX_BASIC_INFO *pFindData,
3532 const struct nls_table *nls_codepage, int remap)
3534 /* SMB_QUERY_FILE_UNIX_BASIC */
3535 TRANSACTION2_QPI_REQ *pSMB = NULL;
3536 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3537 int rc = 0;
3538 int bytes_returned = 0;
3539 int name_len;
3540 __u16 params, byte_count;
3542 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
3543 UnixQPathInfoRetry:
3544 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3545 (void **) &pSMBr);
3546 if (rc)
3547 return rc;
3549 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3550 name_len =
3551 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3552 PATH_MAX, nls_codepage, remap);
3553 name_len++; /* trailing null */
3554 name_len *= 2;
3555 } else { /* BB improve the check for buffer overruns BB */
3556 name_len = strnlen(searchName, PATH_MAX);
3557 name_len++; /* trailing null */
3558 strncpy(pSMB->FileName, searchName, name_len);
3561 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3562 pSMB->TotalDataCount = 0;
3563 pSMB->MaxParameterCount = cpu_to_le16(2);
3564 /* BB find exact max SMB PDU from sess structure BB */
3565 pSMB->MaxDataCount = cpu_to_le16(4000);
3566 pSMB->MaxSetupCount = 0;
3567 pSMB->Reserved = 0;
3568 pSMB->Flags = 0;
3569 pSMB->Timeout = 0;
3570 pSMB->Reserved2 = 0;
3571 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3572 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3573 pSMB->DataCount = 0;
3574 pSMB->DataOffset = 0;
3575 pSMB->SetupCount = 1;
3576 pSMB->Reserved3 = 0;
3577 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3578 byte_count = params + 1 /* pad */ ;
3579 pSMB->TotalParameterCount = cpu_to_le16(params);
3580 pSMB->ParameterCount = pSMB->TotalParameterCount;
3581 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3582 pSMB->Reserved4 = 0;
3583 pSMB->hdr.smb_buf_length += byte_count;
3584 pSMB->ByteCount = cpu_to_le16(byte_count);
3586 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3587 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3588 if (rc) {
3589 cFYI(1, "Send error in QPathInfo = %d", rc);
3590 } else { /* decode response */
3591 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3593 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3594 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
3595 "Unix Extensions can be disabled on mount "
3596 "by specifying the nosfu mount option.");
3597 rc = -EIO; /* bad smb */
3598 } else {
3599 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3600 memcpy((char *) pFindData,
3601 (char *) &pSMBr->hdr.Protocol +
3602 data_offset,
3603 sizeof(FILE_UNIX_BASIC_INFO));
3606 cifs_buf_release(pSMB);
3607 if (rc == -EAGAIN)
3608 goto UnixQPathInfoRetry;
3610 return rc;
3613 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3615 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3616 const char *searchName,
3617 const struct nls_table *nls_codepage,
3618 __u16 *pnetfid,
3619 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3621 /* level 257 SMB_ */
3622 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3623 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3624 T2_FFIRST_RSP_PARMS *parms;
3625 int rc = 0;
3626 int bytes_returned = 0;
3627 int name_len;
3628 __u16 params, byte_count;
3630 cFYI(1, "In FindFirst for %s", searchName);
3632 findFirstRetry:
3633 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3634 (void **) &pSMBr);
3635 if (rc)
3636 return rc;
3638 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3639 name_len =
3640 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3641 PATH_MAX, nls_codepage, remap);
3642 /* We can not add the asterik earlier in case
3643 it got remapped to 0xF03A as if it were part of the
3644 directory name instead of a wildcard */
3645 name_len *= 2;
3646 pSMB->FileName[name_len] = dirsep;
3647 pSMB->FileName[name_len+1] = 0;
3648 pSMB->FileName[name_len+2] = '*';
3649 pSMB->FileName[name_len+3] = 0;
3650 name_len += 4; /* now the trailing null */
3651 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3652 pSMB->FileName[name_len+1] = 0;
3653 name_len += 2;
3654 } else { /* BB add check for overrun of SMB buf BB */
3655 name_len = strnlen(searchName, PATH_MAX);
3656 /* BB fix here and in unicode clause above ie
3657 if (name_len > buffersize-header)
3658 free buffer exit; BB */
3659 strncpy(pSMB->FileName, searchName, name_len);
3660 pSMB->FileName[name_len] = dirsep;
3661 pSMB->FileName[name_len+1] = '*';
3662 pSMB->FileName[name_len+2] = 0;
3663 name_len += 3;
3666 params = 12 + name_len /* includes null */ ;
3667 pSMB->TotalDataCount = 0; /* no EAs */
3668 pSMB->MaxParameterCount = cpu_to_le16(10);
3669 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3670 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3671 pSMB->MaxSetupCount = 0;
3672 pSMB->Reserved = 0;
3673 pSMB->Flags = 0;
3674 pSMB->Timeout = 0;
3675 pSMB->Reserved2 = 0;
3676 byte_count = params + 1 /* pad */ ;
3677 pSMB->TotalParameterCount = cpu_to_le16(params);
3678 pSMB->ParameterCount = pSMB->TotalParameterCount;
3679 pSMB->ParameterOffset = cpu_to_le16(
3680 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3681 - 4);
3682 pSMB->DataCount = 0;
3683 pSMB->DataOffset = 0;
3684 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3685 pSMB->Reserved3 = 0;
3686 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3687 pSMB->SearchAttributes =
3688 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3689 ATTR_DIRECTORY);
3690 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3691 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3692 CIFS_SEARCH_RETURN_RESUME);
3693 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3695 /* BB what should we set StorageType to? Does it matter? BB */
3696 pSMB->SearchStorageType = 0;
3697 pSMB->hdr.smb_buf_length += byte_count;
3698 pSMB->ByteCount = cpu_to_le16(byte_count);
3700 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3701 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3702 cifs_stats_inc(&tcon->num_ffirst);
3704 if (rc) {/* BB add logic to retry regular search if Unix search
3705 rejected unexpectedly by server */
3706 /* BB Add code to handle unsupported level rc */
3707 cFYI(1, "Error in FindFirst = %d", rc);
3709 cifs_buf_release(pSMB);
3711 /* BB eventually could optimize out free and realloc of buf */
3712 /* for this case */
3713 if (rc == -EAGAIN)
3714 goto findFirstRetry;
3715 } else { /* decode response */
3716 /* BB remember to free buffer if error BB */
3717 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3718 if (rc == 0) {
3719 unsigned int lnoff;
3721 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3722 psrch_inf->unicode = true;
3723 else
3724 psrch_inf->unicode = false;
3726 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3727 psrch_inf->smallBuf = 0;
3728 psrch_inf->srch_entries_start =
3729 (char *) &pSMBr->hdr.Protocol +
3730 le16_to_cpu(pSMBr->t2.DataOffset);
3731 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3732 le16_to_cpu(pSMBr->t2.ParameterOffset));
3734 if (parms->EndofSearch)
3735 psrch_inf->endOfSearch = true;
3736 else
3737 psrch_inf->endOfSearch = false;
3739 psrch_inf->entries_in_buffer =
3740 le16_to_cpu(parms->SearchCount);
3741 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3742 psrch_inf->entries_in_buffer;
3743 lnoff = le16_to_cpu(parms->LastNameOffset);
3744 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3745 lnoff) {
3746 cERROR(1, "ignoring corrupt resume name");
3747 psrch_inf->last_entry = NULL;
3748 return rc;
3751 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3752 lnoff;
3754 *pnetfid = parms->SearchHandle;
3755 } else {
3756 cifs_buf_release(pSMB);
3760 return rc;
3763 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3764 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3766 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3767 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3768 T2_FNEXT_RSP_PARMS *parms;
3769 char *response_data;
3770 int rc = 0;
3771 int bytes_returned, name_len;
3772 __u16 params, byte_count;
3774 cFYI(1, "In FindNext");
3776 if (psrch_inf->endOfSearch)
3777 return -ENOENT;
3779 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3780 (void **) &pSMBr);
3781 if (rc)
3782 return rc;
3784 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3785 byte_count = 0;
3786 pSMB->TotalDataCount = 0; /* no EAs */
3787 pSMB->MaxParameterCount = cpu_to_le16(8);
3788 pSMB->MaxDataCount =
3789 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3790 0xFFFFFF00);
3791 pSMB->MaxSetupCount = 0;
3792 pSMB->Reserved = 0;
3793 pSMB->Flags = 0;
3794 pSMB->Timeout = 0;
3795 pSMB->Reserved2 = 0;
3796 pSMB->ParameterOffset = cpu_to_le16(
3797 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3798 pSMB->DataCount = 0;
3799 pSMB->DataOffset = 0;
3800 pSMB->SetupCount = 1;
3801 pSMB->Reserved3 = 0;
3802 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3803 pSMB->SearchHandle = searchHandle; /* always kept as le */
3804 pSMB->SearchCount =
3805 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3806 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3807 pSMB->ResumeKey = psrch_inf->resume_key;
3808 pSMB->SearchFlags =
3809 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3811 name_len = psrch_inf->resume_name_len;
3812 params += name_len;
3813 if (name_len < PATH_MAX) {
3814 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3815 byte_count += name_len;
3816 /* 14 byte parm len above enough for 2 byte null terminator */
3817 pSMB->ResumeFileName[name_len] = 0;
3818 pSMB->ResumeFileName[name_len+1] = 0;
3819 } else {
3820 rc = -EINVAL;
3821 goto FNext2_err_exit;
3823 byte_count = params + 1 /* pad */ ;
3824 pSMB->TotalParameterCount = cpu_to_le16(params);
3825 pSMB->ParameterCount = pSMB->TotalParameterCount;
3826 pSMB->hdr.smb_buf_length += byte_count;
3827 pSMB->ByteCount = cpu_to_le16(byte_count);
3829 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3831 cifs_stats_inc(&tcon->num_fnext);
3832 if (rc) {
3833 if (rc == -EBADF) {
3834 psrch_inf->endOfSearch = true;
3835 cifs_buf_release(pSMB);
3836 rc = 0; /* search probably was closed at end of search*/
3837 } else
3838 cFYI(1, "FindNext returned = %d", rc);
3839 } else { /* decode response */
3840 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3842 if (rc == 0) {
3843 unsigned int lnoff;
3845 /* BB fixme add lock for file (srch_info) struct here */
3846 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3847 psrch_inf->unicode = true;
3848 else
3849 psrch_inf->unicode = false;
3850 response_data = (char *) &pSMBr->hdr.Protocol +
3851 le16_to_cpu(pSMBr->t2.ParameterOffset);
3852 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3853 response_data = (char *)&pSMBr->hdr.Protocol +
3854 le16_to_cpu(pSMBr->t2.DataOffset);
3855 if (psrch_inf->smallBuf)
3856 cifs_small_buf_release(
3857 psrch_inf->ntwrk_buf_start);
3858 else
3859 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3860 psrch_inf->srch_entries_start = response_data;
3861 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3862 psrch_inf->smallBuf = 0;
3863 if (parms->EndofSearch)
3864 psrch_inf->endOfSearch = true;
3865 else
3866 psrch_inf->endOfSearch = false;
3867 psrch_inf->entries_in_buffer =
3868 le16_to_cpu(parms->SearchCount);
3869 psrch_inf->index_of_last_entry +=
3870 psrch_inf->entries_in_buffer;
3871 lnoff = le16_to_cpu(parms->LastNameOffset);
3872 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3873 lnoff) {
3874 cERROR(1, "ignoring corrupt resume name");
3875 psrch_inf->last_entry = NULL;
3876 return rc;
3877 } else
3878 psrch_inf->last_entry =
3879 psrch_inf->srch_entries_start + lnoff;
3881 /* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3882 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
3884 /* BB fixme add unlock here */
3889 /* BB On error, should we leave previous search buf (and count and
3890 last entry fields) intact or free the previous one? */
3892 /* Note: On -EAGAIN error only caller can retry on handle based calls
3893 since file handle passed in no longer valid */
3894 FNext2_err_exit:
3895 if (rc != 0)
3896 cifs_buf_release(pSMB);
3897 return rc;
3901 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3902 const __u16 searchHandle)
3904 int rc = 0;
3905 FINDCLOSE_REQ *pSMB = NULL;
3907 cFYI(1, "In CIFSSMBFindClose");
3908 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3910 /* no sense returning error if session restarted
3911 as file handle has been closed */
3912 if (rc == -EAGAIN)
3913 return 0;
3914 if (rc)
3915 return rc;
3917 pSMB->FileID = searchHandle;
3918 pSMB->ByteCount = 0;
3919 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3920 if (rc)
3921 cERROR(1, "Send error in FindClose = %d", rc);
3923 cifs_stats_inc(&tcon->num_fclose);
3925 /* Since session is dead, search handle closed on server already */
3926 if (rc == -EAGAIN)
3927 rc = 0;
3929 return rc;
3933 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3934 const unsigned char *searchName,
3935 __u64 *inode_number,
3936 const struct nls_table *nls_codepage, int remap)
3938 int rc = 0;
3939 TRANSACTION2_QPI_REQ *pSMB = NULL;
3940 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3941 int name_len, bytes_returned;
3942 __u16 params, byte_count;
3944 cFYI(1, "In GetSrvInodeNum for %s", searchName);
3945 if (tcon == NULL)
3946 return -ENODEV;
3948 GetInodeNumberRetry:
3949 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3950 (void **) &pSMBr);
3951 if (rc)
3952 return rc;
3954 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3955 name_len =
3956 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3957 PATH_MAX, nls_codepage, remap);
3958 name_len++; /* trailing null */
3959 name_len *= 2;
3960 } else { /* BB improve the check for buffer overruns BB */
3961 name_len = strnlen(searchName, PATH_MAX);
3962 name_len++; /* trailing null */
3963 strncpy(pSMB->FileName, searchName, name_len);
3966 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3967 pSMB->TotalDataCount = 0;
3968 pSMB->MaxParameterCount = cpu_to_le16(2);
3969 /* BB find exact max data count below from sess structure BB */
3970 pSMB->MaxDataCount = cpu_to_le16(4000);
3971 pSMB->MaxSetupCount = 0;
3972 pSMB->Reserved = 0;
3973 pSMB->Flags = 0;
3974 pSMB->Timeout = 0;
3975 pSMB->Reserved2 = 0;
3976 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3977 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3978 pSMB->DataCount = 0;
3979 pSMB->DataOffset = 0;
3980 pSMB->SetupCount = 1;
3981 pSMB->Reserved3 = 0;
3982 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3983 byte_count = params + 1 /* pad */ ;
3984 pSMB->TotalParameterCount = cpu_to_le16(params);
3985 pSMB->ParameterCount = pSMB->TotalParameterCount;
3986 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3987 pSMB->Reserved4 = 0;
3988 pSMB->hdr.smb_buf_length += byte_count;
3989 pSMB->ByteCount = cpu_to_le16(byte_count);
3991 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3992 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3993 if (rc) {
3994 cFYI(1, "error %d in QueryInternalInfo", rc);
3995 } else {
3996 /* decode response */
3997 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3998 if (rc || (pSMBr->ByteCount < 2))
3999 /* BB also check enough total bytes returned */
4000 /* If rc should we check for EOPNOSUPP and
4001 disable the srvino flag? or in caller? */
4002 rc = -EIO; /* bad smb */
4003 else {
4004 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4005 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
4006 struct file_internal_info *pfinfo;
4007 /* BB Do we need a cast or hash here ? */
4008 if (count < 8) {
4009 cFYI(1, "Illegal size ret in QryIntrnlInf");
4010 rc = -EIO;
4011 goto GetInodeNumOut;
4013 pfinfo = (struct file_internal_info *)
4014 (data_offset + (char *) &pSMBr->hdr.Protocol);
4015 *inode_number = le64_to_cpu(pfinfo->UniqueId);
4018 GetInodeNumOut:
4019 cifs_buf_release(pSMB);
4020 if (rc == -EAGAIN)
4021 goto GetInodeNumberRetry;
4022 return rc;
4025 /* parses DFS refferal V3 structure
4026 * caller is responsible for freeing target_nodes
4027 * returns:
4028 * on success - 0
4029 * on failure - errno
4031 static int
4032 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
4033 unsigned int *num_of_nodes,
4034 struct dfs_info3_param **target_nodes,
4035 const struct nls_table *nls_codepage, int remap,
4036 const char *searchName)
4038 int i, rc = 0;
4039 char *data_end;
4040 bool is_unicode;
4041 struct dfs_referral_level_3 *ref;
4043 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4044 is_unicode = true;
4045 else
4046 is_unicode = false;
4047 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4049 if (*num_of_nodes < 1) {
4050 cERROR(1, "num_referrals: must be at least > 0,"
4051 "but we get num_referrals = %d\n", *num_of_nodes);
4052 rc = -EINVAL;
4053 goto parse_DFS_referrals_exit;
4056 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
4057 if (ref->VersionNumber != cpu_to_le16(3)) {
4058 cERROR(1, "Referrals of V%d version are not supported,"
4059 "should be V3", le16_to_cpu(ref->VersionNumber));
4060 rc = -EINVAL;
4061 goto parse_DFS_referrals_exit;
4064 /* get the upper boundary of the resp buffer */
4065 data_end = (char *)(&(pSMBr->PathConsumed)) +
4066 le16_to_cpu(pSMBr->t2.DataCount);
4068 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
4069 *num_of_nodes,
4070 le32_to_cpu(pSMBr->DFSFlags));
4072 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4073 *num_of_nodes, GFP_KERNEL);
4074 if (*target_nodes == NULL) {
4075 cERROR(1, "Failed to allocate buffer for target_nodes\n");
4076 rc = -ENOMEM;
4077 goto parse_DFS_referrals_exit;
4080 /* collect necessary data from referrals */
4081 for (i = 0; i < *num_of_nodes; i++) {
4082 char *temp;
4083 int max_len;
4084 struct dfs_info3_param *node = (*target_nodes)+i;
4086 node->flags = le32_to_cpu(pSMBr->DFSFlags);
4087 if (is_unicode) {
4088 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4089 GFP_KERNEL);
4090 if (tmp == NULL) {
4091 rc = -ENOMEM;
4092 goto parse_DFS_referrals_exit;
4094 cifsConvertToUCS((__le16 *) tmp, searchName,
4095 PATH_MAX, nls_codepage, remap);
4096 node->path_consumed = cifs_ucs2_bytes(tmp,
4097 le16_to_cpu(pSMBr->PathConsumed),
4098 nls_codepage);
4099 kfree(tmp);
4100 } else
4101 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4103 node->server_type = le16_to_cpu(ref->ServerType);
4104 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4106 /* copy DfsPath */
4107 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4108 max_len = data_end - temp;
4109 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4110 is_unicode, nls_codepage);
4111 if (!node->path_name) {
4112 rc = -ENOMEM;
4113 goto parse_DFS_referrals_exit;
4116 /* copy link target UNC */
4117 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4118 max_len = data_end - temp;
4119 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4120 is_unicode, nls_codepage);
4121 if (!node->node_name)
4122 rc = -ENOMEM;
4125 parse_DFS_referrals_exit:
4126 if (rc) {
4127 free_dfs_info_array(*target_nodes, *num_of_nodes);
4128 *target_nodes = NULL;
4129 *num_of_nodes = 0;
4131 return rc;
4135 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4136 const unsigned char *searchName,
4137 struct dfs_info3_param **target_nodes,
4138 unsigned int *num_of_nodes,
4139 const struct nls_table *nls_codepage, int remap)
4141 /* TRANS2_GET_DFS_REFERRAL */
4142 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4143 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4144 int rc = 0;
4145 int bytes_returned;
4146 int name_len;
4147 __u16 params, byte_count;
4148 *num_of_nodes = 0;
4149 *target_nodes = NULL;
4151 cFYI(1, "In GetDFSRefer the path %s", searchName);
4152 if (ses == NULL)
4153 return -ENODEV;
4154 getDFSRetry:
4155 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4156 (void **) &pSMBr);
4157 if (rc)
4158 return rc;
4160 /* server pointer checked in called function,
4161 but should never be null here anyway */
4162 pSMB->hdr.Mid = GetNextMid(ses->server);
4163 pSMB->hdr.Tid = ses->ipc_tid;
4164 pSMB->hdr.Uid = ses->Suid;
4165 if (ses->capabilities & CAP_STATUS32)
4166 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4167 if (ses->capabilities & CAP_DFS)
4168 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4170 if (ses->capabilities & CAP_UNICODE) {
4171 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4172 name_len =
4173 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4174 searchName, PATH_MAX, nls_codepage, remap);
4175 name_len++; /* trailing null */
4176 name_len *= 2;
4177 } else { /* BB improve the check for buffer overruns BB */
4178 name_len = strnlen(searchName, PATH_MAX);
4179 name_len++; /* trailing null */
4180 strncpy(pSMB->RequestFileName, searchName, name_len);
4183 if (ses->server) {
4184 if (ses->server->secMode &
4185 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4186 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4189 pSMB->hdr.Uid = ses->Suid;
4191 params = 2 /* level */ + name_len /*includes null */ ;
4192 pSMB->TotalDataCount = 0;
4193 pSMB->DataCount = 0;
4194 pSMB->DataOffset = 0;
4195 pSMB->MaxParameterCount = 0;
4196 /* BB find exact max SMB PDU from sess structure BB */
4197 pSMB->MaxDataCount = cpu_to_le16(4000);
4198 pSMB->MaxSetupCount = 0;
4199 pSMB->Reserved = 0;
4200 pSMB->Flags = 0;
4201 pSMB->Timeout = 0;
4202 pSMB->Reserved2 = 0;
4203 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4204 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4205 pSMB->SetupCount = 1;
4206 pSMB->Reserved3 = 0;
4207 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4208 byte_count = params + 3 /* pad */ ;
4209 pSMB->ParameterCount = cpu_to_le16(params);
4210 pSMB->TotalParameterCount = pSMB->ParameterCount;
4211 pSMB->MaxReferralLevel = cpu_to_le16(3);
4212 pSMB->hdr.smb_buf_length += byte_count;
4213 pSMB->ByteCount = cpu_to_le16(byte_count);
4215 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4216 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4217 if (rc) {
4218 cFYI(1, "Send error in GetDFSRefer = %d", rc);
4219 goto GetDFSRefExit;
4221 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4223 /* BB Also check if enough total bytes returned? */
4224 if (rc || (pSMBr->ByteCount < 17)) {
4225 rc = -EIO; /* bad smb */
4226 goto GetDFSRefExit;
4229 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
4230 pSMBr->ByteCount,
4231 le16_to_cpu(pSMBr->t2.DataOffset));
4233 /* parse returned result into more usable form */
4234 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4235 target_nodes, nls_codepage, remap,
4236 searchName);
4238 GetDFSRefExit:
4239 cifs_buf_release(pSMB);
4241 if (rc == -EAGAIN)
4242 goto getDFSRetry;
4244 return rc;
4247 /* Query File System Info such as free space to old servers such as Win 9x */
4249 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4251 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4252 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4253 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4254 FILE_SYSTEM_ALLOC_INFO *response_data;
4255 int rc = 0;
4256 int bytes_returned = 0;
4257 __u16 params, byte_count;
4259 cFYI(1, "OldQFSInfo");
4260 oldQFSInfoRetry:
4261 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4262 (void **) &pSMBr);
4263 if (rc)
4264 return rc;
4266 params = 2; /* level */
4267 pSMB->TotalDataCount = 0;
4268 pSMB->MaxParameterCount = cpu_to_le16(2);
4269 pSMB->MaxDataCount = cpu_to_le16(1000);
4270 pSMB->MaxSetupCount = 0;
4271 pSMB->Reserved = 0;
4272 pSMB->Flags = 0;
4273 pSMB->Timeout = 0;
4274 pSMB->Reserved2 = 0;
4275 byte_count = params + 1 /* pad */ ;
4276 pSMB->TotalParameterCount = cpu_to_le16(params);
4277 pSMB->ParameterCount = pSMB->TotalParameterCount;
4278 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4279 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4280 pSMB->DataCount = 0;
4281 pSMB->DataOffset = 0;
4282 pSMB->SetupCount = 1;
4283 pSMB->Reserved3 = 0;
4284 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4285 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4286 pSMB->hdr.smb_buf_length += byte_count;
4287 pSMB->ByteCount = cpu_to_le16(byte_count);
4289 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4290 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4291 if (rc) {
4292 cFYI(1, "Send error in QFSInfo = %d", rc);
4293 } else { /* decode response */
4294 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4296 if (rc || (pSMBr->ByteCount < 18))
4297 rc = -EIO; /* bad smb */
4298 else {
4299 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4300 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4301 pSMBr->ByteCount, data_offset);
4303 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4304 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4305 FSData->f_bsize =
4306 le16_to_cpu(response_data->BytesPerSector) *
4307 le32_to_cpu(response_data->
4308 SectorsPerAllocationUnit);
4309 FSData->f_blocks =
4310 le32_to_cpu(response_data->TotalAllocationUnits);
4311 FSData->f_bfree = FSData->f_bavail =
4312 le32_to_cpu(response_data->FreeAllocationUnits);
4313 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4314 (unsigned long long)FSData->f_blocks,
4315 (unsigned long long)FSData->f_bfree,
4316 FSData->f_bsize);
4319 cifs_buf_release(pSMB);
4321 if (rc == -EAGAIN)
4322 goto oldQFSInfoRetry;
4324 return rc;
4328 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4330 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4331 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4332 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4333 FILE_SYSTEM_INFO *response_data;
4334 int rc = 0;
4335 int bytes_returned = 0;
4336 __u16 params, byte_count;
4338 cFYI(1, "In QFSInfo");
4339 QFSInfoRetry:
4340 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4341 (void **) &pSMBr);
4342 if (rc)
4343 return rc;
4345 params = 2; /* level */
4346 pSMB->TotalDataCount = 0;
4347 pSMB->MaxParameterCount = cpu_to_le16(2);
4348 pSMB->MaxDataCount = cpu_to_le16(1000);
4349 pSMB->MaxSetupCount = 0;
4350 pSMB->Reserved = 0;
4351 pSMB->Flags = 0;
4352 pSMB->Timeout = 0;
4353 pSMB->Reserved2 = 0;
4354 byte_count = params + 1 /* pad */ ;
4355 pSMB->TotalParameterCount = cpu_to_le16(params);
4356 pSMB->ParameterCount = pSMB->TotalParameterCount;
4357 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4358 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4359 pSMB->DataCount = 0;
4360 pSMB->DataOffset = 0;
4361 pSMB->SetupCount = 1;
4362 pSMB->Reserved3 = 0;
4363 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4364 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4365 pSMB->hdr.smb_buf_length += byte_count;
4366 pSMB->ByteCount = cpu_to_le16(byte_count);
4368 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4369 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4370 if (rc) {
4371 cFYI(1, "Send error in QFSInfo = %d", rc);
4372 } else { /* decode response */
4373 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4375 if (rc || (pSMBr->ByteCount < 24))
4376 rc = -EIO; /* bad smb */
4377 else {
4378 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4380 response_data =
4381 (FILE_SYSTEM_INFO
4382 *) (((char *) &pSMBr->hdr.Protocol) +
4383 data_offset);
4384 FSData->f_bsize =
4385 le32_to_cpu(response_data->BytesPerSector) *
4386 le32_to_cpu(response_data->
4387 SectorsPerAllocationUnit);
4388 FSData->f_blocks =
4389 le64_to_cpu(response_data->TotalAllocationUnits);
4390 FSData->f_bfree = FSData->f_bavail =
4391 le64_to_cpu(response_data->FreeAllocationUnits);
4392 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4393 (unsigned long long)FSData->f_blocks,
4394 (unsigned long long)FSData->f_bfree,
4395 FSData->f_bsize);
4398 cifs_buf_release(pSMB);
4400 if (rc == -EAGAIN)
4401 goto QFSInfoRetry;
4403 return rc;
4407 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4409 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4410 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4411 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4412 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4413 int rc = 0;
4414 int bytes_returned = 0;
4415 __u16 params, byte_count;
4417 cFYI(1, "In QFSAttributeInfo");
4418 QFSAttributeRetry:
4419 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4420 (void **) &pSMBr);
4421 if (rc)
4422 return rc;
4424 params = 2; /* level */
4425 pSMB->TotalDataCount = 0;
4426 pSMB->MaxParameterCount = cpu_to_le16(2);
4427 /* BB find exact max SMB PDU from sess structure BB */
4428 pSMB->MaxDataCount = cpu_to_le16(1000);
4429 pSMB->MaxSetupCount = 0;
4430 pSMB->Reserved = 0;
4431 pSMB->Flags = 0;
4432 pSMB->Timeout = 0;
4433 pSMB->Reserved2 = 0;
4434 byte_count = params + 1 /* pad */ ;
4435 pSMB->TotalParameterCount = cpu_to_le16(params);
4436 pSMB->ParameterCount = pSMB->TotalParameterCount;
4437 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4438 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4439 pSMB->DataCount = 0;
4440 pSMB->DataOffset = 0;
4441 pSMB->SetupCount = 1;
4442 pSMB->Reserved3 = 0;
4443 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4444 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4445 pSMB->hdr.smb_buf_length += byte_count;
4446 pSMB->ByteCount = cpu_to_le16(byte_count);
4448 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4449 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4450 if (rc) {
4451 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
4452 } else { /* decode response */
4453 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4455 if (rc || (pSMBr->ByteCount < 13)) {
4456 /* BB also check if enough bytes returned */
4457 rc = -EIO; /* bad smb */
4458 } else {
4459 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4460 response_data =
4461 (FILE_SYSTEM_ATTRIBUTE_INFO
4462 *) (((char *) &pSMBr->hdr.Protocol) +
4463 data_offset);
4464 memcpy(&tcon->fsAttrInfo, response_data,
4465 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4468 cifs_buf_release(pSMB);
4470 if (rc == -EAGAIN)
4471 goto QFSAttributeRetry;
4473 return rc;
4477 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4479 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4480 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4481 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4482 FILE_SYSTEM_DEVICE_INFO *response_data;
4483 int rc = 0;
4484 int bytes_returned = 0;
4485 __u16 params, byte_count;
4487 cFYI(1, "In QFSDeviceInfo");
4488 QFSDeviceRetry:
4489 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4490 (void **) &pSMBr);
4491 if (rc)
4492 return rc;
4494 params = 2; /* level */
4495 pSMB->TotalDataCount = 0;
4496 pSMB->MaxParameterCount = cpu_to_le16(2);
4497 /* BB find exact max SMB PDU from sess structure BB */
4498 pSMB->MaxDataCount = cpu_to_le16(1000);
4499 pSMB->MaxSetupCount = 0;
4500 pSMB->Reserved = 0;
4501 pSMB->Flags = 0;
4502 pSMB->Timeout = 0;
4503 pSMB->Reserved2 = 0;
4504 byte_count = params + 1 /* pad */ ;
4505 pSMB->TotalParameterCount = cpu_to_le16(params);
4506 pSMB->ParameterCount = pSMB->TotalParameterCount;
4507 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4508 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4510 pSMB->DataCount = 0;
4511 pSMB->DataOffset = 0;
4512 pSMB->SetupCount = 1;
4513 pSMB->Reserved3 = 0;
4514 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4515 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4516 pSMB->hdr.smb_buf_length += byte_count;
4517 pSMB->ByteCount = cpu_to_le16(byte_count);
4519 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4520 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4521 if (rc) {
4522 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
4523 } else { /* decode response */
4524 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4526 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4527 rc = -EIO; /* bad smb */
4528 else {
4529 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4530 response_data =
4531 (FILE_SYSTEM_DEVICE_INFO *)
4532 (((char *) &pSMBr->hdr.Protocol) +
4533 data_offset);
4534 memcpy(&tcon->fsDevInfo, response_data,
4535 sizeof(FILE_SYSTEM_DEVICE_INFO));
4538 cifs_buf_release(pSMB);
4540 if (rc == -EAGAIN)
4541 goto QFSDeviceRetry;
4543 return rc;
4547 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4549 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4550 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4551 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4552 FILE_SYSTEM_UNIX_INFO *response_data;
4553 int rc = 0;
4554 int bytes_returned = 0;
4555 __u16 params, byte_count;
4557 cFYI(1, "In QFSUnixInfo");
4558 QFSUnixRetry:
4559 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4560 (void **) &pSMB, (void **) &pSMBr);
4561 if (rc)
4562 return rc;
4564 params = 2; /* level */
4565 pSMB->TotalDataCount = 0;
4566 pSMB->DataCount = 0;
4567 pSMB->DataOffset = 0;
4568 pSMB->MaxParameterCount = cpu_to_le16(2);
4569 /* BB find exact max SMB PDU from sess structure BB */
4570 pSMB->MaxDataCount = cpu_to_le16(100);
4571 pSMB->MaxSetupCount = 0;
4572 pSMB->Reserved = 0;
4573 pSMB->Flags = 0;
4574 pSMB->Timeout = 0;
4575 pSMB->Reserved2 = 0;
4576 byte_count = params + 1 /* pad */ ;
4577 pSMB->ParameterCount = cpu_to_le16(params);
4578 pSMB->TotalParameterCount = pSMB->ParameterCount;
4579 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4580 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4581 pSMB->SetupCount = 1;
4582 pSMB->Reserved3 = 0;
4583 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4584 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4585 pSMB->hdr.smb_buf_length += byte_count;
4586 pSMB->ByteCount = cpu_to_le16(byte_count);
4588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4589 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4590 if (rc) {
4591 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
4592 } else { /* decode response */
4593 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4595 if (rc || (pSMBr->ByteCount < 13)) {
4596 rc = -EIO; /* bad smb */
4597 } else {
4598 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4599 response_data =
4600 (FILE_SYSTEM_UNIX_INFO
4601 *) (((char *) &pSMBr->hdr.Protocol) +
4602 data_offset);
4603 memcpy(&tcon->fsUnixInfo, response_data,
4604 sizeof(FILE_SYSTEM_UNIX_INFO));
4607 cifs_buf_release(pSMB);
4609 if (rc == -EAGAIN)
4610 goto QFSUnixRetry;
4613 return rc;
4617 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4619 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4620 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4621 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4622 int rc = 0;
4623 int bytes_returned = 0;
4624 __u16 params, param_offset, offset, byte_count;
4626 cFYI(1, "In SETFSUnixInfo");
4627 SETFSUnixRetry:
4628 /* BB switch to small buf init to save memory */
4629 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4630 (void **) &pSMB, (void **) &pSMBr);
4631 if (rc)
4632 return rc;
4634 params = 4; /* 2 bytes zero followed by info level. */
4635 pSMB->MaxSetupCount = 0;
4636 pSMB->Reserved = 0;
4637 pSMB->Flags = 0;
4638 pSMB->Timeout = 0;
4639 pSMB->Reserved2 = 0;
4640 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4641 - 4;
4642 offset = param_offset + params;
4644 pSMB->MaxParameterCount = cpu_to_le16(4);
4645 /* BB find exact max SMB PDU from sess structure BB */
4646 pSMB->MaxDataCount = cpu_to_le16(100);
4647 pSMB->SetupCount = 1;
4648 pSMB->Reserved3 = 0;
4649 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4650 byte_count = 1 /* pad */ + params + 12;
4652 pSMB->DataCount = cpu_to_le16(12);
4653 pSMB->ParameterCount = cpu_to_le16(params);
4654 pSMB->TotalDataCount = pSMB->DataCount;
4655 pSMB->TotalParameterCount = pSMB->ParameterCount;
4656 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4657 pSMB->DataOffset = cpu_to_le16(offset);
4659 /* Params. */
4660 pSMB->FileNum = 0;
4661 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4663 /* Data. */
4664 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4665 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4666 pSMB->ClientUnixCap = cpu_to_le64(cap);
4668 pSMB->hdr.smb_buf_length += byte_count;
4669 pSMB->ByteCount = cpu_to_le16(byte_count);
4671 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4672 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4673 if (rc) {
4674 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
4675 } else { /* decode response */
4676 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4677 if (rc)
4678 rc = -EIO; /* bad smb */
4680 cifs_buf_release(pSMB);
4682 if (rc == -EAGAIN)
4683 goto SETFSUnixRetry;
4685 return rc;
4691 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4692 struct kstatfs *FSData)
4694 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4695 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4696 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4697 FILE_SYSTEM_POSIX_INFO *response_data;
4698 int rc = 0;
4699 int bytes_returned = 0;
4700 __u16 params, byte_count;
4702 cFYI(1, "In QFSPosixInfo");
4703 QFSPosixRetry:
4704 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4705 (void **) &pSMBr);
4706 if (rc)
4707 return rc;
4709 params = 2; /* level */
4710 pSMB->TotalDataCount = 0;
4711 pSMB->DataCount = 0;
4712 pSMB->DataOffset = 0;
4713 pSMB->MaxParameterCount = cpu_to_le16(2);
4714 /* BB find exact max SMB PDU from sess structure BB */
4715 pSMB->MaxDataCount = cpu_to_le16(100);
4716 pSMB->MaxSetupCount = 0;
4717 pSMB->Reserved = 0;
4718 pSMB->Flags = 0;
4719 pSMB->Timeout = 0;
4720 pSMB->Reserved2 = 0;
4721 byte_count = params + 1 /* pad */ ;
4722 pSMB->ParameterCount = cpu_to_le16(params);
4723 pSMB->TotalParameterCount = pSMB->ParameterCount;
4724 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4725 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4726 pSMB->SetupCount = 1;
4727 pSMB->Reserved3 = 0;
4728 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4729 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4730 pSMB->hdr.smb_buf_length += byte_count;
4731 pSMB->ByteCount = cpu_to_le16(byte_count);
4733 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4734 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4735 if (rc) {
4736 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
4737 } else { /* decode response */
4738 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4740 if (rc || (pSMBr->ByteCount < 13)) {
4741 rc = -EIO; /* bad smb */
4742 } else {
4743 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4744 response_data =
4745 (FILE_SYSTEM_POSIX_INFO
4746 *) (((char *) &pSMBr->hdr.Protocol) +
4747 data_offset);
4748 FSData->f_bsize =
4749 le32_to_cpu(response_data->BlockSize);
4750 FSData->f_blocks =
4751 le64_to_cpu(response_data->TotalBlocks);
4752 FSData->f_bfree =
4753 le64_to_cpu(response_data->BlocksAvail);
4754 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4755 FSData->f_bavail = FSData->f_bfree;
4756 } else {
4757 FSData->f_bavail =
4758 le64_to_cpu(response_data->UserBlocksAvail);
4760 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4761 FSData->f_files =
4762 le64_to_cpu(response_data->TotalFileNodes);
4763 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4764 FSData->f_ffree =
4765 le64_to_cpu(response_data->FreeFileNodes);
4768 cifs_buf_release(pSMB);
4770 if (rc == -EAGAIN)
4771 goto QFSPosixRetry;
4773 return rc;
4777 /* We can not use write of zero bytes trick to
4778 set file size due to need for large file support. Also note that
4779 this SetPathInfo is preferred to SetFileInfo based method in next
4780 routine which is only needed to work around a sharing violation bug
4781 in Samba which this routine can run into */
4784 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4785 __u64 size, bool SetAllocation,
4786 const struct nls_table *nls_codepage, int remap)
4788 struct smb_com_transaction2_spi_req *pSMB = NULL;
4789 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4790 struct file_end_of_file_info *parm_data;
4791 int name_len;
4792 int rc = 0;
4793 int bytes_returned = 0;
4794 __u16 params, byte_count, data_count, param_offset, offset;
4796 cFYI(1, "In SetEOF");
4797 SetEOFRetry:
4798 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4799 (void **) &pSMBr);
4800 if (rc)
4801 return rc;
4803 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4804 name_len =
4805 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4806 PATH_MAX, nls_codepage, remap);
4807 name_len++; /* trailing null */
4808 name_len *= 2;
4809 } else { /* BB improve the check for buffer overruns BB */
4810 name_len = strnlen(fileName, PATH_MAX);
4811 name_len++; /* trailing null */
4812 strncpy(pSMB->FileName, fileName, name_len);
4814 params = 6 + name_len;
4815 data_count = sizeof(struct file_end_of_file_info);
4816 pSMB->MaxParameterCount = cpu_to_le16(2);
4817 pSMB->MaxDataCount = cpu_to_le16(4100);
4818 pSMB->MaxSetupCount = 0;
4819 pSMB->Reserved = 0;
4820 pSMB->Flags = 0;
4821 pSMB->Timeout = 0;
4822 pSMB->Reserved2 = 0;
4823 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4824 InformationLevel) - 4;
4825 offset = param_offset + params;
4826 if (SetAllocation) {
4827 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4828 pSMB->InformationLevel =
4829 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4830 else
4831 pSMB->InformationLevel =
4832 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4833 } else /* Set File Size */ {
4834 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4835 pSMB->InformationLevel =
4836 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4837 else
4838 pSMB->InformationLevel =
4839 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4842 parm_data =
4843 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4844 offset);
4845 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4846 pSMB->DataOffset = cpu_to_le16(offset);
4847 pSMB->SetupCount = 1;
4848 pSMB->Reserved3 = 0;
4849 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4850 byte_count = 3 /* pad */ + params + data_count;
4851 pSMB->DataCount = cpu_to_le16(data_count);
4852 pSMB->TotalDataCount = pSMB->DataCount;
4853 pSMB->ParameterCount = cpu_to_le16(params);
4854 pSMB->TotalParameterCount = pSMB->ParameterCount;
4855 pSMB->Reserved4 = 0;
4856 pSMB->hdr.smb_buf_length += byte_count;
4857 parm_data->FileSize = cpu_to_le64(size);
4858 pSMB->ByteCount = cpu_to_le16(byte_count);
4859 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4860 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4861 if (rc)
4862 cFYI(1, "SetPathInfo (file size) returned %d", rc);
4864 cifs_buf_release(pSMB);
4866 if (rc == -EAGAIN)
4867 goto SetEOFRetry;
4869 return rc;
4873 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4874 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4876 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4877 char *data_offset;
4878 struct file_end_of_file_info *parm_data;
4879 int rc = 0;
4880 __u16 params, param_offset, offset, byte_count, count;
4882 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4883 (long long)size);
4884 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4886 if (rc)
4887 return rc;
4889 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4890 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4892 params = 6;
4893 pSMB->MaxSetupCount = 0;
4894 pSMB->Reserved = 0;
4895 pSMB->Flags = 0;
4896 pSMB->Timeout = 0;
4897 pSMB->Reserved2 = 0;
4898 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4899 offset = param_offset + params;
4901 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4903 count = sizeof(struct file_end_of_file_info);
4904 pSMB->MaxParameterCount = cpu_to_le16(2);
4905 /* BB find exact max SMB PDU from sess structure BB */
4906 pSMB->MaxDataCount = cpu_to_le16(1000);
4907 pSMB->SetupCount = 1;
4908 pSMB->Reserved3 = 0;
4909 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4910 byte_count = 3 /* pad */ + params + count;
4911 pSMB->DataCount = cpu_to_le16(count);
4912 pSMB->ParameterCount = cpu_to_le16(params);
4913 pSMB->TotalDataCount = pSMB->DataCount;
4914 pSMB->TotalParameterCount = pSMB->ParameterCount;
4915 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4916 parm_data =
4917 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4918 + offset);
4919 pSMB->DataOffset = cpu_to_le16(offset);
4920 parm_data->FileSize = cpu_to_le64(size);
4921 pSMB->Fid = fid;
4922 if (SetAllocation) {
4923 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4924 pSMB->InformationLevel =
4925 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4926 else
4927 pSMB->InformationLevel =
4928 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4929 } else /* Set File Size */ {
4930 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4931 pSMB->InformationLevel =
4932 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4933 else
4934 pSMB->InformationLevel =
4935 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4937 pSMB->Reserved4 = 0;
4938 pSMB->hdr.smb_buf_length += byte_count;
4939 pSMB->ByteCount = cpu_to_le16(byte_count);
4940 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4941 if (rc) {
4942 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
4945 /* Note: On -EAGAIN error only caller can retry on handle based calls
4946 since file handle passed in no longer valid */
4948 return rc;
4951 /* Some legacy servers such as NT4 require that the file times be set on
4952 an open handle, rather than by pathname - this is awkward due to
4953 potential access conflicts on the open, but it is unavoidable for these
4954 old servers since the only other choice is to go from 100 nanosecond DCE
4955 time and resort to the original setpathinfo level which takes the ancient
4956 DOS time format with 2 second granularity */
4958 CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4959 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4961 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4962 char *data_offset;
4963 int rc = 0;
4964 __u16 params, param_offset, offset, byte_count, count;
4966 cFYI(1, "Set Times (via SetFileInfo)");
4967 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4969 if (rc)
4970 return rc;
4972 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4973 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4975 params = 6;
4976 pSMB->MaxSetupCount = 0;
4977 pSMB->Reserved = 0;
4978 pSMB->Flags = 0;
4979 pSMB->Timeout = 0;
4980 pSMB->Reserved2 = 0;
4981 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4982 offset = param_offset + params;
4984 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4986 count = sizeof(FILE_BASIC_INFO);
4987 pSMB->MaxParameterCount = cpu_to_le16(2);
4988 /* BB find max SMB PDU from sess */
4989 pSMB->MaxDataCount = cpu_to_le16(1000);
4990 pSMB->SetupCount = 1;
4991 pSMB->Reserved3 = 0;
4992 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4993 byte_count = 3 /* pad */ + params + count;
4994 pSMB->DataCount = cpu_to_le16(count);
4995 pSMB->ParameterCount = cpu_to_le16(params);
4996 pSMB->TotalDataCount = pSMB->DataCount;
4997 pSMB->TotalParameterCount = pSMB->ParameterCount;
4998 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4999 pSMB->DataOffset = cpu_to_le16(offset);
5000 pSMB->Fid = fid;
5001 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5002 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5003 else
5004 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5005 pSMB->Reserved4 = 0;
5006 pSMB->hdr.smb_buf_length += byte_count;
5007 pSMB->ByteCount = cpu_to_le16(byte_count);
5008 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5009 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5010 if (rc)
5011 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
5013 /* Note: On -EAGAIN error only caller can retry on handle based calls
5014 since file handle passed in no longer valid */
5016 return rc;
5020 CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5021 bool delete_file, __u16 fid, __u32 pid_of_opener)
5023 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5024 char *data_offset;
5025 int rc = 0;
5026 __u16 params, param_offset, offset, byte_count, count;
5028 cFYI(1, "Set File Disposition (via SetFileInfo)");
5029 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5031 if (rc)
5032 return rc;
5034 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5035 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5037 params = 6;
5038 pSMB->MaxSetupCount = 0;
5039 pSMB->Reserved = 0;
5040 pSMB->Flags = 0;
5041 pSMB->Timeout = 0;
5042 pSMB->Reserved2 = 0;
5043 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5044 offset = param_offset + params;
5046 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5048 count = 1;
5049 pSMB->MaxParameterCount = cpu_to_le16(2);
5050 /* BB find max SMB PDU from sess */
5051 pSMB->MaxDataCount = cpu_to_le16(1000);
5052 pSMB->SetupCount = 1;
5053 pSMB->Reserved3 = 0;
5054 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5055 byte_count = 3 /* pad */ + params + count;
5056 pSMB->DataCount = cpu_to_le16(count);
5057 pSMB->ParameterCount = cpu_to_le16(params);
5058 pSMB->TotalDataCount = pSMB->DataCount;
5059 pSMB->TotalParameterCount = pSMB->ParameterCount;
5060 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5061 pSMB->DataOffset = cpu_to_le16(offset);
5062 pSMB->Fid = fid;
5063 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5064 pSMB->Reserved4 = 0;
5065 pSMB->hdr.smb_buf_length += byte_count;
5066 pSMB->ByteCount = cpu_to_le16(byte_count);
5067 *data_offset = delete_file ? 1 : 0;
5068 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5069 if (rc)
5070 cFYI(1, "Send error in SetFileDisposition = %d", rc);
5072 return rc;
5076 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5077 const char *fileName, const FILE_BASIC_INFO *data,
5078 const struct nls_table *nls_codepage, int remap)
5080 TRANSACTION2_SPI_REQ *pSMB = NULL;
5081 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5082 int name_len;
5083 int rc = 0;
5084 int bytes_returned = 0;
5085 char *data_offset;
5086 __u16 params, param_offset, offset, byte_count, count;
5088 cFYI(1, "In SetTimes");
5090 SetTimesRetry:
5091 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5092 (void **) &pSMBr);
5093 if (rc)
5094 return rc;
5096 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5097 name_len =
5098 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5099 PATH_MAX, nls_codepage, remap);
5100 name_len++; /* trailing null */
5101 name_len *= 2;
5102 } else { /* BB improve the check for buffer overruns BB */
5103 name_len = strnlen(fileName, PATH_MAX);
5104 name_len++; /* trailing null */
5105 strncpy(pSMB->FileName, fileName, name_len);
5108 params = 6 + name_len;
5109 count = sizeof(FILE_BASIC_INFO);
5110 pSMB->MaxParameterCount = cpu_to_le16(2);
5111 /* BB find max SMB PDU from sess structure BB */
5112 pSMB->MaxDataCount = cpu_to_le16(1000);
5113 pSMB->MaxSetupCount = 0;
5114 pSMB->Reserved = 0;
5115 pSMB->Flags = 0;
5116 pSMB->Timeout = 0;
5117 pSMB->Reserved2 = 0;
5118 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5119 InformationLevel) - 4;
5120 offset = param_offset + params;
5121 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5122 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5123 pSMB->DataOffset = cpu_to_le16(offset);
5124 pSMB->SetupCount = 1;
5125 pSMB->Reserved3 = 0;
5126 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5127 byte_count = 3 /* pad */ + params + count;
5129 pSMB->DataCount = cpu_to_le16(count);
5130 pSMB->ParameterCount = cpu_to_le16(params);
5131 pSMB->TotalDataCount = pSMB->DataCount;
5132 pSMB->TotalParameterCount = pSMB->ParameterCount;
5133 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5134 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5135 else
5136 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5137 pSMB->Reserved4 = 0;
5138 pSMB->hdr.smb_buf_length += byte_count;
5139 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5140 pSMB->ByteCount = cpu_to_le16(byte_count);
5141 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5142 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5143 if (rc)
5144 cFYI(1, "SetPathInfo (times) returned %d", rc);
5146 cifs_buf_release(pSMB);
5148 if (rc == -EAGAIN)
5149 goto SetTimesRetry;
5151 return rc;
5154 /* Can not be used to set time stamps yet (due to old DOS time format) */
5155 /* Can be used to set attributes */
5156 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5157 handling it anyway and NT4 was what we thought it would be needed for
5158 Do not delete it until we prove whether needed for Win9x though */
5160 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5161 __u16 dos_attrs, const struct nls_table *nls_codepage)
5163 SETATTR_REQ *pSMB = NULL;
5164 SETATTR_RSP *pSMBr = NULL;
5165 int rc = 0;
5166 int bytes_returned;
5167 int name_len;
5169 cFYI(1, "In SetAttrLegacy");
5171 SetAttrLgcyRetry:
5172 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5173 (void **) &pSMBr);
5174 if (rc)
5175 return rc;
5177 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5178 name_len =
5179 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
5180 PATH_MAX, nls_codepage);
5181 name_len++; /* trailing null */
5182 name_len *= 2;
5183 } else { /* BB improve the check for buffer overruns BB */
5184 name_len = strnlen(fileName, PATH_MAX);
5185 name_len++; /* trailing null */
5186 strncpy(pSMB->fileName, fileName, name_len);
5188 pSMB->attr = cpu_to_le16(dos_attrs);
5189 pSMB->BufferFormat = 0x04;
5190 pSMB->hdr.smb_buf_length += name_len + 1;
5191 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5192 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5193 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5194 if (rc)
5195 cFYI(1, "Error in LegacySetAttr = %d", rc);
5197 cifs_buf_release(pSMB);
5199 if (rc == -EAGAIN)
5200 goto SetAttrLgcyRetry;
5202 return rc;
5204 #endif /* temporarily unneeded SetAttr legacy function */
5206 static void
5207 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5208 const struct cifs_unix_set_info_args *args)
5210 u64 mode = args->mode;
5213 * Samba server ignores set of file size to zero due to bugs in some
5214 * older clients, but we should be precise - we use SetFileSize to
5215 * set file size and do not want to truncate file size to zero
5216 * accidently as happened on one Samba server beta by putting
5217 * zero instead of -1 here
5219 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5220 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5221 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5222 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5223 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5224 data_offset->Uid = cpu_to_le64(args->uid);
5225 data_offset->Gid = cpu_to_le64(args->gid);
5226 /* better to leave device as zero when it is */
5227 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5228 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5229 data_offset->Permissions = cpu_to_le64(mode);
5231 if (S_ISREG(mode))
5232 data_offset->Type = cpu_to_le32(UNIX_FILE);
5233 else if (S_ISDIR(mode))
5234 data_offset->Type = cpu_to_le32(UNIX_DIR);
5235 else if (S_ISLNK(mode))
5236 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5237 else if (S_ISCHR(mode))
5238 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5239 else if (S_ISBLK(mode))
5240 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5241 else if (S_ISFIFO(mode))
5242 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5243 else if (S_ISSOCK(mode))
5244 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5248 CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5249 const struct cifs_unix_set_info_args *args,
5250 u16 fid, u32 pid_of_opener)
5252 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5253 FILE_UNIX_BASIC_INFO *data_offset;
5254 int rc = 0;
5255 u16 params, param_offset, offset, byte_count, count;
5257 cFYI(1, "Set Unix Info (via SetFileInfo)");
5258 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5260 if (rc)
5261 return rc;
5263 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5264 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5266 params = 6;
5267 pSMB->MaxSetupCount = 0;
5268 pSMB->Reserved = 0;
5269 pSMB->Flags = 0;
5270 pSMB->Timeout = 0;
5271 pSMB->Reserved2 = 0;
5272 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5273 offset = param_offset + params;
5275 data_offset = (FILE_UNIX_BASIC_INFO *)
5276 ((char *)(&pSMB->hdr.Protocol) + offset);
5277 count = sizeof(FILE_UNIX_BASIC_INFO);
5279 pSMB->MaxParameterCount = cpu_to_le16(2);
5280 /* BB find max SMB PDU from sess */
5281 pSMB->MaxDataCount = cpu_to_le16(1000);
5282 pSMB->SetupCount = 1;
5283 pSMB->Reserved3 = 0;
5284 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5285 byte_count = 3 /* pad */ + params + count;
5286 pSMB->DataCount = cpu_to_le16(count);
5287 pSMB->ParameterCount = cpu_to_le16(params);
5288 pSMB->TotalDataCount = pSMB->DataCount;
5289 pSMB->TotalParameterCount = pSMB->ParameterCount;
5290 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5291 pSMB->DataOffset = cpu_to_le16(offset);
5292 pSMB->Fid = fid;
5293 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5294 pSMB->Reserved4 = 0;
5295 pSMB->hdr.smb_buf_length += byte_count;
5296 pSMB->ByteCount = cpu_to_le16(byte_count);
5298 cifs_fill_unix_set_info(data_offset, args);
5300 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5301 if (rc)
5302 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
5304 /* Note: On -EAGAIN error only caller can retry on handle based calls
5305 since file handle passed in no longer valid */
5307 return rc;
5311 CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5312 const struct cifs_unix_set_info_args *args,
5313 const struct nls_table *nls_codepage, int remap)
5315 TRANSACTION2_SPI_REQ *pSMB = NULL;
5316 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5317 int name_len;
5318 int rc = 0;
5319 int bytes_returned = 0;
5320 FILE_UNIX_BASIC_INFO *data_offset;
5321 __u16 params, param_offset, offset, count, byte_count;
5323 cFYI(1, "In SetUID/GID/Mode");
5324 setPermsRetry:
5325 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5326 (void **) &pSMBr);
5327 if (rc)
5328 return rc;
5330 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5331 name_len =
5332 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5333 PATH_MAX, nls_codepage, remap);
5334 name_len++; /* trailing null */
5335 name_len *= 2;
5336 } else { /* BB improve the check for buffer overruns BB */
5337 name_len = strnlen(fileName, PATH_MAX);
5338 name_len++; /* trailing null */
5339 strncpy(pSMB->FileName, fileName, name_len);
5342 params = 6 + name_len;
5343 count = sizeof(FILE_UNIX_BASIC_INFO);
5344 pSMB->MaxParameterCount = cpu_to_le16(2);
5345 /* BB find max SMB PDU from sess structure BB */
5346 pSMB->MaxDataCount = cpu_to_le16(1000);
5347 pSMB->MaxSetupCount = 0;
5348 pSMB->Reserved = 0;
5349 pSMB->Flags = 0;
5350 pSMB->Timeout = 0;
5351 pSMB->Reserved2 = 0;
5352 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5353 InformationLevel) - 4;
5354 offset = param_offset + params;
5355 data_offset =
5356 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5357 offset);
5358 memset(data_offset, 0, count);
5359 pSMB->DataOffset = cpu_to_le16(offset);
5360 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5361 pSMB->SetupCount = 1;
5362 pSMB->Reserved3 = 0;
5363 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5364 byte_count = 3 /* pad */ + params + count;
5365 pSMB->ParameterCount = cpu_to_le16(params);
5366 pSMB->DataCount = cpu_to_le16(count);
5367 pSMB->TotalParameterCount = pSMB->ParameterCount;
5368 pSMB->TotalDataCount = pSMB->DataCount;
5369 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5370 pSMB->Reserved4 = 0;
5371 pSMB->hdr.smb_buf_length += byte_count;
5373 cifs_fill_unix_set_info(data_offset, args);
5375 pSMB->ByteCount = cpu_to_le16(byte_count);
5376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5377 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5378 if (rc)
5379 cFYI(1, "SetPathInfo (perms) returned %d", rc);
5381 cifs_buf_release(pSMB);
5382 if (rc == -EAGAIN)
5383 goto setPermsRetry;
5384 return rc;
5387 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5388 const int notify_subdirs, const __u16 netfid,
5389 __u32 filter, struct file *pfile, int multishot,
5390 const struct nls_table *nls_codepage)
5392 int rc = 0;
5393 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5394 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5395 struct dir_notify_req *dnotify_req;
5396 int bytes_returned;
5398 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
5399 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5400 (void **) &pSMBr);
5401 if (rc)
5402 return rc;
5404 pSMB->TotalParameterCount = 0 ;
5405 pSMB->TotalDataCount = 0;
5406 pSMB->MaxParameterCount = cpu_to_le32(2);
5407 /* BB find exact data count max from sess structure BB */
5408 pSMB->MaxDataCount = 0; /* same in little endian or be */
5409 /* BB VERIFY verify which is correct for above BB */
5410 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5411 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5413 pSMB->MaxSetupCount = 4;
5414 pSMB->Reserved = 0;
5415 pSMB->ParameterOffset = 0;
5416 pSMB->DataCount = 0;
5417 pSMB->DataOffset = 0;
5418 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5419 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5420 pSMB->ParameterCount = pSMB->TotalParameterCount;
5421 if (notify_subdirs)
5422 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5423 pSMB->Reserved2 = 0;
5424 pSMB->CompletionFilter = cpu_to_le32(filter);
5425 pSMB->Fid = netfid; /* file handle always le */
5426 pSMB->ByteCount = 0;
5428 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5429 (struct smb_hdr *)pSMBr, &bytes_returned,
5430 CIFS_ASYNC_OP);
5431 if (rc) {
5432 cFYI(1, "Error in Notify = %d", rc);
5433 } else {
5434 /* Add file to outstanding requests */
5435 /* BB change to kmem cache alloc */
5436 dnotify_req = kmalloc(
5437 sizeof(struct dir_notify_req),
5438 GFP_KERNEL);
5439 if (dnotify_req) {
5440 dnotify_req->Pid = pSMB->hdr.Pid;
5441 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5442 dnotify_req->Mid = pSMB->hdr.Mid;
5443 dnotify_req->Tid = pSMB->hdr.Tid;
5444 dnotify_req->Uid = pSMB->hdr.Uid;
5445 dnotify_req->netfid = netfid;
5446 dnotify_req->pfile = pfile;
5447 dnotify_req->filter = filter;
5448 dnotify_req->multishot = multishot;
5449 spin_lock(&GlobalMid_Lock);
5450 list_add_tail(&dnotify_req->lhead,
5451 &GlobalDnotifyReqList);
5452 spin_unlock(&GlobalMid_Lock);
5453 } else
5454 rc = -ENOMEM;
5456 cifs_buf_release(pSMB);
5457 return rc;
5460 #ifdef CONFIG_CIFS_XATTR
5462 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5463 * function used by listxattr and getxattr type calls. When ea_name is set,
5464 * it looks for that attribute name and stuffs that value into the EAData
5465 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5466 * buffer. In both cases, the return value is either the length of the
5467 * resulting data or a negative error code. If EAData is a NULL pointer then
5468 * the data isn't copied to it, but the length is returned.
5470 ssize_t
5471 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5472 const unsigned char *searchName, const unsigned char *ea_name,
5473 char *EAData, size_t buf_size,
5474 const struct nls_table *nls_codepage, int remap)
5476 /* BB assumes one setup word */
5477 TRANSACTION2_QPI_REQ *pSMB = NULL;
5478 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5479 int rc = 0;
5480 int bytes_returned;
5481 int list_len;
5482 struct fealist *ea_response_data;
5483 struct fea *temp_fea;
5484 char *temp_ptr;
5485 char *end_of_smb;
5486 __u16 params, byte_count, data_offset;
5488 cFYI(1, "In Query All EAs path %s", searchName);
5489 QAllEAsRetry:
5490 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5491 (void **) &pSMBr);
5492 if (rc)
5493 return rc;
5495 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5496 list_len =
5497 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5498 PATH_MAX, nls_codepage, remap);
5499 list_len++; /* trailing null */
5500 list_len *= 2;
5501 } else { /* BB improve the check for buffer overruns BB */
5502 list_len = strnlen(searchName, PATH_MAX);
5503 list_len++; /* trailing null */
5504 strncpy(pSMB->FileName, searchName, list_len);
5507 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
5508 pSMB->TotalDataCount = 0;
5509 pSMB->MaxParameterCount = cpu_to_le16(2);
5510 /* BB find exact max SMB PDU from sess structure BB */
5511 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
5512 pSMB->MaxSetupCount = 0;
5513 pSMB->Reserved = 0;
5514 pSMB->Flags = 0;
5515 pSMB->Timeout = 0;
5516 pSMB->Reserved2 = 0;
5517 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5518 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5519 pSMB->DataCount = 0;
5520 pSMB->DataOffset = 0;
5521 pSMB->SetupCount = 1;
5522 pSMB->Reserved3 = 0;
5523 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5524 byte_count = params + 1 /* pad */ ;
5525 pSMB->TotalParameterCount = cpu_to_le16(params);
5526 pSMB->ParameterCount = pSMB->TotalParameterCount;
5527 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5528 pSMB->Reserved4 = 0;
5529 pSMB->hdr.smb_buf_length += byte_count;
5530 pSMB->ByteCount = cpu_to_le16(byte_count);
5532 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5533 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5534 if (rc) {
5535 cFYI(1, "Send error in QueryAllEAs = %d", rc);
5536 goto QAllEAsOut;
5540 /* BB also check enough total bytes returned */
5541 /* BB we need to improve the validity checking
5542 of these trans2 responses */
5544 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5545 if (rc || (pSMBr->ByteCount < 4)) {
5546 rc = -EIO; /* bad smb */
5547 goto QAllEAsOut;
5550 /* check that length of list is not more than bcc */
5551 /* check that each entry does not go beyond length
5552 of list */
5553 /* check that each element of each entry does not
5554 go beyond end of list */
5555 /* validate_trans2_offsets() */
5556 /* BB check if start of smb + data_offset > &bcc+ bcc */
5558 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5559 ea_response_data = (struct fealist *)
5560 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5562 list_len = le32_to_cpu(ea_response_data->list_len);
5563 cFYI(1, "ea length %d", list_len);
5564 if (list_len <= 8) {
5565 cFYI(1, "empty EA list returned from server");
5566 goto QAllEAsOut;
5569 /* make sure list_len doesn't go past end of SMB */
5570 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5571 if ((char *)ea_response_data + list_len > end_of_smb) {
5572 cFYI(1, "EA list appears to go beyond SMB");
5573 rc = -EIO;
5574 goto QAllEAsOut;
5577 /* account for ea list len */
5578 list_len -= 4;
5579 temp_fea = ea_response_data->list;
5580 temp_ptr = (char *)temp_fea;
5581 while (list_len > 0) {
5582 unsigned int name_len;
5583 __u16 value_len;
5585 list_len -= 4;
5586 temp_ptr += 4;
5587 /* make sure we can read name_len and value_len */
5588 if (list_len < 0) {
5589 cFYI(1, "EA entry goes beyond length of list");
5590 rc = -EIO;
5591 goto QAllEAsOut;
5594 name_len = temp_fea->name_len;
5595 value_len = le16_to_cpu(temp_fea->value_len);
5596 list_len -= name_len + 1 + value_len;
5597 if (list_len < 0) {
5598 cFYI(1, "EA entry goes beyond length of list");
5599 rc = -EIO;
5600 goto QAllEAsOut;
5603 if (ea_name) {
5604 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5605 temp_ptr += name_len + 1;
5606 rc = value_len;
5607 if (buf_size == 0)
5608 goto QAllEAsOut;
5609 if ((size_t)value_len > buf_size) {
5610 rc = -ERANGE;
5611 goto QAllEAsOut;
5613 memcpy(EAData, temp_ptr, value_len);
5614 goto QAllEAsOut;
5616 } else {
5617 /* account for prefix user. and trailing null */
5618 rc += (5 + 1 + name_len);
5619 if (rc < (int) buf_size) {
5620 memcpy(EAData, "user.", 5);
5621 EAData += 5;
5622 memcpy(EAData, temp_ptr, name_len);
5623 EAData += name_len;
5624 /* null terminate name */
5625 *EAData = 0;
5626 ++EAData;
5627 } else if (buf_size == 0) {
5628 /* skip copy - calc size only */
5629 } else {
5630 /* stop before overrun buffer */
5631 rc = -ERANGE;
5632 break;
5635 temp_ptr += name_len + 1 + value_len;
5636 temp_fea = (struct fea *)temp_ptr;
5639 /* didn't find the named attribute */
5640 if (ea_name)
5641 rc = -ENODATA;
5643 QAllEAsOut:
5644 cifs_buf_release(pSMB);
5645 if (rc == -EAGAIN)
5646 goto QAllEAsRetry;
5648 return (ssize_t)rc;
5652 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5653 const char *ea_name, const void *ea_value,
5654 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5655 int remap)
5657 struct smb_com_transaction2_spi_req *pSMB = NULL;
5658 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5659 struct fealist *parm_data;
5660 int name_len;
5661 int rc = 0;
5662 int bytes_returned = 0;
5663 __u16 params, param_offset, byte_count, offset, count;
5665 cFYI(1, "In SetEA");
5666 SetEARetry:
5667 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5668 (void **) &pSMBr);
5669 if (rc)
5670 return rc;
5672 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5673 name_len =
5674 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5675 PATH_MAX, nls_codepage, remap);
5676 name_len++; /* trailing null */
5677 name_len *= 2;
5678 } else { /* BB improve the check for buffer overruns BB */
5679 name_len = strnlen(fileName, PATH_MAX);
5680 name_len++; /* trailing null */
5681 strncpy(pSMB->FileName, fileName, name_len);
5684 params = 6 + name_len;
5686 /* done calculating parms using name_len of file name,
5687 now use name_len to calculate length of ea name
5688 we are going to create in the inode xattrs */
5689 if (ea_name == NULL)
5690 name_len = 0;
5691 else
5692 name_len = strnlen(ea_name, 255);
5694 count = sizeof(*parm_data) + ea_value_len + name_len;
5695 pSMB->MaxParameterCount = cpu_to_le16(2);
5696 /* BB find max SMB PDU from sess */
5697 pSMB->MaxDataCount = cpu_to_le16(1000);
5698 pSMB->MaxSetupCount = 0;
5699 pSMB->Reserved = 0;
5700 pSMB->Flags = 0;
5701 pSMB->Timeout = 0;
5702 pSMB->Reserved2 = 0;
5703 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5704 InformationLevel) - 4;
5705 offset = param_offset + params;
5706 pSMB->InformationLevel =
5707 cpu_to_le16(SMB_SET_FILE_EA);
5709 parm_data =
5710 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5711 offset);
5712 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5713 pSMB->DataOffset = cpu_to_le16(offset);
5714 pSMB->SetupCount = 1;
5715 pSMB->Reserved3 = 0;
5716 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5717 byte_count = 3 /* pad */ + params + count;
5718 pSMB->DataCount = cpu_to_le16(count);
5719 parm_data->list_len = cpu_to_le32(count);
5720 parm_data->list[0].EA_flags = 0;
5721 /* we checked above that name len is less than 255 */
5722 parm_data->list[0].name_len = (__u8)name_len;
5723 /* EA names are always ASCII */
5724 if (ea_name)
5725 strncpy(parm_data->list[0].name, ea_name, name_len);
5726 parm_data->list[0].name[name_len] = 0;
5727 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5728 /* caller ensures that ea_value_len is less than 64K but
5729 we need to ensure that it fits within the smb */
5731 /*BB add length check to see if it would fit in
5732 negotiated SMB buffer size BB */
5733 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5734 if (ea_value_len)
5735 memcpy(parm_data->list[0].name+name_len+1,
5736 ea_value, ea_value_len);
5738 pSMB->TotalDataCount = pSMB->DataCount;
5739 pSMB->ParameterCount = cpu_to_le16(params);
5740 pSMB->TotalParameterCount = pSMB->ParameterCount;
5741 pSMB->Reserved4 = 0;
5742 pSMB->hdr.smb_buf_length += byte_count;
5743 pSMB->ByteCount = cpu_to_le16(byte_count);
5744 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5745 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5746 if (rc)
5747 cFYI(1, "SetPathInfo (EA) returned %d", rc);
5749 cifs_buf_release(pSMB);
5751 if (rc == -EAGAIN)
5752 goto SetEARetry;
5754 return rc;
5757 #endif