sched: add cond_resched_rcu() helper
[linux/fpc-iii.git] / fs / cifs / cifssmb.c
bloba58dc77cc4430d57d8c8226c3120f3a12519fb00
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 <linux/pagemap.h>
36 #include <linux/swap.h>
37 #include <linux/task_io_accounting_ops.h>
38 #include <asm/uaccess.h>
39 #include "cifspdu.h"
40 #include "cifsglob.h"
41 #include "cifsacl.h"
42 #include "cifsproto.h"
43 #include "cifs_unicode.h"
44 #include "cifs_debug.h"
45 #include "fscache.h"
47 #ifdef CONFIG_CIFS_POSIX
48 static struct {
49 int index;
50 char *name;
51 } protocols[] = {
52 #ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
54 {LANMAN2_PROT, "\2LANMAN2.1"},
55 #endif /* weak password hashing for legacy clients */
56 {CIFS_PROT, "\2NT LM 0.12"},
57 {POSIX_PROT, "\2POSIX 2"},
58 {BAD_PROT, "\2"}
60 #else
61 static struct {
62 int index;
63 char *name;
64 } protocols[] = {
65 #ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
67 {LANMAN2_PROT, "\2LANMAN2.1"},
68 #endif /* weak password hashing for legacy clients */
69 {CIFS_PROT, "\2NT LM 0.12"},
70 {BAD_PROT, "\2"}
72 #endif
74 /* define the number of elements in the cifs dialect array */
75 #ifdef CONFIG_CIFS_POSIX
76 #ifdef CONFIG_CIFS_WEAK_PW_HASH
77 #define CIFS_NUM_PROT 4
78 #else
79 #define CIFS_NUM_PROT 2
80 #endif /* CIFS_WEAK_PW_HASH */
81 #else /* not posix */
82 #ifdef CONFIG_CIFS_WEAK_PW_HASH
83 #define CIFS_NUM_PROT 3
84 #else
85 #define CIFS_NUM_PROT 1
86 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
87 #endif /* CIFS_POSIX */
90 * Mark as invalid, all open files on tree connections since they
91 * were closed when session to server was lost.
93 void
94 cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
96 struct cifsFileInfo *open_file = NULL;
97 struct list_head *tmp;
98 struct list_head *tmp1;
100 /* list all files open on tree connection and mark them invalid */
101 spin_lock(&cifs_file_list_lock);
102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
103 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
104 open_file->invalidHandle = true;
105 open_file->oplock_break_cancelled = true;
107 spin_unlock(&cifs_file_list_lock);
109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
110 * to this tcon.
114 /* reconnect the socket, tcon, and smb session if needed */
115 static int
116 cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
118 int rc;
119 struct cifs_ses *ses;
120 struct TCP_Server_Info *server;
121 struct nls_table *nls_codepage;
124 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
125 * tcp and smb session status done differently for those three - in the
126 * calling routine
128 if (!tcon)
129 return 0;
131 ses = tcon->ses;
132 server = ses->server;
135 * only tree disconnect, open, and write, (and ulogoff which does not
136 * have tcon) are allowed as we start force umount
138 if (tcon->tidStatus == CifsExiting) {
139 if (smb_command != SMB_COM_WRITE_ANDX &&
140 smb_command != SMB_COM_OPEN_ANDX &&
141 smb_command != SMB_COM_TREE_DISCONNECT) {
142 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
143 smb_command);
144 return -ENODEV;
149 * Give demultiplex thread up to 10 seconds to reconnect, should be
150 * greater than cifs socket timeout which is 7 seconds
152 while (server->tcpStatus == CifsNeedReconnect) {
153 wait_event_interruptible_timeout(server->response_q,
154 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
156 /* are we still trying to reconnect? */
157 if (server->tcpStatus != CifsNeedReconnect)
158 break;
161 * on "soft" mounts we wait once. Hard mounts keep
162 * retrying until process is killed or server comes
163 * back on-line
165 if (!tcon->retry) {
166 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
167 return -EHOSTDOWN;
171 if (!ses->need_reconnect && !tcon->need_reconnect)
172 return 0;
174 nls_codepage = load_nls_default();
177 * need to prevent multiple threads trying to simultaneously
178 * reconnect the same SMB session
180 mutex_lock(&ses->session_mutex);
181 rc = cifs_negotiate_protocol(0, ses);
182 if (rc == 0 && ses->need_reconnect)
183 rc = cifs_setup_session(0, ses, nls_codepage);
185 /* do we need to reconnect tcon? */
186 if (rc || !tcon->need_reconnect) {
187 mutex_unlock(&ses->session_mutex);
188 goto out;
191 cifs_mark_open_files_invalid(tcon);
192 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
193 mutex_unlock(&ses->session_mutex);
194 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
196 if (rc)
197 goto out;
200 * FIXME: check if wsize needs updated due to negotiated smb buffer
201 * size shrinking
203 atomic_inc(&tconInfoReconnectCount);
205 /* tell server Unix caps we support */
206 if (ses->capabilities & CAP_UNIX)
207 reset_cifs_unix_caps(0, tcon, NULL, NULL);
210 * Removed call to reopen open files here. It is safer (and faster) to
211 * reopen files one at a time as needed in read and write.
213 * FIXME: what about file locks? don't we need to reclaim them ASAP?
216 out:
218 * Check if handle based operation so we know whether we can continue
219 * or not without returning to caller to reset file handle
221 switch (smb_command) {
222 case SMB_COM_READ_ANDX:
223 case SMB_COM_WRITE_ANDX:
224 case SMB_COM_CLOSE:
225 case SMB_COM_FIND_CLOSE2:
226 case SMB_COM_LOCKING_ANDX:
227 rc = -EAGAIN;
230 unload_nls(nls_codepage);
231 return rc;
234 /* Allocate and return pointer to an SMB request buffer, and set basic
235 SMB information in the SMB header. If the return code is zero, this
236 function must have filled in request_buf pointer */
237 static int
238 small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
239 void **request_buf)
241 int rc;
243 rc = cifs_reconnect_tcon(tcon, smb_command);
244 if (rc)
245 return rc;
247 *request_buf = cifs_small_buf_get();
248 if (*request_buf == NULL) {
249 /* BB should we add a retry in here if not a writepage? */
250 return -ENOMEM;
253 header_assemble((struct smb_hdr *) *request_buf, smb_command,
254 tcon, wct);
256 if (tcon != NULL)
257 cifs_stats_inc(&tcon->num_smbs_sent);
259 return 0;
263 small_smb_init_no_tc(const int smb_command, const int wct,
264 struct cifs_ses *ses, void **request_buf)
266 int rc;
267 struct smb_hdr *buffer;
269 rc = small_smb_init(smb_command, wct, NULL, request_buf);
270 if (rc)
271 return rc;
273 buffer = (struct smb_hdr *)*request_buf;
274 buffer->Mid = get_next_mid(ses->server);
275 if (ses->capabilities & CAP_UNICODE)
276 buffer->Flags2 |= SMBFLG2_UNICODE;
277 if (ses->capabilities & CAP_STATUS32)
278 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
280 /* uid, tid can stay at zero as set in header assemble */
282 /* BB add support for turning on the signing when
283 this function is used after 1st of session setup requests */
285 return rc;
288 /* If the return code is zero, this function must fill in request_buf pointer */
289 static int
290 __smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
291 void **request_buf, void **response_buf)
293 *request_buf = cifs_buf_get();
294 if (*request_buf == NULL) {
295 /* BB should we add a retry in here if not a writepage? */
296 return -ENOMEM;
298 /* Although the original thought was we needed the response buf for */
299 /* potential retries of smb operations it turns out we can determine */
300 /* from the mid flags when the request buffer can be resent without */
301 /* having to use a second distinct buffer for the response */
302 if (response_buf)
303 *response_buf = *request_buf;
305 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
306 wct);
308 if (tcon != NULL)
309 cifs_stats_inc(&tcon->num_smbs_sent);
311 return 0;
314 /* If the return code is zero, this function must fill in request_buf pointer */
315 static int
316 smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
317 void **request_buf, void **response_buf)
319 int rc;
321 rc = cifs_reconnect_tcon(tcon, smb_command);
322 if (rc)
323 return rc;
325 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
328 static int
329 smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
330 void **request_buf, void **response_buf)
332 if (tcon->ses->need_reconnect || tcon->need_reconnect)
333 return -EHOSTDOWN;
335 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
338 static int validate_t2(struct smb_t2_rsp *pSMB)
340 unsigned int total_size;
342 /* check for plausible wct */
343 if (pSMB->hdr.WordCount < 10)
344 goto vt2_err;
346 /* check for parm and data offset going beyond end of smb */
347 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
348 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
349 goto vt2_err;
351 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
352 if (total_size >= 512)
353 goto vt2_err;
355 /* check that bcc is at least as big as parms + data, and that it is
356 * less than negotiated smb buffer
358 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
359 if (total_size > get_bcc(&pSMB->hdr) ||
360 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
361 goto vt2_err;
363 return 0;
364 vt2_err:
365 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
366 sizeof(struct smb_t2_rsp) + 16);
367 return -EINVAL;
371 CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
373 NEGOTIATE_REQ *pSMB;
374 NEGOTIATE_RSP *pSMBr;
375 int rc = 0;
376 int bytes_returned;
377 int i;
378 struct TCP_Server_Info *server;
379 u16 count;
380 unsigned int secFlags;
382 if (ses->server)
383 server = ses->server;
384 else {
385 rc = -EIO;
386 return rc;
388 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
389 (void **) &pSMB, (void **) &pSMBr);
390 if (rc)
391 return rc;
393 /* if any of auth flags (ie not sign or seal) are overriden use them */
394 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
395 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
396 else /* if override flags set only sign/seal OR them with global auth */
397 secFlags = global_secflags | ses->overrideSecFlg;
399 cifs_dbg(FYI, "secFlags 0x%x\n", secFlags);
401 pSMB->hdr.Mid = get_next_mid(server);
402 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
404 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
405 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
406 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
407 cifs_dbg(FYI, "Kerberos only mechanism, enable extended security\n");
408 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
409 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
410 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
411 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
412 cifs_dbg(FYI, "NTLMSSP only mechanism, enable extended security\n");
413 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
416 count = 0;
417 for (i = 0; i < CIFS_NUM_PROT; i++) {
418 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
419 count += strlen(protocols[i].name) + 1;
420 /* null at end of source and target buffers anyway */
422 inc_rfc1001_len(pSMB, count);
423 pSMB->ByteCount = cpu_to_le16(count);
425 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
426 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
427 if (rc != 0)
428 goto neg_err_exit;
430 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
431 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
432 /* Check wct = 1 error case */
433 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
434 /* core returns wct = 1, but we do not ask for core - otherwise
435 small wct just comes when dialect index is -1 indicating we
436 could not negotiate a common dialect */
437 rc = -EOPNOTSUPP;
438 goto neg_err_exit;
439 #ifdef CONFIG_CIFS_WEAK_PW_HASH
440 } else if ((pSMBr->hdr.WordCount == 13)
441 && ((server->dialect == LANMAN_PROT)
442 || (server->dialect == LANMAN2_PROT))) {
443 __s16 tmp;
444 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
446 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
447 (secFlags & CIFSSEC_MAY_PLNTXT))
448 server->secType = LANMAN;
449 else {
450 cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
451 rc = -EOPNOTSUPP;
452 goto neg_err_exit;
454 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
455 server->maxReq = min_t(unsigned int,
456 le16_to_cpu(rsp->MaxMpxCount),
457 cifs_max_pending);
458 set_credits(server, server->maxReq);
459 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
460 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
461 /* even though we do not use raw we might as well set this
462 accurately, in case we ever find a need for it */
463 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
464 server->max_rw = 0xFF00;
465 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
466 } else {
467 server->max_rw = 0;/* do not need to use raw anyway */
468 server->capabilities = CAP_MPX_MODE;
470 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
471 if (tmp == -1) {
472 /* OS/2 often does not set timezone therefore
473 * we must use server time to calc time zone.
474 * Could deviate slightly from the right zone.
475 * Smallest defined timezone difference is 15 minutes
476 * (i.e. Nepal). Rounding up/down is done to match
477 * this requirement.
479 int val, seconds, remain, result;
480 struct timespec ts, utc;
481 utc = CURRENT_TIME;
482 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
483 rsp->SrvTime.Time, 0);
484 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
485 (int)ts.tv_sec, (int)utc.tv_sec,
486 (int)(utc.tv_sec - ts.tv_sec));
487 val = (int)(utc.tv_sec - ts.tv_sec);
488 seconds = abs(val);
489 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
490 remain = seconds % MIN_TZ_ADJ;
491 if (remain >= (MIN_TZ_ADJ / 2))
492 result += MIN_TZ_ADJ;
493 if (val < 0)
494 result = -result;
495 server->timeAdj = result;
496 } else {
497 server->timeAdj = (int)tmp;
498 server->timeAdj *= 60; /* also in seconds */
500 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
503 /* BB get server time for time conversions and add
504 code to use it and timezone since this is not UTC */
506 if (rsp->EncryptionKeyLength ==
507 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
508 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
509 CIFS_CRYPTO_KEY_SIZE);
510 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
511 rc = -EIO; /* need cryptkey unless plain text */
512 goto neg_err_exit;
515 cifs_dbg(FYI, "LANMAN negotiated\n");
516 /* we will not end up setting signing flags - as no signing
517 was in LANMAN and server did not return the flags on */
518 goto signing_check;
519 #else /* weak security disabled */
520 } else if (pSMBr->hdr.WordCount == 13) {
521 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
522 rc = -EOPNOTSUPP;
523 #endif /* WEAK_PW_HASH */
524 goto neg_err_exit;
525 } else if (pSMBr->hdr.WordCount != 17) {
526 /* unknown wct */
527 rc = -EOPNOTSUPP;
528 goto neg_err_exit;
530 /* else wct == 17 NTLM */
531 server->sec_mode = pSMBr->SecurityMode;
532 if ((server->sec_mode & SECMODE_USER) == 0)
533 cifs_dbg(FYI, "share mode security\n");
535 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
536 #ifdef CONFIG_CIFS_WEAK_PW_HASH
537 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
538 #endif /* CIFS_WEAK_PW_HASH */
539 cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");
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 else {
554 rc = -EOPNOTSUPP;
555 cifs_dbg(VFS, "Invalid security type\n");
556 goto neg_err_exit;
558 /* else ... any others ...? */
560 /* one byte, so no need to convert this or EncryptionKeyLen from
561 little endian */
562 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
563 cifs_max_pending);
564 set_credits(server, server->maxReq);
565 /* probably no need to store and check maxvcs */
566 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
567 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
568 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
569 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
570 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
571 server->timeAdj *= 60;
572 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
573 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
574 CIFS_CRYPTO_KEY_SIZE);
575 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
576 server->capabilities & CAP_EXTENDED_SECURITY) &&
577 (pSMBr->EncryptionKeyLength == 0)) {
578 /* decode security blob */
579 count = get_bcc(&pSMBr->hdr);
580 if (count < 16) {
581 rc = -EIO;
582 goto neg_err_exit;
584 spin_lock(&cifs_tcp_ses_lock);
585 if (server->srv_count > 1) {
586 spin_unlock(&cifs_tcp_ses_lock);
587 if (memcmp(server->server_GUID,
588 pSMBr->u.extended_response.
589 GUID, 16) != 0) {
590 cifs_dbg(FYI, "server UID changed\n");
591 memcpy(server->server_GUID,
592 pSMBr->u.extended_response.GUID,
593 16);
595 } else {
596 spin_unlock(&cifs_tcp_ses_lock);
597 memcpy(server->server_GUID,
598 pSMBr->u.extended_response.GUID, 16);
601 if (count == 16) {
602 server->secType = RawNTLMSSP;
603 } else {
604 rc = decode_negTokenInit(pSMBr->u.extended_response.
605 SecurityBlob, count - 16,
606 server);
607 if (rc == 1)
608 rc = 0;
609 else
610 rc = -EINVAL;
611 if (server->secType == Kerberos) {
612 if (!server->sec_kerberos &&
613 !server->sec_mskerberos)
614 rc = -EOPNOTSUPP;
615 } else if (server->secType == RawNTLMSSP) {
616 if (!server->sec_ntlmssp)
617 rc = -EOPNOTSUPP;
618 } else
619 rc = -EOPNOTSUPP;
621 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
622 rc = -EIO; /* no crypt key only if plain text pwd */
623 goto neg_err_exit;
624 } else
625 server->capabilities &= ~CAP_EXTENDED_SECURITY;
627 #ifdef CONFIG_CIFS_WEAK_PW_HASH
628 signing_check:
629 #endif
630 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
631 /* MUST_SIGN already includes the MAY_SIGN FLAG
632 so if this is zero it means that signing is disabled */
633 cifs_dbg(FYI, "Signing disabled\n");
634 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
635 cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
636 rc = -EOPNOTSUPP;
638 server->sec_mode &=
639 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
640 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
641 /* signing required */
642 cifs_dbg(FYI, "Must sign - secFlags 0x%x\n", secFlags);
643 if ((server->sec_mode &
644 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
645 cifs_dbg(VFS, "signing required but server lacks support\n");
646 rc = -EOPNOTSUPP;
647 } else
648 server->sec_mode |= SECMODE_SIGN_REQUIRED;
649 } else {
650 /* signing optional ie CIFSSEC_MAY_SIGN */
651 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
652 server->sec_mode &=
653 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
656 neg_err_exit:
657 cifs_buf_release(pSMB);
659 cifs_dbg(FYI, "negprot rc %d\n", rc);
660 return rc;
664 CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
666 struct smb_hdr *smb_buffer;
667 int rc = 0;
669 cifs_dbg(FYI, "In tree disconnect\n");
671 /* BB: do we need to check this? These should never be NULL. */
672 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
673 return -EIO;
676 * No need to return error on this operation if tid invalidated and
677 * closed on server already e.g. due to tcp session crashing. Also,
678 * the tcon is no longer on the list, so no need to take lock before
679 * checking this.
681 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
682 return 0;
684 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
685 (void **)&smb_buffer);
686 if (rc)
687 return rc;
689 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
690 if (rc)
691 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
693 /* No need to return error on this operation if tid invalidated and
694 closed on server already e.g. due to tcp session crashing */
695 if (rc == -EAGAIN)
696 rc = 0;
698 return rc;
702 * This is a no-op for now. We're not really interested in the reply, but
703 * rather in the fact that the server sent one and that server->lstrp
704 * gets updated.
706 * FIXME: maybe we should consider checking that the reply matches request?
708 static void
709 cifs_echo_callback(struct mid_q_entry *mid)
711 struct TCP_Server_Info *server = mid->callback_data;
713 DeleteMidQEntry(mid);
714 add_credits(server, 1, CIFS_ECHO_OP);
718 CIFSSMBEcho(struct TCP_Server_Info *server)
720 ECHO_REQ *smb;
721 int rc = 0;
722 struct kvec iov;
723 struct smb_rqst rqst = { .rq_iov = &iov,
724 .rq_nvec = 1 };
726 cifs_dbg(FYI, "In echo request\n");
728 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
729 if (rc)
730 return rc;
732 /* set up echo request */
733 smb->hdr.Tid = 0xffff;
734 smb->hdr.WordCount = 1;
735 put_unaligned_le16(1, &smb->EchoCount);
736 put_bcc(1, &smb->hdr);
737 smb->Data[0] = 'a';
738 inc_rfc1001_len(smb, 3);
739 iov.iov_base = smb;
740 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
742 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
743 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
744 if (rc)
745 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
747 cifs_small_buf_release(smb);
749 return rc;
753 CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
755 LOGOFF_ANDX_REQ *pSMB;
756 int rc = 0;
758 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
761 * BB: do we need to check validity of ses and server? They should
762 * always be valid since we have an active reference. If not, that
763 * should probably be a BUG()
765 if (!ses || !ses->server)
766 return -EIO;
768 mutex_lock(&ses->session_mutex);
769 if (ses->need_reconnect)
770 goto session_already_dead; /* no need to send SMBlogoff if uid
771 already closed due to reconnect */
772 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
773 if (rc) {
774 mutex_unlock(&ses->session_mutex);
775 return rc;
778 pSMB->hdr.Mid = get_next_mid(ses->server);
780 if (ses->server->sec_mode &
781 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
782 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
784 pSMB->hdr.Uid = ses->Suid;
786 pSMB->AndXCommand = 0xFF;
787 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
788 session_already_dead:
789 mutex_unlock(&ses->session_mutex);
791 /* if session dead then we do not need to do ulogoff,
792 since server closed smb session, no sense reporting
793 error */
794 if (rc == -EAGAIN)
795 rc = 0;
796 return rc;
800 CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
801 const char *fileName, __u16 type,
802 const struct nls_table *nls_codepage, int remap)
804 TRANSACTION2_SPI_REQ *pSMB = NULL;
805 TRANSACTION2_SPI_RSP *pSMBr = NULL;
806 struct unlink_psx_rq *pRqD;
807 int name_len;
808 int rc = 0;
809 int bytes_returned = 0;
810 __u16 params, param_offset, offset, byte_count;
812 cifs_dbg(FYI, "In POSIX delete\n");
813 PsxDelete:
814 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
815 (void **) &pSMBr);
816 if (rc)
817 return rc;
819 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
820 name_len =
821 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
822 PATH_MAX, nls_codepage, remap);
823 name_len++; /* trailing null */
824 name_len *= 2;
825 } else { /* BB add path length overrun check */
826 name_len = strnlen(fileName, PATH_MAX);
827 name_len++; /* trailing null */
828 strncpy(pSMB->FileName, fileName, name_len);
831 params = 6 + name_len;
832 pSMB->MaxParameterCount = cpu_to_le16(2);
833 pSMB->MaxDataCount = 0; /* BB double check this with jra */
834 pSMB->MaxSetupCount = 0;
835 pSMB->Reserved = 0;
836 pSMB->Flags = 0;
837 pSMB->Timeout = 0;
838 pSMB->Reserved2 = 0;
839 param_offset = offsetof(struct smb_com_transaction2_spi_req,
840 InformationLevel) - 4;
841 offset = param_offset + params;
843 /* Setup pointer to Request Data (inode type) */
844 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
845 pRqD->type = cpu_to_le16(type);
846 pSMB->ParameterOffset = cpu_to_le16(param_offset);
847 pSMB->DataOffset = cpu_to_le16(offset);
848 pSMB->SetupCount = 1;
849 pSMB->Reserved3 = 0;
850 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
851 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
853 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
854 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
855 pSMB->ParameterCount = cpu_to_le16(params);
856 pSMB->TotalParameterCount = pSMB->ParameterCount;
857 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
858 pSMB->Reserved4 = 0;
859 inc_rfc1001_len(pSMB, byte_count);
860 pSMB->ByteCount = cpu_to_le16(byte_count);
861 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
862 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
863 if (rc)
864 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
865 cifs_buf_release(pSMB);
867 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
869 if (rc == -EAGAIN)
870 goto PsxDelete;
872 return rc;
876 CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
877 struct cifs_sb_info *cifs_sb)
879 DELETE_FILE_REQ *pSMB = NULL;
880 DELETE_FILE_RSP *pSMBr = NULL;
881 int rc = 0;
882 int bytes_returned;
883 int name_len;
884 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
886 DelFileRetry:
887 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
888 (void **) &pSMBr);
889 if (rc)
890 return rc;
892 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
893 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
894 PATH_MAX, cifs_sb->local_nls,
895 remap);
896 name_len++; /* trailing null */
897 name_len *= 2;
898 } else { /* BB improve check for buffer overruns BB */
899 name_len = strnlen(name, PATH_MAX);
900 name_len++; /* trailing null */
901 strncpy(pSMB->fileName, name, name_len);
903 pSMB->SearchAttributes =
904 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
905 pSMB->BufferFormat = 0x04;
906 inc_rfc1001_len(pSMB, name_len + 1);
907 pSMB->ByteCount = cpu_to_le16(name_len + 1);
908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
910 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
911 if (rc)
912 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
914 cifs_buf_release(pSMB);
915 if (rc == -EAGAIN)
916 goto DelFileRetry;
918 return rc;
922 CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
923 struct cifs_sb_info *cifs_sb)
925 DELETE_DIRECTORY_REQ *pSMB = NULL;
926 DELETE_DIRECTORY_RSP *pSMBr = NULL;
927 int rc = 0;
928 int bytes_returned;
929 int name_len;
930 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
932 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
933 RmDirRetry:
934 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
935 (void **) &pSMBr);
936 if (rc)
937 return rc;
939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
940 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
941 PATH_MAX, cifs_sb->local_nls,
942 remap);
943 name_len++; /* trailing null */
944 name_len *= 2;
945 } else { /* BB improve check for buffer overruns BB */
946 name_len = strnlen(name, PATH_MAX);
947 name_len++; /* trailing null */
948 strncpy(pSMB->DirName, name, name_len);
951 pSMB->BufferFormat = 0x04;
952 inc_rfc1001_len(pSMB, name_len + 1);
953 pSMB->ByteCount = cpu_to_le16(name_len + 1);
954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
956 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
957 if (rc)
958 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
960 cifs_buf_release(pSMB);
961 if (rc == -EAGAIN)
962 goto RmDirRetry;
963 return rc;
967 CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
968 struct cifs_sb_info *cifs_sb)
970 int rc = 0;
971 CREATE_DIRECTORY_REQ *pSMB = NULL;
972 CREATE_DIRECTORY_RSP *pSMBr = NULL;
973 int bytes_returned;
974 int name_len;
975 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
977 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
978 MkDirRetry:
979 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
980 (void **) &pSMBr);
981 if (rc)
982 return rc;
984 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
985 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
986 PATH_MAX, cifs_sb->local_nls,
987 remap);
988 name_len++; /* trailing null */
989 name_len *= 2;
990 } else { /* BB improve check for buffer overruns BB */
991 name_len = strnlen(name, PATH_MAX);
992 name_len++; /* trailing null */
993 strncpy(pSMB->DirName, name, name_len);
996 pSMB->BufferFormat = 0x04;
997 inc_rfc1001_len(pSMB, name_len + 1);
998 pSMB->ByteCount = cpu_to_le16(name_len + 1);
999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1001 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
1002 if (rc)
1003 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
1005 cifs_buf_release(pSMB);
1006 if (rc == -EAGAIN)
1007 goto MkDirRetry;
1008 return rc;
1012 CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1013 __u32 posix_flags, __u64 mode, __u16 *netfid,
1014 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1015 const char *name, const struct nls_table *nls_codepage,
1016 int remap)
1018 TRANSACTION2_SPI_REQ *pSMB = NULL;
1019 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1020 int name_len;
1021 int rc = 0;
1022 int bytes_returned = 0;
1023 __u16 params, param_offset, offset, byte_count, count;
1024 OPEN_PSX_REQ *pdata;
1025 OPEN_PSX_RSP *psx_rsp;
1027 cifs_dbg(FYI, "In POSIX Create\n");
1028 PsxCreat:
1029 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1030 (void **) &pSMBr);
1031 if (rc)
1032 return rc;
1034 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1035 name_len =
1036 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1037 PATH_MAX, nls_codepage, remap);
1038 name_len++; /* trailing null */
1039 name_len *= 2;
1040 } else { /* BB improve the check for buffer overruns BB */
1041 name_len = strnlen(name, PATH_MAX);
1042 name_len++; /* trailing null */
1043 strncpy(pSMB->FileName, name, name_len);
1046 params = 6 + name_len;
1047 count = sizeof(OPEN_PSX_REQ);
1048 pSMB->MaxParameterCount = cpu_to_le16(2);
1049 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1050 pSMB->MaxSetupCount = 0;
1051 pSMB->Reserved = 0;
1052 pSMB->Flags = 0;
1053 pSMB->Timeout = 0;
1054 pSMB->Reserved2 = 0;
1055 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1056 InformationLevel) - 4;
1057 offset = param_offset + params;
1058 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1059 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1060 pdata->Permissions = cpu_to_le64(mode);
1061 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1062 pdata->OpenFlags = cpu_to_le32(*pOplock);
1063 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1064 pSMB->DataOffset = cpu_to_le16(offset);
1065 pSMB->SetupCount = 1;
1066 pSMB->Reserved3 = 0;
1067 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1068 byte_count = 3 /* pad */ + params + count;
1070 pSMB->DataCount = cpu_to_le16(count);
1071 pSMB->ParameterCount = cpu_to_le16(params);
1072 pSMB->TotalDataCount = pSMB->DataCount;
1073 pSMB->TotalParameterCount = pSMB->ParameterCount;
1074 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1075 pSMB->Reserved4 = 0;
1076 inc_rfc1001_len(pSMB, byte_count);
1077 pSMB->ByteCount = cpu_to_le16(byte_count);
1078 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1079 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1080 if (rc) {
1081 cifs_dbg(FYI, "Posix create returned %d\n", rc);
1082 goto psx_create_err;
1085 cifs_dbg(FYI, "copying inode info\n");
1086 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1088 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
1089 rc = -EIO; /* bad smb */
1090 goto psx_create_err;
1093 /* copy return information to pRetData */
1094 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1095 + le16_to_cpu(pSMBr->t2.DataOffset));
1097 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1098 if (netfid)
1099 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1100 /* Let caller know file was created so we can set the mode. */
1101 /* Do we care about the CreateAction in any other cases? */
1102 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1103 *pOplock |= CIFS_CREATE_ACTION;
1104 /* check to make sure response data is there */
1105 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1106 pRetData->Type = cpu_to_le32(-1); /* unknown */
1107 cifs_dbg(NOISY, "unknown type\n");
1108 } else {
1109 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
1110 + sizeof(FILE_UNIX_BASIC_INFO)) {
1111 cifs_dbg(VFS, "Open response data too small\n");
1112 pRetData->Type = cpu_to_le32(-1);
1113 goto psx_create_err;
1115 memcpy((char *) pRetData,
1116 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1117 sizeof(FILE_UNIX_BASIC_INFO));
1120 psx_create_err:
1121 cifs_buf_release(pSMB);
1123 if (posix_flags & SMB_O_DIRECTORY)
1124 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
1125 else
1126 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
1128 if (rc == -EAGAIN)
1129 goto PsxCreat;
1131 return rc;
1134 static __u16 convert_disposition(int disposition)
1136 __u16 ofun = 0;
1138 switch (disposition) {
1139 case FILE_SUPERSEDE:
1140 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1141 break;
1142 case FILE_OPEN:
1143 ofun = SMBOPEN_OAPPEND;
1144 break;
1145 case FILE_CREATE:
1146 ofun = SMBOPEN_OCREATE;
1147 break;
1148 case FILE_OPEN_IF:
1149 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1150 break;
1151 case FILE_OVERWRITE:
1152 ofun = SMBOPEN_OTRUNC;
1153 break;
1154 case FILE_OVERWRITE_IF:
1155 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1156 break;
1157 default:
1158 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
1159 ofun = SMBOPEN_OAPPEND; /* regular open */
1161 return ofun;
1164 static int
1165 access_flags_to_smbopen_mode(const int access_flags)
1167 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1169 if (masked_flags == GENERIC_READ)
1170 return SMBOPEN_READ;
1171 else if (masked_flags == GENERIC_WRITE)
1172 return SMBOPEN_WRITE;
1174 /* just go for read/write */
1175 return SMBOPEN_READWRITE;
1179 SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
1180 const char *fileName, const int openDisposition,
1181 const int access_flags, const int create_options, __u16 *netfid,
1182 int *pOplock, FILE_ALL_INFO *pfile_info,
1183 const struct nls_table *nls_codepage, int remap)
1185 int rc = -EACCES;
1186 OPENX_REQ *pSMB = NULL;
1187 OPENX_RSP *pSMBr = NULL;
1188 int bytes_returned;
1189 int name_len;
1190 __u16 count;
1192 OldOpenRetry:
1193 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1194 (void **) &pSMBr);
1195 if (rc)
1196 return rc;
1198 pSMB->AndXCommand = 0xFF; /* none */
1200 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1201 count = 1; /* account for one byte pad to word boundary */
1202 name_len =
1203 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1204 fileName, PATH_MAX, nls_codepage, remap);
1205 name_len++; /* trailing null */
1206 name_len *= 2;
1207 } else { /* BB improve check for buffer overruns BB */
1208 count = 0; /* no pad */
1209 name_len = strnlen(fileName, PATH_MAX);
1210 name_len++; /* trailing null */
1211 strncpy(pSMB->fileName, fileName, name_len);
1213 if (*pOplock & REQ_OPLOCK)
1214 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1215 else if (*pOplock & REQ_BATCHOPLOCK)
1216 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1218 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1219 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1220 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1221 /* set file as system file if special file such
1222 as fifo and server expecting SFU style and
1223 no Unix extensions */
1225 if (create_options & CREATE_OPTION_SPECIAL)
1226 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1227 else /* BB FIXME BB */
1228 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1230 if (create_options & CREATE_OPTION_READONLY)
1231 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1233 /* BB FIXME BB */
1234 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1235 CREATE_OPTIONS_MASK); */
1236 /* BB FIXME END BB */
1238 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1239 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1240 count += name_len;
1241 inc_rfc1001_len(pSMB, count);
1243 pSMB->ByteCount = cpu_to_le16(count);
1244 /* long_op set to 1 to allow for oplock break timeouts */
1245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1246 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1247 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
1248 if (rc) {
1249 cifs_dbg(FYI, "Error in Open = %d\n", rc);
1250 } else {
1251 /* BB verify if wct == 15 */
1253 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1255 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1256 /* Let caller know file was created so we can set the mode. */
1257 /* Do we care about the CreateAction in any other cases? */
1258 /* BB FIXME BB */
1259 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1260 *pOplock |= CIFS_CREATE_ACTION; */
1261 /* BB FIXME END */
1263 if (pfile_info) {
1264 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1265 pfile_info->LastAccessTime = 0; /* BB fixme */
1266 pfile_info->LastWriteTime = 0; /* BB fixme */
1267 pfile_info->ChangeTime = 0; /* BB fixme */
1268 pfile_info->Attributes =
1269 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1270 /* the file_info buf is endian converted by caller */
1271 pfile_info->AllocationSize =
1272 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1273 pfile_info->EndOfFile = pfile_info->AllocationSize;
1274 pfile_info->NumberOfLinks = cpu_to_le32(1);
1275 pfile_info->DeletePending = 0;
1279 cifs_buf_release(pSMB);
1280 if (rc == -EAGAIN)
1281 goto OldOpenRetry;
1282 return rc;
1286 CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
1287 const char *fileName, const int openDisposition,
1288 const int access_flags, const int create_options, __u16 *netfid,
1289 int *pOplock, FILE_ALL_INFO *pfile_info,
1290 const struct nls_table *nls_codepage, int remap)
1292 int rc = -EACCES;
1293 OPEN_REQ *pSMB = NULL;
1294 OPEN_RSP *pSMBr = NULL;
1295 int bytes_returned;
1296 int name_len;
1297 __u16 count;
1299 openRetry:
1300 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1301 (void **) &pSMBr);
1302 if (rc)
1303 return rc;
1305 pSMB->AndXCommand = 0xFF; /* none */
1307 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1308 count = 1; /* account for one byte pad to word boundary */
1309 name_len =
1310 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1311 fileName, PATH_MAX, nls_codepage, remap);
1312 name_len++; /* trailing null */
1313 name_len *= 2;
1314 pSMB->NameLength = cpu_to_le16(name_len);
1315 } else { /* BB improve check for buffer overruns BB */
1316 count = 0; /* no pad */
1317 name_len = strnlen(fileName, PATH_MAX);
1318 name_len++; /* trailing null */
1319 pSMB->NameLength = cpu_to_le16(name_len);
1320 strncpy(pSMB->fileName, fileName, name_len);
1322 if (*pOplock & REQ_OPLOCK)
1323 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1324 else if (*pOplock & REQ_BATCHOPLOCK)
1325 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1326 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1327 pSMB->AllocationSize = 0;
1328 /* set file as system file if special file such
1329 as fifo and server expecting SFU style and
1330 no Unix extensions */
1331 if (create_options & CREATE_OPTION_SPECIAL)
1332 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1333 else
1334 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1336 /* XP does not handle ATTR_POSIX_SEMANTICS */
1337 /* but it helps speed up case sensitive checks for other
1338 servers such as Samba */
1339 if (tcon->ses->capabilities & CAP_UNIX)
1340 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1342 if (create_options & CREATE_OPTION_READONLY)
1343 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1345 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1346 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1347 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1348 /* BB Expirement with various impersonation levels and verify */
1349 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1350 pSMB->SecurityFlags =
1351 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1353 count += name_len;
1354 inc_rfc1001_len(pSMB, count);
1356 pSMB->ByteCount = cpu_to_le16(count);
1357 /* long_op set to 1 to allow for oplock break timeouts */
1358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1359 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1360 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
1361 if (rc) {
1362 cifs_dbg(FYI, "Error in Open = %d\n", rc);
1363 } else {
1364 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1365 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1366 /* Let caller know file was created so we can set the mode. */
1367 /* Do we care about the CreateAction in any other cases? */
1368 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1369 *pOplock |= CIFS_CREATE_ACTION;
1370 if (pfile_info) {
1371 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1372 36 /* CreationTime to Attributes */);
1373 /* the file_info buf is endian converted by caller */
1374 pfile_info->AllocationSize = pSMBr->AllocationSize;
1375 pfile_info->EndOfFile = pSMBr->EndOfFile;
1376 pfile_info->NumberOfLinks = cpu_to_le32(1);
1377 pfile_info->DeletePending = 0;
1381 cifs_buf_release(pSMB);
1382 if (rc == -EAGAIN)
1383 goto openRetry;
1384 return rc;
1388 * Discard any remaining data in the current SMB. To do this, we borrow the
1389 * current bigbuf.
1391 static int
1392 cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1394 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
1395 int remaining = rfclen + 4 - server->total_read;
1396 struct cifs_readdata *rdata = mid->callback_data;
1398 while (remaining > 0) {
1399 int length;
1401 length = cifs_read_from_socket(server, server->bigbuf,
1402 min_t(unsigned int, remaining,
1403 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
1404 if (length < 0)
1405 return length;
1406 server->total_read += length;
1407 remaining -= length;
1410 dequeue_mid(mid, rdata->result);
1411 return 0;
1415 cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1417 int length, len;
1418 unsigned int data_offset, data_len;
1419 struct cifs_readdata *rdata = mid->callback_data;
1420 char *buf = server->smallbuf;
1421 unsigned int buflen = get_rfc1002_length(buf) + 4;
1423 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1424 __func__, mid->mid, rdata->offset, rdata->bytes);
1427 * read the rest of READ_RSP header (sans Data array), or whatever we
1428 * can if there's not enough data. At this point, we've read down to
1429 * the Mid.
1431 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
1432 HEADER_SIZE(server) + 1;
1434 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1435 rdata->iov.iov_len = len;
1437 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
1438 if (length < 0)
1439 return length;
1440 server->total_read += length;
1442 /* Was the SMB read successful? */
1443 rdata->result = server->ops->map_error(buf, false);
1444 if (rdata->result != 0) {
1445 cifs_dbg(FYI, "%s: server returned error %d\n",
1446 __func__, rdata->result);
1447 return cifs_readv_discard(server, mid);
1450 /* Is there enough to get to the rest of the READ_RSP header? */
1451 if (server->total_read < server->vals->read_rsp_size) {
1452 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1453 __func__, server->total_read,
1454 server->vals->read_rsp_size);
1455 rdata->result = -EIO;
1456 return cifs_readv_discard(server, mid);
1459 data_offset = server->ops->read_data_offset(buf) + 4;
1460 if (data_offset < server->total_read) {
1462 * win2k8 sometimes sends an offset of 0 when the read
1463 * is beyond the EOF. Treat it as if the data starts just after
1464 * the header.
1466 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1467 __func__, data_offset);
1468 data_offset = server->total_read;
1469 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1470 /* data_offset is beyond the end of smallbuf */
1471 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1472 __func__, data_offset);
1473 rdata->result = -EIO;
1474 return cifs_readv_discard(server, mid);
1477 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1478 __func__, server->total_read, data_offset);
1480 len = data_offset - server->total_read;
1481 if (len > 0) {
1482 /* read any junk before data into the rest of smallbuf */
1483 rdata->iov.iov_base = buf + server->total_read;
1484 rdata->iov.iov_len = len;
1485 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
1486 if (length < 0)
1487 return length;
1488 server->total_read += length;
1491 /* set up first iov for signature check */
1492 rdata->iov.iov_base = buf;
1493 rdata->iov.iov_len = server->total_read;
1494 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1495 rdata->iov.iov_base, rdata->iov.iov_len);
1497 /* how much data is in the response? */
1498 data_len = server->ops->read_data_length(buf);
1499 if (data_offset + data_len > buflen) {
1500 /* data_len is corrupt -- discard frame */
1501 rdata->result = -EIO;
1502 return cifs_readv_discard(server, mid);
1505 length = rdata->read_into_pages(server, rdata, data_len);
1506 if (length < 0)
1507 return length;
1509 server->total_read += length;
1510 rdata->bytes = length;
1512 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1513 server->total_read, buflen, data_len);
1515 /* discard anything left over */
1516 if (server->total_read < buflen)
1517 return cifs_readv_discard(server, mid);
1519 dequeue_mid(mid, false);
1520 return length;
1523 static void
1524 cifs_readv_callback(struct mid_q_entry *mid)
1526 struct cifs_readdata *rdata = mid->callback_data;
1527 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1528 struct TCP_Server_Info *server = tcon->ses->server;
1529 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1530 .rq_nvec = 1,
1531 .rq_pages = rdata->pages,
1532 .rq_npages = rdata->nr_pages,
1533 .rq_pagesz = rdata->pagesz,
1534 .rq_tailsz = rdata->tailsz };
1536 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1537 __func__, mid->mid, mid->mid_state, rdata->result,
1538 rdata->bytes);
1540 switch (mid->mid_state) {
1541 case MID_RESPONSE_RECEIVED:
1542 /* result already set, check signature */
1543 if (server->sec_mode &
1544 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1545 int rc = 0;
1547 rc = cifs_verify_signature(&rqst, server,
1548 mid->sequence_number);
1549 if (rc)
1550 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1551 rc);
1553 /* FIXME: should this be counted toward the initiating task? */
1554 task_io_account_read(rdata->bytes);
1555 cifs_stats_bytes_read(tcon, rdata->bytes);
1556 break;
1557 case MID_REQUEST_SUBMITTED:
1558 case MID_RETRY_NEEDED:
1559 rdata->result = -EAGAIN;
1560 break;
1561 default:
1562 rdata->result = -EIO;
1565 queue_work(cifsiod_wq, &rdata->work);
1566 DeleteMidQEntry(mid);
1567 add_credits(server, 1, 0);
1570 /* cifs_async_readv - send an async write, and set up mid to handle result */
1572 cifs_async_readv(struct cifs_readdata *rdata)
1574 int rc;
1575 READ_REQ *smb = NULL;
1576 int wct;
1577 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1578 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1579 .rq_nvec = 1 };
1581 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1582 __func__, rdata->offset, rdata->bytes);
1584 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1585 wct = 12;
1586 else {
1587 wct = 10; /* old style read */
1588 if ((rdata->offset >> 32) > 0) {
1589 /* can not handle this big offset for old */
1590 return -EIO;
1594 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1595 if (rc)
1596 return rc;
1598 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1599 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1601 smb->AndXCommand = 0xFF; /* none */
1602 smb->Fid = rdata->cfile->fid.netfid;
1603 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1604 if (wct == 12)
1605 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1606 smb->Remaining = 0;
1607 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1608 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1609 if (wct == 12)
1610 smb->ByteCount = 0;
1611 else {
1612 /* old style read */
1613 struct smb_com_readx_req *smbr =
1614 (struct smb_com_readx_req *)smb;
1615 smbr->ByteCount = 0;
1618 /* 4 for RFC1001 length + 1 for BCC */
1619 rdata->iov.iov_base = smb;
1620 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1622 kref_get(&rdata->refcount);
1623 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1624 cifs_readv_callback, rdata, 0);
1626 if (rc == 0)
1627 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
1628 else
1629 kref_put(&rdata->refcount, cifs_readdata_release);
1631 cifs_small_buf_release(smb);
1632 return rc;
1636 CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1637 unsigned int *nbytes, char **buf, int *pbuf_type)
1639 int rc = -EACCES;
1640 READ_REQ *pSMB = NULL;
1641 READ_RSP *pSMBr = NULL;
1642 char *pReadData = NULL;
1643 int wct;
1644 int resp_buf_type = 0;
1645 struct kvec iov[1];
1646 __u32 pid = io_parms->pid;
1647 __u16 netfid = io_parms->netfid;
1648 __u64 offset = io_parms->offset;
1649 struct cifs_tcon *tcon = io_parms->tcon;
1650 unsigned int count = io_parms->length;
1652 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
1653 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1654 wct = 12;
1655 else {
1656 wct = 10; /* old style read */
1657 if ((offset >> 32) > 0) {
1658 /* can not handle this big offset for old */
1659 return -EIO;
1663 *nbytes = 0;
1664 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1665 if (rc)
1666 return rc;
1668 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1669 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1671 /* tcon and ses pointer are checked in smb_init */
1672 if (tcon->ses->server == NULL)
1673 return -ECONNABORTED;
1675 pSMB->AndXCommand = 0xFF; /* none */
1676 pSMB->Fid = netfid;
1677 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1678 if (wct == 12)
1679 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1681 pSMB->Remaining = 0;
1682 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1683 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1684 if (wct == 12)
1685 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1686 else {
1687 /* old style read */
1688 struct smb_com_readx_req *pSMBW =
1689 (struct smb_com_readx_req *)pSMB;
1690 pSMBW->ByteCount = 0;
1693 iov[0].iov_base = (char *)pSMB;
1694 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
1695 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1696 &resp_buf_type, CIFS_LOG_ERROR);
1697 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
1698 pSMBr = (READ_RSP *)iov[0].iov_base;
1699 if (rc) {
1700 cifs_dbg(VFS, "Send error in read = %d\n", rc);
1701 } else {
1702 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1703 data_length = data_length << 16;
1704 data_length += le16_to_cpu(pSMBr->DataLength);
1705 *nbytes = data_length;
1707 /*check that DataLength would not go beyond end of SMB */
1708 if ((data_length > CIFSMaxBufSize)
1709 || (data_length > count)) {
1710 cifs_dbg(FYI, "bad length %d for count %d\n",
1711 data_length, count);
1712 rc = -EIO;
1713 *nbytes = 0;
1714 } else {
1715 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1716 le16_to_cpu(pSMBr->DataOffset);
1717 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1718 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
1719 rc = -EFAULT;
1720 }*/ /* can not use copy_to_user when using page cache*/
1721 if (*buf)
1722 memcpy(*buf, pReadData, data_length);
1726 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1727 if (*buf) {
1728 if (resp_buf_type == CIFS_SMALL_BUFFER)
1729 cifs_small_buf_release(iov[0].iov_base);
1730 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1731 cifs_buf_release(iov[0].iov_base);
1732 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1733 /* return buffer to caller to free */
1734 *buf = iov[0].iov_base;
1735 if (resp_buf_type == CIFS_SMALL_BUFFER)
1736 *pbuf_type = CIFS_SMALL_BUFFER;
1737 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1738 *pbuf_type = CIFS_LARGE_BUFFER;
1739 } /* else no valid buffer on return - leave as null */
1741 /* Note: On -EAGAIN error only caller can retry on handle based calls
1742 since file handle passed in no longer valid */
1743 return rc;
1748 CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
1749 unsigned int *nbytes, const char *buf,
1750 const char __user *ubuf, const int long_op)
1752 int rc = -EACCES;
1753 WRITE_REQ *pSMB = NULL;
1754 WRITE_RSP *pSMBr = NULL;
1755 int bytes_returned, wct;
1756 __u32 bytes_sent;
1757 __u16 byte_count;
1758 __u32 pid = io_parms->pid;
1759 __u16 netfid = io_parms->netfid;
1760 __u64 offset = io_parms->offset;
1761 struct cifs_tcon *tcon = io_parms->tcon;
1762 unsigned int count = io_parms->length;
1764 *nbytes = 0;
1766 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
1767 if (tcon->ses == NULL)
1768 return -ECONNABORTED;
1770 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1771 wct = 14;
1772 else {
1773 wct = 12;
1774 if ((offset >> 32) > 0) {
1775 /* can not handle big offset for old srv */
1776 return -EIO;
1780 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1781 (void **) &pSMBr);
1782 if (rc)
1783 return rc;
1785 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1786 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1788 /* tcon and ses pointer are checked in smb_init */
1789 if (tcon->ses->server == NULL)
1790 return -ECONNABORTED;
1792 pSMB->AndXCommand = 0xFF; /* none */
1793 pSMB->Fid = netfid;
1794 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1795 if (wct == 14)
1796 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1798 pSMB->Reserved = 0xFFFFFFFF;
1799 pSMB->WriteMode = 0;
1800 pSMB->Remaining = 0;
1802 /* Can increase buffer size if buffer is big enough in some cases ie we
1803 can send more if LARGE_WRITE_X capability returned by the server and if
1804 our buffer is big enough or if we convert to iovecs on socket writes
1805 and eliminate the copy to the CIFS buffer */
1806 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1807 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1808 } else {
1809 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1810 & ~0xFF;
1813 if (bytes_sent > count)
1814 bytes_sent = count;
1815 pSMB->DataOffset =
1816 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1817 if (buf)
1818 memcpy(pSMB->Data, buf, bytes_sent);
1819 else if (ubuf) {
1820 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1821 cifs_buf_release(pSMB);
1822 return -EFAULT;
1824 } else if (count != 0) {
1825 /* No buffer */
1826 cifs_buf_release(pSMB);
1827 return -EINVAL;
1828 } /* else setting file size with write of zero bytes */
1829 if (wct == 14)
1830 byte_count = bytes_sent + 1; /* pad */
1831 else /* wct == 12 */
1832 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1834 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1835 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1836 inc_rfc1001_len(pSMB, byte_count);
1838 if (wct == 14)
1839 pSMB->ByteCount = cpu_to_le16(byte_count);
1840 else { /* old style write has byte count 4 bytes earlier
1841 so 4 bytes pad */
1842 struct smb_com_writex_req *pSMBW =
1843 (struct smb_com_writex_req *)pSMB;
1844 pSMBW->ByteCount = cpu_to_le16(byte_count);
1847 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1848 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1849 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
1850 if (rc) {
1851 cifs_dbg(FYI, "Send error in write = %d\n", rc);
1852 } else {
1853 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1854 *nbytes = (*nbytes) << 16;
1855 *nbytes += le16_to_cpu(pSMBr->Count);
1858 * Mask off high 16 bits when bytes written as returned by the
1859 * server is greater than bytes requested by the client. Some
1860 * OS/2 servers are known to set incorrect CountHigh values.
1862 if (*nbytes > count)
1863 *nbytes &= 0xFFFF;
1866 cifs_buf_release(pSMB);
1868 /* Note: On -EAGAIN error only caller can retry on handle based calls
1869 since file handle passed in no longer valid */
1871 return rc;
1874 void
1875 cifs_writedata_release(struct kref *refcount)
1877 struct cifs_writedata *wdata = container_of(refcount,
1878 struct cifs_writedata, refcount);
1880 if (wdata->cfile)
1881 cifsFileInfo_put(wdata->cfile);
1883 kfree(wdata);
1887 * Write failed with a retryable error. Resend the write request. It's also
1888 * possible that the page was redirtied so re-clean the page.
1890 static void
1891 cifs_writev_requeue(struct cifs_writedata *wdata)
1893 int i, rc;
1894 struct inode *inode = wdata->cfile->dentry->d_inode;
1895 struct TCP_Server_Info *server;
1897 for (i = 0; i < wdata->nr_pages; i++) {
1898 lock_page(wdata->pages[i]);
1899 clear_page_dirty_for_io(wdata->pages[i]);
1902 do {
1903 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1904 rc = server->ops->async_writev(wdata);
1905 } while (rc == -EAGAIN);
1907 for (i = 0; i < wdata->nr_pages; i++) {
1908 unlock_page(wdata->pages[i]);
1909 if (rc != 0) {
1910 SetPageError(wdata->pages[i]);
1911 end_page_writeback(wdata->pages[i]);
1912 page_cache_release(wdata->pages[i]);
1916 mapping_set_error(inode->i_mapping, rc);
1917 kref_put(&wdata->refcount, cifs_writedata_release);
1920 void
1921 cifs_writev_complete(struct work_struct *work)
1923 struct cifs_writedata *wdata = container_of(work,
1924 struct cifs_writedata, work);
1925 struct inode *inode = wdata->cfile->dentry->d_inode;
1926 int i = 0;
1928 if (wdata->result == 0) {
1929 spin_lock(&inode->i_lock);
1930 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
1931 spin_unlock(&inode->i_lock);
1932 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1933 wdata->bytes);
1934 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1935 return cifs_writev_requeue(wdata);
1937 for (i = 0; i < wdata->nr_pages; i++) {
1938 struct page *page = wdata->pages[i];
1939 if (wdata->result == -EAGAIN)
1940 __set_page_dirty_nobuffers(page);
1941 else if (wdata->result < 0)
1942 SetPageError(page);
1943 end_page_writeback(page);
1944 page_cache_release(page);
1946 if (wdata->result != -EAGAIN)
1947 mapping_set_error(inode->i_mapping, wdata->result);
1948 kref_put(&wdata->refcount, cifs_writedata_release);
1951 struct cifs_writedata *
1952 cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
1954 struct cifs_writedata *wdata;
1956 /* this would overflow */
1957 if (nr_pages == 0) {
1958 cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
1959 return NULL;
1962 /* writedata + number of page pointers */
1963 wdata = kzalloc(sizeof(*wdata) +
1964 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1965 if (wdata != NULL) {
1966 kref_init(&wdata->refcount);
1967 INIT_LIST_HEAD(&wdata->list);
1968 init_completion(&wdata->done);
1969 INIT_WORK(&wdata->work, complete);
1971 return wdata;
1975 * Check the mid_state and signature on received buffer (if any), and queue the
1976 * workqueue completion task.
1978 static void
1979 cifs_writev_callback(struct mid_q_entry *mid)
1981 struct cifs_writedata *wdata = mid->callback_data;
1982 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
1983 unsigned int written;
1984 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1986 switch (mid->mid_state) {
1987 case MID_RESPONSE_RECEIVED:
1988 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1989 if (wdata->result != 0)
1990 break;
1992 written = le16_to_cpu(smb->CountHigh);
1993 written <<= 16;
1994 written += le16_to_cpu(smb->Count);
1996 * Mask off high 16 bits when bytes written as returned
1997 * by the server is greater than bytes requested by the
1998 * client. OS/2 servers are known to set incorrect
1999 * CountHigh values.
2001 if (written > wdata->bytes)
2002 written &= 0xFFFF;
2004 if (written < wdata->bytes)
2005 wdata->result = -ENOSPC;
2006 else
2007 wdata->bytes = written;
2008 break;
2009 case MID_REQUEST_SUBMITTED:
2010 case MID_RETRY_NEEDED:
2011 wdata->result = -EAGAIN;
2012 break;
2013 default:
2014 wdata->result = -EIO;
2015 break;
2018 queue_work(cifsiod_wq, &wdata->work);
2019 DeleteMidQEntry(mid);
2020 add_credits(tcon->ses->server, 1, 0);
2023 /* cifs_async_writev - send an async write, and set up mid to handle result */
2025 cifs_async_writev(struct cifs_writedata *wdata)
2027 int rc = -EACCES;
2028 WRITE_REQ *smb = NULL;
2029 int wct;
2030 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
2031 struct kvec iov;
2032 struct smb_rqst rqst = { };
2034 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2035 wct = 14;
2036 } else {
2037 wct = 12;
2038 if (wdata->offset >> 32 > 0) {
2039 /* can not handle big offset for old srv */
2040 return -EIO;
2044 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2045 if (rc)
2046 goto async_writev_out;
2048 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2049 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
2051 smb->AndXCommand = 0xFF; /* none */
2052 smb->Fid = wdata->cfile->fid.netfid;
2053 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2054 if (wct == 14)
2055 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2056 smb->Reserved = 0xFFFFFFFF;
2057 smb->WriteMode = 0;
2058 smb->Remaining = 0;
2060 smb->DataOffset =
2061 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2063 /* 4 for RFC1001 length + 1 for BCC */
2064 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2065 iov.iov_base = smb;
2067 rqst.rq_iov = &iov;
2068 rqst.rq_nvec = 1;
2069 rqst.rq_pages = wdata->pages;
2070 rqst.rq_npages = wdata->nr_pages;
2071 rqst.rq_pagesz = wdata->pagesz;
2072 rqst.rq_tailsz = wdata->tailsz;
2074 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2075 wdata->offset, wdata->bytes);
2077 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2078 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2080 if (wct == 14) {
2081 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2082 put_bcc(wdata->bytes + 1, &smb->hdr);
2083 } else {
2084 /* wct == 12 */
2085 struct smb_com_writex_req *smbw =
2086 (struct smb_com_writex_req *)smb;
2087 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2088 put_bcc(wdata->bytes + 5, &smbw->hdr);
2089 iov.iov_len += 4; /* pad bigger by four bytes */
2092 kref_get(&wdata->refcount);
2093 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2094 cifs_writev_callback, wdata, 0);
2096 if (rc == 0)
2097 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
2098 else
2099 kref_put(&wdata->refcount, cifs_writedata_release);
2101 async_writev_out:
2102 cifs_small_buf_release(smb);
2103 return rc;
2107 CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
2108 unsigned int *nbytes, struct kvec *iov, int n_vec)
2110 int rc = -EACCES;
2111 WRITE_REQ *pSMB = NULL;
2112 int wct;
2113 int smb_hdr_len;
2114 int resp_buf_type = 0;
2115 __u32 pid = io_parms->pid;
2116 __u16 netfid = io_parms->netfid;
2117 __u64 offset = io_parms->offset;
2118 struct cifs_tcon *tcon = io_parms->tcon;
2119 unsigned int count = io_parms->length;
2121 *nbytes = 0;
2123 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
2125 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2126 wct = 14;
2127 } else {
2128 wct = 12;
2129 if ((offset >> 32) > 0) {
2130 /* can not handle big offset for old srv */
2131 return -EIO;
2134 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
2135 if (rc)
2136 return rc;
2138 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2139 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2141 /* tcon and ses pointer are checked in smb_init */
2142 if (tcon->ses->server == NULL)
2143 return -ECONNABORTED;
2145 pSMB->AndXCommand = 0xFF; /* none */
2146 pSMB->Fid = netfid;
2147 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
2148 if (wct == 14)
2149 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
2150 pSMB->Reserved = 0xFFFFFFFF;
2151 pSMB->WriteMode = 0;
2152 pSMB->Remaining = 0;
2154 pSMB->DataOffset =
2155 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2157 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2158 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
2159 /* header + 1 byte pad */
2160 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
2161 if (wct == 14)
2162 inc_rfc1001_len(pSMB, count + 1);
2163 else /* wct == 12 */
2164 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
2165 if (wct == 14)
2166 pSMB->ByteCount = cpu_to_le16(count + 1);
2167 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
2168 struct smb_com_writex_req *pSMBW =
2169 (struct smb_com_writex_req *)pSMB;
2170 pSMBW->ByteCount = cpu_to_le16(count + 5);
2172 iov[0].iov_base = pSMB;
2173 if (wct == 14)
2174 iov[0].iov_len = smb_hdr_len + 4;
2175 else /* wct == 12 pad bigger by four bytes */
2176 iov[0].iov_len = smb_hdr_len + 8;
2179 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
2180 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
2181 if (rc) {
2182 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
2183 } else if (resp_buf_type == 0) {
2184 /* presumably this can not happen, but best to be safe */
2185 rc = -EIO;
2186 } else {
2187 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
2188 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2189 *nbytes = (*nbytes) << 16;
2190 *nbytes += le16_to_cpu(pSMBr->Count);
2193 * Mask off high 16 bits when bytes written as returned by the
2194 * server is greater than bytes requested by the client. OS/2
2195 * servers are known to set incorrect CountHigh values.
2197 if (*nbytes > count)
2198 *nbytes &= 0xFFFF;
2201 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2202 if (resp_buf_type == CIFS_SMALL_BUFFER)
2203 cifs_small_buf_release(iov[0].iov_base);
2204 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2205 cifs_buf_release(iov[0].iov_base);
2207 /* Note: On -EAGAIN error only caller can retry on handle based calls
2208 since file handle passed in no longer valid */
2210 return rc;
2213 int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2214 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
2215 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2217 int rc = 0;
2218 LOCK_REQ *pSMB = NULL;
2219 struct kvec iov[2];
2220 int resp_buf_type;
2221 __u16 count;
2223 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2224 num_lock, num_unlock);
2226 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2227 if (rc)
2228 return rc;
2230 pSMB->Timeout = 0;
2231 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2232 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2233 pSMB->LockType = lock_type;
2234 pSMB->AndXCommand = 0xFF; /* none */
2235 pSMB->Fid = netfid; /* netfid stays le */
2237 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2238 inc_rfc1001_len(pSMB, count);
2239 pSMB->ByteCount = cpu_to_le16(count);
2241 iov[0].iov_base = (char *)pSMB;
2242 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2243 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2244 iov[1].iov_base = (char *)buf;
2245 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2247 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
2248 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2249 if (rc)
2250 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
2252 return rc;
2256 CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
2257 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
2258 const __u64 offset, const __u32 numUnlock,
2259 const __u32 numLock, const __u8 lockType,
2260 const bool waitFlag, const __u8 oplock_level)
2262 int rc = 0;
2263 LOCK_REQ *pSMB = NULL;
2264 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
2265 int bytes_returned;
2266 int flags = 0;
2267 __u16 count;
2269 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2270 (int)waitFlag, numLock);
2271 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2273 if (rc)
2274 return rc;
2276 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
2277 /* no response expected */
2278 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
2279 pSMB->Timeout = 0;
2280 } else if (waitFlag) {
2281 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2282 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2283 } else {
2284 pSMB->Timeout = 0;
2287 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2288 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2289 pSMB->LockType = lockType;
2290 pSMB->OplockLevel = oplock_level;
2291 pSMB->AndXCommand = 0xFF; /* none */
2292 pSMB->Fid = smb_file_id; /* netfid stays le */
2294 if ((numLock != 0) || (numUnlock != 0)) {
2295 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
2296 /* BB where to store pid high? */
2297 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2298 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2299 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2300 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2301 count = sizeof(LOCKING_ANDX_RANGE);
2302 } else {
2303 /* oplock break */
2304 count = 0;
2306 inc_rfc1001_len(pSMB, count);
2307 pSMB->ByteCount = cpu_to_le16(count);
2309 if (waitFlag) {
2310 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2311 (struct smb_hdr *) pSMB, &bytes_returned);
2312 cifs_small_buf_release(pSMB);
2313 } else {
2314 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
2315 /* SMB buffer freed by function above */
2317 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
2318 if (rc)
2319 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
2321 /* Note: On -EAGAIN error only caller can retry on handle based calls
2322 since file handle passed in no longer valid */
2323 return rc;
2327 CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
2328 const __u16 smb_file_id, const __u32 netpid,
2329 const loff_t start_offset, const __u64 len,
2330 struct file_lock *pLockData, const __u16 lock_type,
2331 const bool waitFlag)
2333 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2334 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2335 struct cifs_posix_lock *parm_data;
2336 int rc = 0;
2337 int timeout = 0;
2338 int bytes_returned = 0;
2339 int resp_buf_type = 0;
2340 __u16 params, param_offset, offset, byte_count, count;
2341 struct kvec iov[1];
2343 cifs_dbg(FYI, "Posix Lock\n");
2345 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2347 if (rc)
2348 return rc;
2350 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2352 params = 6;
2353 pSMB->MaxSetupCount = 0;
2354 pSMB->Reserved = 0;
2355 pSMB->Flags = 0;
2356 pSMB->Reserved2 = 0;
2357 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2358 offset = param_offset + params;
2360 count = sizeof(struct cifs_posix_lock);
2361 pSMB->MaxParameterCount = cpu_to_le16(2);
2362 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2363 pSMB->SetupCount = 1;
2364 pSMB->Reserved3 = 0;
2365 if (pLockData)
2366 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2367 else
2368 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2369 byte_count = 3 /* pad */ + params + count;
2370 pSMB->DataCount = cpu_to_le16(count);
2371 pSMB->ParameterCount = cpu_to_le16(params);
2372 pSMB->TotalDataCount = pSMB->DataCount;
2373 pSMB->TotalParameterCount = pSMB->ParameterCount;
2374 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2375 parm_data = (struct cifs_posix_lock *)
2376 (((char *) &pSMB->hdr.Protocol) + offset);
2378 parm_data->lock_type = cpu_to_le16(lock_type);
2379 if (waitFlag) {
2380 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2381 parm_data->lock_flags = cpu_to_le16(1);
2382 pSMB->Timeout = cpu_to_le32(-1);
2383 } else
2384 pSMB->Timeout = 0;
2386 parm_data->pid = cpu_to_le32(netpid);
2387 parm_data->start = cpu_to_le64(start_offset);
2388 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
2390 pSMB->DataOffset = cpu_to_le16(offset);
2391 pSMB->Fid = smb_file_id;
2392 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2393 pSMB->Reserved4 = 0;
2394 inc_rfc1001_len(pSMB, byte_count);
2395 pSMB->ByteCount = cpu_to_le16(byte_count);
2396 if (waitFlag) {
2397 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2398 (struct smb_hdr *) pSMBr, &bytes_returned);
2399 } else {
2400 iov[0].iov_base = (char *)pSMB;
2401 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
2402 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2403 &resp_buf_type, timeout);
2404 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2405 not try to free it twice below on exit */
2406 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
2409 if (rc) {
2410 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
2411 } else if (pLockData) {
2412 /* lock structure can be returned on get */
2413 __u16 data_offset;
2414 __u16 data_count;
2415 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2417 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
2418 rc = -EIO; /* bad smb */
2419 goto plk_err_exit;
2421 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2422 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2423 if (data_count < sizeof(struct cifs_posix_lock)) {
2424 rc = -EIO;
2425 goto plk_err_exit;
2427 parm_data = (struct cifs_posix_lock *)
2428 ((char *)&pSMBr->hdr.Protocol + data_offset);
2429 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
2430 pLockData->fl_type = F_UNLCK;
2431 else {
2432 if (parm_data->lock_type ==
2433 __constant_cpu_to_le16(CIFS_RDLCK))
2434 pLockData->fl_type = F_RDLCK;
2435 else if (parm_data->lock_type ==
2436 __constant_cpu_to_le16(CIFS_WRLCK))
2437 pLockData->fl_type = F_WRLCK;
2439 pLockData->fl_start = le64_to_cpu(parm_data->start);
2440 pLockData->fl_end = pLockData->fl_start +
2441 le64_to_cpu(parm_data->length) - 1;
2442 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
2446 plk_err_exit:
2447 if (pSMB)
2448 cifs_small_buf_release(pSMB);
2450 if (resp_buf_type == CIFS_SMALL_BUFFER)
2451 cifs_small_buf_release(iov[0].iov_base);
2452 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2453 cifs_buf_release(iov[0].iov_base);
2455 /* Note: On -EAGAIN error only caller can retry on handle based calls
2456 since file handle passed in no longer valid */
2458 return rc;
2463 CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
2465 int rc = 0;
2466 CLOSE_REQ *pSMB = NULL;
2467 cifs_dbg(FYI, "In CIFSSMBClose\n");
2469 /* do not retry on dead session on close */
2470 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
2471 if (rc == -EAGAIN)
2472 return 0;
2473 if (rc)
2474 return rc;
2476 pSMB->FileID = (__u16) smb_file_id;
2477 pSMB->LastWriteTime = 0xFFFFFFFF;
2478 pSMB->ByteCount = 0;
2479 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
2480 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
2481 if (rc) {
2482 if (rc != -EINTR) {
2483 /* EINTR is expected when user ctl-c to kill app */
2484 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
2488 /* Since session is dead, file will be closed on server already */
2489 if (rc == -EAGAIN)
2490 rc = 0;
2492 return rc;
2496 CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
2498 int rc = 0;
2499 FLUSH_REQ *pSMB = NULL;
2500 cifs_dbg(FYI, "In CIFSSMBFlush\n");
2502 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2503 if (rc)
2504 return rc;
2506 pSMB->FileID = (__u16) smb_file_id;
2507 pSMB->ByteCount = 0;
2508 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
2509 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
2510 if (rc)
2511 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
2513 return rc;
2517 CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
2518 const char *from_name, const char *to_name,
2519 struct cifs_sb_info *cifs_sb)
2521 int rc = 0;
2522 RENAME_REQ *pSMB = NULL;
2523 RENAME_RSP *pSMBr = NULL;
2524 int bytes_returned;
2525 int name_len, name_len2;
2526 __u16 count;
2527 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
2529 cifs_dbg(FYI, "In CIFSSMBRename\n");
2530 renameRetry:
2531 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2532 (void **) &pSMBr);
2533 if (rc)
2534 return rc;
2536 pSMB->BufferFormat = 0x04;
2537 pSMB->SearchAttributes =
2538 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2539 ATTR_DIRECTORY);
2541 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2542 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2543 from_name, PATH_MAX,
2544 cifs_sb->local_nls, remap);
2545 name_len++; /* trailing null */
2546 name_len *= 2;
2547 pSMB->OldFileName[name_len] = 0x04; /* pad */
2548 /* protocol requires ASCII signature byte on Unicode string */
2549 pSMB->OldFileName[name_len + 1] = 0x00;
2550 name_len2 =
2551 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2552 to_name, PATH_MAX, cifs_sb->local_nls,
2553 remap);
2554 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2555 name_len2 *= 2; /* convert to bytes */
2556 } else { /* BB improve the check for buffer overruns BB */
2557 name_len = strnlen(from_name, PATH_MAX);
2558 name_len++; /* trailing null */
2559 strncpy(pSMB->OldFileName, from_name, name_len);
2560 name_len2 = strnlen(to_name, PATH_MAX);
2561 name_len2++; /* trailing null */
2562 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2563 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
2564 name_len2++; /* trailing null */
2565 name_len2++; /* signature byte */
2568 count = 1 /* 1st signature byte */ + name_len + name_len2;
2569 inc_rfc1001_len(pSMB, count);
2570 pSMB->ByteCount = cpu_to_le16(count);
2572 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2573 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2574 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
2575 if (rc)
2576 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
2578 cifs_buf_release(pSMB);
2580 if (rc == -EAGAIN)
2581 goto renameRetry;
2583 return rc;
2586 int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
2587 int netfid, const char *target_name,
2588 const struct nls_table *nls_codepage, int remap)
2590 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2591 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2592 struct set_file_rename *rename_info;
2593 char *data_offset;
2594 char dummy_string[30];
2595 int rc = 0;
2596 int bytes_returned = 0;
2597 int len_of_str;
2598 __u16 params, param_offset, offset, count, byte_count;
2600 cifs_dbg(FYI, "Rename to File by handle\n");
2601 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2602 (void **) &pSMBr);
2603 if (rc)
2604 return rc;
2606 params = 6;
2607 pSMB->MaxSetupCount = 0;
2608 pSMB->Reserved = 0;
2609 pSMB->Flags = 0;
2610 pSMB->Timeout = 0;
2611 pSMB->Reserved2 = 0;
2612 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2613 offset = param_offset + params;
2615 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2616 rename_info = (struct set_file_rename *) data_offset;
2617 pSMB->MaxParameterCount = cpu_to_le16(2);
2618 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2619 pSMB->SetupCount = 1;
2620 pSMB->Reserved3 = 0;
2621 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2622 byte_count = 3 /* pad */ + params;
2623 pSMB->ParameterCount = cpu_to_le16(params);
2624 pSMB->TotalParameterCount = pSMB->ParameterCount;
2625 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2626 pSMB->DataOffset = cpu_to_le16(offset);
2627 /* construct random name ".cifs_tmp<inodenum><mid>" */
2628 rename_info->overwrite = cpu_to_le32(1);
2629 rename_info->root_fid = 0;
2630 /* unicode only call */
2631 if (target_name == NULL) {
2632 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2633 len_of_str =
2634 cifsConvertToUTF16((__le16 *)rename_info->target_name,
2635 dummy_string, 24, nls_codepage, remap);
2636 } else {
2637 len_of_str =
2638 cifsConvertToUTF16((__le16 *)rename_info->target_name,
2639 target_name, PATH_MAX, nls_codepage,
2640 remap);
2642 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2643 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2644 byte_count += count;
2645 pSMB->DataCount = cpu_to_le16(count);
2646 pSMB->TotalDataCount = pSMB->DataCount;
2647 pSMB->Fid = netfid;
2648 pSMB->InformationLevel =
2649 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2650 pSMB->Reserved4 = 0;
2651 inc_rfc1001_len(pSMB, byte_count);
2652 pSMB->ByteCount = cpu_to_le16(byte_count);
2653 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2654 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2655 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
2656 if (rc)
2657 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2658 rc);
2660 cifs_buf_release(pSMB);
2662 /* Note: On -EAGAIN error only caller can retry on handle based calls
2663 since file handle passed in no longer valid */
2665 return rc;
2669 CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2670 const char *fromName, const __u16 target_tid, const char *toName,
2671 const int flags, const struct nls_table *nls_codepage, int remap)
2673 int rc = 0;
2674 COPY_REQ *pSMB = NULL;
2675 COPY_RSP *pSMBr = NULL;
2676 int bytes_returned;
2677 int name_len, name_len2;
2678 __u16 count;
2680 cifs_dbg(FYI, "In CIFSSMBCopy\n");
2681 copyRetry:
2682 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2683 (void **) &pSMBr);
2684 if (rc)
2685 return rc;
2687 pSMB->BufferFormat = 0x04;
2688 pSMB->Tid2 = target_tid;
2690 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2692 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2693 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2694 fromName, PATH_MAX, nls_codepage,
2695 remap);
2696 name_len++; /* trailing null */
2697 name_len *= 2;
2698 pSMB->OldFileName[name_len] = 0x04; /* pad */
2699 /* protocol requires ASCII signature byte on Unicode string */
2700 pSMB->OldFileName[name_len + 1] = 0x00;
2701 name_len2 =
2702 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2703 toName, PATH_MAX, nls_codepage, remap);
2704 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2705 name_len2 *= 2; /* convert to bytes */
2706 } else { /* BB improve the check for buffer overruns BB */
2707 name_len = strnlen(fromName, PATH_MAX);
2708 name_len++; /* trailing null */
2709 strncpy(pSMB->OldFileName, fromName, name_len);
2710 name_len2 = strnlen(toName, PATH_MAX);
2711 name_len2++; /* trailing null */
2712 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2713 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2714 name_len2++; /* trailing null */
2715 name_len2++; /* signature byte */
2718 count = 1 /* 1st signature byte */ + name_len + name_len2;
2719 inc_rfc1001_len(pSMB, count);
2720 pSMB->ByteCount = cpu_to_le16(count);
2722 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2723 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2724 if (rc) {
2725 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2726 rc, le16_to_cpu(pSMBr->CopyCount));
2728 cifs_buf_release(pSMB);
2730 if (rc == -EAGAIN)
2731 goto copyRetry;
2733 return rc;
2737 CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
2738 const char *fromName, const char *toName,
2739 const struct nls_table *nls_codepage)
2741 TRANSACTION2_SPI_REQ *pSMB = NULL;
2742 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2743 char *data_offset;
2744 int name_len;
2745 int name_len_target;
2746 int rc = 0;
2747 int bytes_returned = 0;
2748 __u16 params, param_offset, offset, byte_count;
2750 cifs_dbg(FYI, "In Symlink Unix style\n");
2751 createSymLinkRetry:
2752 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2753 (void **) &pSMBr);
2754 if (rc)
2755 return rc;
2757 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2758 name_len =
2759 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2760 /* find define for this maxpathcomponent */
2761 PATH_MAX, nls_codepage);
2762 name_len++; /* trailing null */
2763 name_len *= 2;
2765 } else { /* BB improve the check for buffer overruns BB */
2766 name_len = strnlen(fromName, PATH_MAX);
2767 name_len++; /* trailing null */
2768 strncpy(pSMB->FileName, fromName, name_len);
2770 params = 6 + name_len;
2771 pSMB->MaxSetupCount = 0;
2772 pSMB->Reserved = 0;
2773 pSMB->Flags = 0;
2774 pSMB->Timeout = 0;
2775 pSMB->Reserved2 = 0;
2776 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2777 InformationLevel) - 4;
2778 offset = param_offset + params;
2780 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2781 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2782 name_len_target =
2783 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2784 /* find define for this maxpathcomponent */
2785 , nls_codepage);
2786 name_len_target++; /* trailing null */
2787 name_len_target *= 2;
2788 } else { /* BB improve the check for buffer overruns BB */
2789 name_len_target = strnlen(toName, PATH_MAX);
2790 name_len_target++; /* trailing null */
2791 strncpy(data_offset, toName, name_len_target);
2794 pSMB->MaxParameterCount = cpu_to_le16(2);
2795 /* BB find exact max on data count below from sess */
2796 pSMB->MaxDataCount = cpu_to_le16(1000);
2797 pSMB->SetupCount = 1;
2798 pSMB->Reserved3 = 0;
2799 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2800 byte_count = 3 /* pad */ + params + name_len_target;
2801 pSMB->DataCount = cpu_to_le16(name_len_target);
2802 pSMB->ParameterCount = cpu_to_le16(params);
2803 pSMB->TotalDataCount = pSMB->DataCount;
2804 pSMB->TotalParameterCount = pSMB->ParameterCount;
2805 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2806 pSMB->DataOffset = cpu_to_le16(offset);
2807 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2808 pSMB->Reserved4 = 0;
2809 inc_rfc1001_len(pSMB, byte_count);
2810 pSMB->ByteCount = cpu_to_le16(byte_count);
2811 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2812 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2813 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
2814 if (rc)
2815 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2816 rc);
2818 cifs_buf_release(pSMB);
2820 if (rc == -EAGAIN)
2821 goto createSymLinkRetry;
2823 return rc;
2827 CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
2828 const char *fromName, const char *toName,
2829 const struct nls_table *nls_codepage, int remap)
2831 TRANSACTION2_SPI_REQ *pSMB = NULL;
2832 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2833 char *data_offset;
2834 int name_len;
2835 int name_len_target;
2836 int rc = 0;
2837 int bytes_returned = 0;
2838 __u16 params, param_offset, offset, byte_count;
2840 cifs_dbg(FYI, "In Create Hard link Unix style\n");
2841 createHardLinkRetry:
2842 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2843 (void **) &pSMBr);
2844 if (rc)
2845 return rc;
2847 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2848 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2849 PATH_MAX, nls_codepage, remap);
2850 name_len++; /* trailing null */
2851 name_len *= 2;
2853 } else { /* BB improve the check for buffer overruns BB */
2854 name_len = strnlen(toName, PATH_MAX);
2855 name_len++; /* trailing null */
2856 strncpy(pSMB->FileName, toName, name_len);
2858 params = 6 + name_len;
2859 pSMB->MaxSetupCount = 0;
2860 pSMB->Reserved = 0;
2861 pSMB->Flags = 0;
2862 pSMB->Timeout = 0;
2863 pSMB->Reserved2 = 0;
2864 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2865 InformationLevel) - 4;
2866 offset = param_offset + params;
2868 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2869 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2870 name_len_target =
2871 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2872 PATH_MAX, nls_codepage, remap);
2873 name_len_target++; /* trailing null */
2874 name_len_target *= 2;
2875 } else { /* BB improve the check for buffer overruns BB */
2876 name_len_target = strnlen(fromName, PATH_MAX);
2877 name_len_target++; /* trailing null */
2878 strncpy(data_offset, fromName, name_len_target);
2881 pSMB->MaxParameterCount = cpu_to_le16(2);
2882 /* BB find exact max on data count below from sess*/
2883 pSMB->MaxDataCount = cpu_to_le16(1000);
2884 pSMB->SetupCount = 1;
2885 pSMB->Reserved3 = 0;
2886 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2887 byte_count = 3 /* pad */ + params + name_len_target;
2888 pSMB->ParameterCount = cpu_to_le16(params);
2889 pSMB->TotalParameterCount = pSMB->ParameterCount;
2890 pSMB->DataCount = cpu_to_le16(name_len_target);
2891 pSMB->TotalDataCount = pSMB->DataCount;
2892 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2893 pSMB->DataOffset = cpu_to_le16(offset);
2894 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2895 pSMB->Reserved4 = 0;
2896 inc_rfc1001_len(pSMB, byte_count);
2897 pSMB->ByteCount = cpu_to_le16(byte_count);
2898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2899 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2900 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
2901 if (rc)
2902 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2903 rc);
2905 cifs_buf_release(pSMB);
2906 if (rc == -EAGAIN)
2907 goto createHardLinkRetry;
2909 return rc;
2913 CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
2914 const char *from_name, const char *to_name,
2915 struct cifs_sb_info *cifs_sb)
2917 int rc = 0;
2918 NT_RENAME_REQ *pSMB = NULL;
2919 RENAME_RSP *pSMBr = NULL;
2920 int bytes_returned;
2921 int name_len, name_len2;
2922 __u16 count;
2923 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
2925 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
2926 winCreateHardLinkRetry:
2928 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2929 (void **) &pSMBr);
2930 if (rc)
2931 return rc;
2933 pSMB->SearchAttributes =
2934 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2935 ATTR_DIRECTORY);
2936 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2937 pSMB->ClusterCount = 0;
2939 pSMB->BufferFormat = 0x04;
2941 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2942 name_len =
2943 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2944 PATH_MAX, cifs_sb->local_nls, remap);
2945 name_len++; /* trailing null */
2946 name_len *= 2;
2948 /* protocol specifies ASCII buffer format (0x04) for unicode */
2949 pSMB->OldFileName[name_len] = 0x04;
2950 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2951 name_len2 =
2952 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2953 to_name, PATH_MAX, cifs_sb->local_nls,
2954 remap);
2955 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2956 name_len2 *= 2; /* convert to bytes */
2957 } else { /* BB improve the check for buffer overruns BB */
2958 name_len = strnlen(from_name, PATH_MAX);
2959 name_len++; /* trailing null */
2960 strncpy(pSMB->OldFileName, from_name, name_len);
2961 name_len2 = strnlen(to_name, PATH_MAX);
2962 name_len2++; /* trailing null */
2963 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2964 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
2965 name_len2++; /* trailing null */
2966 name_len2++; /* signature byte */
2969 count = 1 /* string type byte */ + name_len + name_len2;
2970 inc_rfc1001_len(pSMB, count);
2971 pSMB->ByteCount = cpu_to_le16(count);
2973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2975 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
2976 if (rc)
2977 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
2979 cifs_buf_release(pSMB);
2980 if (rc == -EAGAIN)
2981 goto winCreateHardLinkRetry;
2983 return rc;
2987 CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
2988 const unsigned char *searchName, char **symlinkinfo,
2989 const struct nls_table *nls_codepage)
2991 /* SMB_QUERY_FILE_UNIX_LINK */
2992 TRANSACTION2_QPI_REQ *pSMB = NULL;
2993 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2994 int rc = 0;
2995 int bytes_returned;
2996 int name_len;
2997 __u16 params, byte_count;
2998 char *data_start;
3000 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
3002 querySymLinkRetry:
3003 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3004 (void **) &pSMBr);
3005 if (rc)
3006 return rc;
3008 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3009 name_len =
3010 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3011 PATH_MAX, nls_codepage);
3012 name_len++; /* trailing null */
3013 name_len *= 2;
3014 } else { /* BB improve the check for buffer overruns BB */
3015 name_len = strnlen(searchName, PATH_MAX);
3016 name_len++; /* trailing null */
3017 strncpy(pSMB->FileName, searchName, name_len);
3020 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3021 pSMB->TotalDataCount = 0;
3022 pSMB->MaxParameterCount = cpu_to_le16(2);
3023 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3024 pSMB->MaxSetupCount = 0;
3025 pSMB->Reserved = 0;
3026 pSMB->Flags = 0;
3027 pSMB->Timeout = 0;
3028 pSMB->Reserved2 = 0;
3029 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3030 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3031 pSMB->DataCount = 0;
3032 pSMB->DataOffset = 0;
3033 pSMB->SetupCount = 1;
3034 pSMB->Reserved3 = 0;
3035 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3036 byte_count = params + 1 /* pad */ ;
3037 pSMB->TotalParameterCount = cpu_to_le16(params);
3038 pSMB->ParameterCount = pSMB->TotalParameterCount;
3039 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3040 pSMB->Reserved4 = 0;
3041 inc_rfc1001_len(pSMB, byte_count);
3042 pSMB->ByteCount = cpu_to_le16(byte_count);
3044 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3045 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3046 if (rc) {
3047 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
3048 } else {
3049 /* decode response */
3051 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3052 /* BB also check enough total bytes returned */
3053 if (rc || get_bcc(&pSMBr->hdr) < 2)
3054 rc = -EIO;
3055 else {
3056 bool is_unicode;
3057 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3059 data_start = ((char *) &pSMBr->hdr.Protocol) +
3060 le16_to_cpu(pSMBr->t2.DataOffset);
3062 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3063 is_unicode = true;
3064 else
3065 is_unicode = false;
3067 /* BB FIXME investigate remapping reserved chars here */
3068 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3069 count, is_unicode, nls_codepage);
3070 if (!*symlinkinfo)
3071 rc = -ENOMEM;
3074 cifs_buf_release(pSMB);
3075 if (rc == -EAGAIN)
3076 goto querySymLinkRetry;
3077 return rc;
3080 #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3082 * Recent Windows versions now create symlinks more frequently
3083 * and they use the "reparse point" mechanism below. We can of course
3084 * do symlinks nicely to Samba and other servers which support the
3085 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3086 * "MF" symlinks optionally, but for recent Windows we really need to
3087 * reenable the code below and fix the cifs_symlink callers to handle this.
3088 * In the interim this code has been moved to its own config option so
3089 * it is not compiled in by default until callers fixed up and more tested.
3092 CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
3093 const unsigned char *searchName,
3094 char *symlinkinfo, const int buflen, __u16 fid,
3095 const struct nls_table *nls_codepage)
3097 int rc = 0;
3098 int bytes_returned;
3099 struct smb_com_transaction_ioctl_req *pSMB;
3100 struct smb_com_transaction_ioctl_rsp *pSMBr;
3102 cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n",
3103 searchName);
3104 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3105 (void **) &pSMBr);
3106 if (rc)
3107 return rc;
3109 pSMB->TotalParameterCount = 0 ;
3110 pSMB->TotalDataCount = 0;
3111 pSMB->MaxParameterCount = cpu_to_le32(2);
3112 /* BB find exact data count max from sess structure BB */
3113 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
3114 pSMB->MaxSetupCount = 4;
3115 pSMB->Reserved = 0;
3116 pSMB->ParameterOffset = 0;
3117 pSMB->DataCount = 0;
3118 pSMB->DataOffset = 0;
3119 pSMB->SetupCount = 4;
3120 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3121 pSMB->ParameterCount = pSMB->TotalParameterCount;
3122 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3123 pSMB->IsFsctl = 1; /* FSCTL */
3124 pSMB->IsRootFlag = 0;
3125 pSMB->Fid = fid; /* file handle always le */
3126 pSMB->ByteCount = 0;
3128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3129 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3130 if (rc) {
3131 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
3132 } else { /* decode response */
3133 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3134 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
3135 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3136 /* BB also check enough total bytes returned */
3137 rc = -EIO; /* bad smb */
3138 goto qreparse_out;
3140 if (data_count && (data_count < 2048)) {
3141 char *end_of_smb = 2 /* sizeof byte count */ +
3142 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
3144 struct reparse_data *reparse_buf =
3145 (struct reparse_data *)
3146 ((char *)&pSMBr->hdr.Protocol
3147 + data_offset);
3148 if ((char *)reparse_buf >= end_of_smb) {
3149 rc = -EIO;
3150 goto qreparse_out;
3152 if ((reparse_buf->LinkNamesBuf +
3153 reparse_buf->TargetNameOffset +
3154 reparse_buf->TargetNameLen) > end_of_smb) {
3155 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3156 rc = -EIO;
3157 goto qreparse_out;
3160 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3161 cifs_from_ucs2(symlinkinfo, (__le16 *)
3162 (reparse_buf->LinkNamesBuf +
3163 reparse_buf->TargetNameOffset),
3164 buflen,
3165 reparse_buf->TargetNameLen,
3166 nls_codepage, 0);
3167 } else { /* ASCII names */
3168 strncpy(symlinkinfo,
3169 reparse_buf->LinkNamesBuf +
3170 reparse_buf->TargetNameOffset,
3171 min_t(const int, buflen,
3172 reparse_buf->TargetNameLen));
3174 } else {
3175 rc = -EIO;
3176 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3178 symlinkinfo[buflen] = 0; /* just in case so the caller
3179 does not go off the end of the buffer */
3180 cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
3183 qreparse_out:
3184 cifs_buf_release(pSMB);
3186 /* Note: On -EAGAIN error only caller can retry on handle based calls
3187 since file handle passed in no longer valid */
3189 return rc;
3191 #endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
3193 #ifdef CONFIG_CIFS_POSIX
3195 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
3196 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3197 struct cifs_posix_ace *cifs_ace)
3199 /* u8 cifs fields do not need le conversion */
3200 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3201 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3202 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
3204 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3205 ace->e_perm, ace->e_tag, ace->e_id);
3208 return;
3211 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
3212 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3213 const int acl_type, const int size_of_data_area)
3215 int size = 0;
3216 int i;
3217 __u16 count;
3218 struct cifs_posix_ace *pACE;
3219 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3220 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
3222 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3223 return -EOPNOTSUPP;
3225 if (acl_type & ACL_TYPE_ACCESS) {
3226 count = le16_to_cpu(cifs_acl->access_entry_count);
3227 pACE = &cifs_acl->ace_array[0];
3228 size = sizeof(struct cifs_posix_acl);
3229 size += sizeof(struct cifs_posix_ace) * count;
3230 /* check if we would go beyond end of SMB */
3231 if (size_of_data_area < size) {
3232 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3233 size_of_data_area, size);
3234 return -EINVAL;
3236 } else if (acl_type & ACL_TYPE_DEFAULT) {
3237 count = le16_to_cpu(cifs_acl->access_entry_count);
3238 size = sizeof(struct cifs_posix_acl);
3239 size += sizeof(struct cifs_posix_ace) * count;
3240 /* skip past access ACEs to get to default ACEs */
3241 pACE = &cifs_acl->ace_array[count];
3242 count = le16_to_cpu(cifs_acl->default_entry_count);
3243 size += sizeof(struct cifs_posix_ace) * count;
3244 /* check if we would go beyond end of SMB */
3245 if (size_of_data_area < size)
3246 return -EINVAL;
3247 } else {
3248 /* illegal type */
3249 return -EINVAL;
3252 size = posix_acl_xattr_size(count);
3253 if ((buflen == 0) || (local_acl == NULL)) {
3254 /* used to query ACL EA size */
3255 } else if (size > buflen) {
3256 return -ERANGE;
3257 } else /* buffer big enough */ {
3258 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
3259 for (i = 0; i < count ; i++) {
3260 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3261 pACE++;
3264 return size;
3267 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3268 const posix_acl_xattr_entry *local_ace)
3270 __u16 rc = 0; /* 0 = ACL converted ok */
3272 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3273 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
3274 /* BB is there a better way to handle the large uid? */
3275 if (local_ace->e_id == cpu_to_le32(-1)) {
3276 /* Probably no need to le convert -1 on any arch but can not hurt */
3277 cifs_ace->cifs_uid = cpu_to_le64(-1);
3278 } else
3279 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
3281 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3282 ace->e_perm, ace->e_tag, ace->e_id);
3284 return rc;
3287 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
3288 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3289 const int buflen, const int acl_type)
3291 __u16 rc = 0;
3292 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3293 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
3294 int count;
3295 int i;
3297 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
3298 return 0;
3300 count = posix_acl_xattr_count((size_t)buflen);
3301 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3302 count, buflen, le32_to_cpu(local_acl->a_version));
3303 if (le32_to_cpu(local_acl->a_version) != 2) {
3304 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3305 le32_to_cpu(local_acl->a_version));
3306 return 0;
3308 cifs_acl->version = cpu_to_le16(1);
3309 if (acl_type == ACL_TYPE_ACCESS)
3310 cifs_acl->access_entry_count = cpu_to_le16(count);
3311 else if (acl_type == ACL_TYPE_DEFAULT)
3312 cifs_acl->default_entry_count = cpu_to_le16(count);
3313 else {
3314 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
3315 return 0;
3317 for (i = 0; i < count; i++) {
3318 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3319 &local_acl->a_entries[i]);
3320 if (rc != 0) {
3321 /* ACE not converted */
3322 break;
3325 if (rc == 0) {
3326 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3327 rc += sizeof(struct cifs_posix_acl);
3328 /* BB add check to make sure ACL does not overflow SMB */
3330 return rc;
3334 CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
3335 const unsigned char *searchName,
3336 char *acl_inf, const int buflen, const int acl_type,
3337 const struct nls_table *nls_codepage, int remap)
3339 /* SMB_QUERY_POSIX_ACL */
3340 TRANSACTION2_QPI_REQ *pSMB = NULL;
3341 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3342 int rc = 0;
3343 int bytes_returned;
3344 int name_len;
3345 __u16 params, byte_count;
3347 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
3349 queryAclRetry:
3350 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3351 (void **) &pSMBr);
3352 if (rc)
3353 return rc;
3355 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3356 name_len =
3357 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3358 searchName, PATH_MAX, nls_codepage,
3359 remap);
3360 name_len++; /* trailing null */
3361 name_len *= 2;
3362 pSMB->FileName[name_len] = 0;
3363 pSMB->FileName[name_len+1] = 0;
3364 } else { /* BB improve the check for buffer overruns BB */
3365 name_len = strnlen(searchName, PATH_MAX);
3366 name_len++; /* trailing null */
3367 strncpy(pSMB->FileName, searchName, name_len);
3370 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3371 pSMB->TotalDataCount = 0;
3372 pSMB->MaxParameterCount = cpu_to_le16(2);
3373 /* BB find exact max data count below from sess structure BB */
3374 pSMB->MaxDataCount = cpu_to_le16(4000);
3375 pSMB->MaxSetupCount = 0;
3376 pSMB->Reserved = 0;
3377 pSMB->Flags = 0;
3378 pSMB->Timeout = 0;
3379 pSMB->Reserved2 = 0;
3380 pSMB->ParameterOffset = cpu_to_le16(
3381 offsetof(struct smb_com_transaction2_qpi_req,
3382 InformationLevel) - 4);
3383 pSMB->DataCount = 0;
3384 pSMB->DataOffset = 0;
3385 pSMB->SetupCount = 1;
3386 pSMB->Reserved3 = 0;
3387 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3388 byte_count = params + 1 /* pad */ ;
3389 pSMB->TotalParameterCount = cpu_to_le16(params);
3390 pSMB->ParameterCount = pSMB->TotalParameterCount;
3391 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3392 pSMB->Reserved4 = 0;
3393 inc_rfc1001_len(pSMB, byte_count);
3394 pSMB->ByteCount = cpu_to_le16(byte_count);
3396 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3397 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3398 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
3399 if (rc) {
3400 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
3401 } else {
3402 /* decode response */
3404 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3405 /* BB also check enough total bytes returned */
3406 if (rc || get_bcc(&pSMBr->hdr) < 2)
3407 rc = -EIO; /* bad smb */
3408 else {
3409 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3410 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3411 rc = cifs_copy_posix_acl(acl_inf,
3412 (char *)&pSMBr->hdr.Protocol+data_offset,
3413 buflen, acl_type, count);
3416 cifs_buf_release(pSMB);
3417 if (rc == -EAGAIN)
3418 goto queryAclRetry;
3419 return rc;
3423 CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
3424 const unsigned char *fileName,
3425 const char *local_acl, const int buflen,
3426 const int acl_type,
3427 const struct nls_table *nls_codepage, int remap)
3429 struct smb_com_transaction2_spi_req *pSMB = NULL;
3430 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3431 char *parm_data;
3432 int name_len;
3433 int rc = 0;
3434 int bytes_returned = 0;
3435 __u16 params, byte_count, data_count, param_offset, offset;
3437 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
3438 setAclRetry:
3439 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3440 (void **) &pSMBr);
3441 if (rc)
3442 return rc;
3443 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3444 name_len =
3445 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3446 PATH_MAX, nls_codepage, remap);
3447 name_len++; /* trailing null */
3448 name_len *= 2;
3449 } else { /* BB improve the check for buffer overruns BB */
3450 name_len = strnlen(fileName, PATH_MAX);
3451 name_len++; /* trailing null */
3452 strncpy(pSMB->FileName, fileName, name_len);
3454 params = 6 + name_len;
3455 pSMB->MaxParameterCount = cpu_to_le16(2);
3456 /* BB find max SMB size from sess */
3457 pSMB->MaxDataCount = cpu_to_le16(1000);
3458 pSMB->MaxSetupCount = 0;
3459 pSMB->Reserved = 0;
3460 pSMB->Flags = 0;
3461 pSMB->Timeout = 0;
3462 pSMB->Reserved2 = 0;
3463 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3464 InformationLevel) - 4;
3465 offset = param_offset + params;
3466 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3467 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3469 /* convert to on the wire format for POSIX ACL */
3470 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
3472 if (data_count == 0) {
3473 rc = -EOPNOTSUPP;
3474 goto setACLerrorExit;
3476 pSMB->DataOffset = cpu_to_le16(offset);
3477 pSMB->SetupCount = 1;
3478 pSMB->Reserved3 = 0;
3479 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3480 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3481 byte_count = 3 /* pad */ + params + data_count;
3482 pSMB->DataCount = cpu_to_le16(data_count);
3483 pSMB->TotalDataCount = pSMB->DataCount;
3484 pSMB->ParameterCount = cpu_to_le16(params);
3485 pSMB->TotalParameterCount = pSMB->ParameterCount;
3486 pSMB->Reserved4 = 0;
3487 inc_rfc1001_len(pSMB, byte_count);
3488 pSMB->ByteCount = cpu_to_le16(byte_count);
3489 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3490 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3491 if (rc)
3492 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
3494 setACLerrorExit:
3495 cifs_buf_release(pSMB);
3496 if (rc == -EAGAIN)
3497 goto setAclRetry;
3498 return rc;
3501 /* BB fix tabs in this function FIXME BB */
3503 CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
3504 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
3506 int rc = 0;
3507 struct smb_t2_qfi_req *pSMB = NULL;
3508 struct smb_t2_qfi_rsp *pSMBr = NULL;
3509 int bytes_returned;
3510 __u16 params, byte_count;
3512 cifs_dbg(FYI, "In GetExtAttr\n");
3513 if (tcon == NULL)
3514 return -ENODEV;
3516 GetExtAttrRetry:
3517 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3518 (void **) &pSMBr);
3519 if (rc)
3520 return rc;
3522 params = 2 /* level */ + 2 /* fid */;
3523 pSMB->t2.TotalDataCount = 0;
3524 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3525 /* BB find exact max data count below from sess structure BB */
3526 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3527 pSMB->t2.MaxSetupCount = 0;
3528 pSMB->t2.Reserved = 0;
3529 pSMB->t2.Flags = 0;
3530 pSMB->t2.Timeout = 0;
3531 pSMB->t2.Reserved2 = 0;
3532 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3533 Fid) - 4);
3534 pSMB->t2.DataCount = 0;
3535 pSMB->t2.DataOffset = 0;
3536 pSMB->t2.SetupCount = 1;
3537 pSMB->t2.Reserved3 = 0;
3538 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3539 byte_count = params + 1 /* pad */ ;
3540 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3541 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3542 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3543 pSMB->Pad = 0;
3544 pSMB->Fid = netfid;
3545 inc_rfc1001_len(pSMB, byte_count);
3546 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3548 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3549 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3550 if (rc) {
3551 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
3552 } else {
3553 /* decode response */
3554 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3555 /* BB also check enough total bytes returned */
3556 if (rc || get_bcc(&pSMBr->hdr) < 2)
3557 /* If rc should we check for EOPNOSUPP and
3558 disable the srvino flag? or in caller? */
3559 rc = -EIO; /* bad smb */
3560 else {
3561 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3562 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3563 struct file_chattr_info *pfinfo;
3564 /* BB Do we need a cast or hash here ? */
3565 if (count != 16) {
3566 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
3567 rc = -EIO;
3568 goto GetExtAttrOut;
3570 pfinfo = (struct file_chattr_info *)
3571 (data_offset + (char *) &pSMBr->hdr.Protocol);
3572 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3573 *pMask = le64_to_cpu(pfinfo->mask);
3576 GetExtAttrOut:
3577 cifs_buf_release(pSMB);
3578 if (rc == -EAGAIN)
3579 goto GetExtAttrRetry;
3580 return rc;
3583 #endif /* CONFIG_POSIX */
3585 #ifdef CONFIG_CIFS_ACL
3587 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3588 * all NT TRANSACTS that we init here have total parm and data under about 400
3589 * bytes (to fit in small cifs buffer size), which is the case so far, it
3590 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3591 * returned setup area) and MaxParameterCount (returned parms size) must be set
3592 * by caller
3594 static int
3595 smb_init_nttransact(const __u16 sub_command, const int setup_count,
3596 const int parm_len, struct cifs_tcon *tcon,
3597 void **ret_buf)
3599 int rc;
3600 __u32 temp_offset;
3601 struct smb_com_ntransact_req *pSMB;
3603 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3604 (void **)&pSMB);
3605 if (rc)
3606 return rc;
3607 *ret_buf = (void *)pSMB;
3608 pSMB->Reserved = 0;
3609 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3610 pSMB->TotalDataCount = 0;
3611 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
3612 pSMB->ParameterCount = pSMB->TotalParameterCount;
3613 pSMB->DataCount = pSMB->TotalDataCount;
3614 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3615 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3616 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3617 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3618 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3619 pSMB->SubCommand = cpu_to_le16(sub_command);
3620 return 0;
3623 static int
3624 validate_ntransact(char *buf, char **ppparm, char **ppdata,
3625 __u32 *pparmlen, __u32 *pdatalen)
3627 char *end_of_smb;
3628 __u32 data_count, data_offset, parm_count, parm_offset;
3629 struct smb_com_ntransact_rsp *pSMBr;
3630 u16 bcc;
3632 *pdatalen = 0;
3633 *pparmlen = 0;
3635 if (buf == NULL)
3636 return -EINVAL;
3638 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3640 bcc = get_bcc(&pSMBr->hdr);
3641 end_of_smb = 2 /* sizeof byte count */ + bcc +
3642 (char *)&pSMBr->ByteCount;
3644 data_offset = le32_to_cpu(pSMBr->DataOffset);
3645 data_count = le32_to_cpu(pSMBr->DataCount);
3646 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3647 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3649 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3650 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3652 /* should we also check that parm and data areas do not overlap? */
3653 if (*ppparm > end_of_smb) {
3654 cifs_dbg(FYI, "parms start after end of smb\n");
3655 return -EINVAL;
3656 } else if (parm_count + *ppparm > end_of_smb) {
3657 cifs_dbg(FYI, "parm end after end of smb\n");
3658 return -EINVAL;
3659 } else if (*ppdata > end_of_smb) {
3660 cifs_dbg(FYI, "data starts after end of smb\n");
3661 return -EINVAL;
3662 } else if (data_count + *ppdata > end_of_smb) {
3663 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3664 *ppdata, data_count, (data_count + *ppdata),
3665 end_of_smb, pSMBr);
3666 return -EINVAL;
3667 } else if (parm_count + data_count > bcc) {
3668 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
3669 return -EINVAL;
3671 *pdatalen = data_count;
3672 *pparmlen = parm_count;
3673 return 0;
3676 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3678 CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
3679 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3681 int rc = 0;
3682 int buf_type = 0;
3683 QUERY_SEC_DESC_REQ *pSMB;
3684 struct kvec iov[1];
3686 cifs_dbg(FYI, "GetCifsACL\n");
3688 *pbuflen = 0;
3689 *acl_inf = NULL;
3691 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3692 8 /* parm len */, tcon, (void **) &pSMB);
3693 if (rc)
3694 return rc;
3696 pSMB->MaxParameterCount = cpu_to_le32(4);
3697 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3698 pSMB->MaxSetupCount = 0;
3699 pSMB->Fid = fid; /* file handle always le */
3700 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3701 CIFS_ACL_DACL);
3702 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3703 inc_rfc1001_len(pSMB, 11);
3704 iov[0].iov_base = (char *)pSMB;
3705 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
3707 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3709 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
3710 if (rc) {
3711 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
3712 } else { /* decode response */
3713 __le32 *parm;
3714 __u32 parm_len;
3715 __u32 acl_len;
3716 struct smb_com_ntransact_rsp *pSMBr;
3717 char *pdata;
3719 /* validate_nttransact */
3720 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3721 &pdata, &parm_len, pbuflen);
3722 if (rc)
3723 goto qsec_out;
3724 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3726 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3727 pSMBr, parm, *acl_inf);
3729 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3730 rc = -EIO; /* bad smb */
3731 *pbuflen = 0;
3732 goto qsec_out;
3735 /* BB check that data area is minimum length and as big as acl_len */
3737 acl_len = le32_to_cpu(*parm);
3738 if (acl_len != *pbuflen) {
3739 cifs_dbg(VFS, "acl length %d does not match %d\n",
3740 acl_len, *pbuflen);
3741 if (*pbuflen > acl_len)
3742 *pbuflen = acl_len;
3745 /* check if buffer is big enough for the acl
3746 header followed by the smallest SID */
3747 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3748 (*pbuflen >= 64 * 1024)) {
3749 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
3750 rc = -EINVAL;
3751 *pbuflen = 0;
3752 } else {
3753 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
3754 if (*acl_inf == NULL) {
3755 *pbuflen = 0;
3756 rc = -ENOMEM;
3760 qsec_out:
3761 if (buf_type == CIFS_SMALL_BUFFER)
3762 cifs_small_buf_release(iov[0].iov_base);
3763 else if (buf_type == CIFS_LARGE_BUFFER)
3764 cifs_buf_release(iov[0].iov_base);
3765 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3766 return rc;
3770 CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
3771 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
3773 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3774 int rc = 0;
3775 int bytes_returned = 0;
3776 SET_SEC_DESC_REQ *pSMB = NULL;
3777 void *pSMBr;
3779 setCifsAclRetry:
3780 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
3781 if (rc)
3782 return rc;
3784 pSMB->MaxSetupCount = 0;
3785 pSMB->Reserved = 0;
3787 param_count = 8;
3788 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3789 data_count = acllen;
3790 data_offset = param_offset + param_count;
3791 byte_count = 3 /* pad */ + param_count;
3793 pSMB->DataCount = cpu_to_le32(data_count);
3794 pSMB->TotalDataCount = pSMB->DataCount;
3795 pSMB->MaxParameterCount = cpu_to_le32(4);
3796 pSMB->MaxDataCount = cpu_to_le32(16384);
3797 pSMB->ParameterCount = cpu_to_le32(param_count);
3798 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3799 pSMB->TotalParameterCount = pSMB->ParameterCount;
3800 pSMB->DataOffset = cpu_to_le32(data_offset);
3801 pSMB->SetupCount = 0;
3802 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3803 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3805 pSMB->Fid = fid; /* file handle always le */
3806 pSMB->Reserved2 = 0;
3807 pSMB->AclFlags = cpu_to_le32(aclflag);
3809 if (pntsd && acllen) {
3810 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3811 data_offset, pntsd, acllen);
3812 inc_rfc1001_len(pSMB, byte_count + data_count);
3813 } else
3814 inc_rfc1001_len(pSMB, byte_count);
3816 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3817 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3819 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3820 bytes_returned, rc);
3821 if (rc)
3822 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
3823 cifs_buf_release(pSMB);
3825 if (rc == -EAGAIN)
3826 goto setCifsAclRetry;
3828 return (rc);
3831 #endif /* CONFIG_CIFS_ACL */
3833 /* Legacy Query Path Information call for lookup to old servers such
3834 as Win9x/WinME */
3836 SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3837 const char *search_name, FILE_ALL_INFO *data,
3838 const struct nls_table *nls_codepage, int remap)
3840 QUERY_INFORMATION_REQ *pSMB;
3841 QUERY_INFORMATION_RSP *pSMBr;
3842 int rc = 0;
3843 int bytes_returned;
3844 int name_len;
3846 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
3847 QInfRetry:
3848 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3849 (void **) &pSMBr);
3850 if (rc)
3851 return rc;
3853 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3854 name_len =
3855 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3856 search_name, PATH_MAX, nls_codepage,
3857 remap);
3858 name_len++; /* trailing null */
3859 name_len *= 2;
3860 } else {
3861 name_len = strnlen(search_name, PATH_MAX);
3862 name_len++; /* trailing null */
3863 strncpy(pSMB->FileName, search_name, name_len);
3865 pSMB->BufferFormat = 0x04;
3866 name_len++; /* account for buffer type byte */
3867 inc_rfc1001_len(pSMB, (__u16)name_len);
3868 pSMB->ByteCount = cpu_to_le16(name_len);
3870 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3871 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3872 if (rc) {
3873 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
3874 } else if (data) {
3875 struct timespec ts;
3876 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3878 /* decode response */
3879 /* BB FIXME - add time zone adjustment BB */
3880 memset(data, 0, sizeof(FILE_ALL_INFO));
3881 ts.tv_nsec = 0;
3882 ts.tv_sec = time;
3883 /* decode time fields */
3884 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3885 data->LastWriteTime = data->ChangeTime;
3886 data->LastAccessTime = 0;
3887 data->AllocationSize =
3888 cpu_to_le64(le32_to_cpu(pSMBr->size));
3889 data->EndOfFile = data->AllocationSize;
3890 data->Attributes =
3891 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3892 } else
3893 rc = -EIO; /* bad buffer passed in */
3895 cifs_buf_release(pSMB);
3897 if (rc == -EAGAIN)
3898 goto QInfRetry;
3900 return rc;
3904 CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
3905 u16 netfid, FILE_ALL_INFO *pFindData)
3907 struct smb_t2_qfi_req *pSMB = NULL;
3908 struct smb_t2_qfi_rsp *pSMBr = NULL;
3909 int rc = 0;
3910 int bytes_returned;
3911 __u16 params, byte_count;
3913 QFileInfoRetry:
3914 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3915 (void **) &pSMBr);
3916 if (rc)
3917 return rc;
3919 params = 2 /* level */ + 2 /* fid */;
3920 pSMB->t2.TotalDataCount = 0;
3921 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3922 /* BB find exact max data count below from sess structure BB */
3923 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3924 pSMB->t2.MaxSetupCount = 0;
3925 pSMB->t2.Reserved = 0;
3926 pSMB->t2.Flags = 0;
3927 pSMB->t2.Timeout = 0;
3928 pSMB->t2.Reserved2 = 0;
3929 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3930 Fid) - 4);
3931 pSMB->t2.DataCount = 0;
3932 pSMB->t2.DataOffset = 0;
3933 pSMB->t2.SetupCount = 1;
3934 pSMB->t2.Reserved3 = 0;
3935 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3936 byte_count = params + 1 /* pad */ ;
3937 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3938 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3939 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3940 pSMB->Pad = 0;
3941 pSMB->Fid = netfid;
3942 inc_rfc1001_len(pSMB, byte_count);
3944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3946 if (rc) {
3947 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
3948 } else { /* decode response */
3949 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3951 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3952 rc = -EIO;
3953 else if (get_bcc(&pSMBr->hdr) < 40)
3954 rc = -EIO; /* bad smb */
3955 else if (pFindData) {
3956 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3957 memcpy((char *) pFindData,
3958 (char *) &pSMBr->hdr.Protocol +
3959 data_offset, sizeof(FILE_ALL_INFO));
3960 } else
3961 rc = -ENOMEM;
3963 cifs_buf_release(pSMB);
3964 if (rc == -EAGAIN)
3965 goto QFileInfoRetry;
3967 return rc;
3971 CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
3972 const char *search_name, FILE_ALL_INFO *data,
3973 int legacy /* old style infolevel */,
3974 const struct nls_table *nls_codepage, int remap)
3976 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3977 TRANSACTION2_QPI_REQ *pSMB = NULL;
3978 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3979 int rc = 0;
3980 int bytes_returned;
3981 int name_len;
3982 __u16 params, byte_count;
3984 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
3985 QPathInfoRetry:
3986 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3987 (void **) &pSMBr);
3988 if (rc)
3989 return rc;
3991 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3992 name_len =
3993 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
3994 PATH_MAX, nls_codepage, remap);
3995 name_len++; /* trailing null */
3996 name_len *= 2;
3997 } else { /* BB improve the check for buffer overruns BB */
3998 name_len = strnlen(search_name, PATH_MAX);
3999 name_len++; /* trailing null */
4000 strncpy(pSMB->FileName, search_name, name_len);
4003 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
4004 pSMB->TotalDataCount = 0;
4005 pSMB->MaxParameterCount = cpu_to_le16(2);
4006 /* BB find exact max SMB PDU from sess structure BB */
4007 pSMB->MaxDataCount = cpu_to_le16(4000);
4008 pSMB->MaxSetupCount = 0;
4009 pSMB->Reserved = 0;
4010 pSMB->Flags = 0;
4011 pSMB->Timeout = 0;
4012 pSMB->Reserved2 = 0;
4013 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4014 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4015 pSMB->DataCount = 0;
4016 pSMB->DataOffset = 0;
4017 pSMB->SetupCount = 1;
4018 pSMB->Reserved3 = 0;
4019 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4020 byte_count = params + 1 /* pad */ ;
4021 pSMB->TotalParameterCount = cpu_to_le16(params);
4022 pSMB->ParameterCount = pSMB->TotalParameterCount;
4023 if (legacy)
4024 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4025 else
4026 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4027 pSMB->Reserved4 = 0;
4028 inc_rfc1001_len(pSMB, byte_count);
4029 pSMB->ByteCount = cpu_to_le16(byte_count);
4031 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4032 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4033 if (rc) {
4034 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
4035 } else { /* decode response */
4036 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4038 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4039 rc = -EIO;
4040 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
4041 rc = -EIO; /* bad smb */
4042 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
4043 rc = -EIO; /* 24 or 26 expected but we do not read
4044 last field */
4045 else if (data) {
4046 int size;
4047 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4050 * On legacy responses we do not read the last field,
4051 * EAsize, fortunately since it varies by subdialect and
4052 * also note it differs on Set vs Get, ie two bytes or 4
4053 * bytes depending but we don't care here.
4055 if (legacy)
4056 size = sizeof(FILE_INFO_STANDARD);
4057 else
4058 size = sizeof(FILE_ALL_INFO);
4059 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
4060 data_offset, size);
4061 } else
4062 rc = -ENOMEM;
4064 cifs_buf_release(pSMB);
4065 if (rc == -EAGAIN)
4066 goto QPathInfoRetry;
4068 return rc;
4072 CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
4073 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4075 struct smb_t2_qfi_req *pSMB = NULL;
4076 struct smb_t2_qfi_rsp *pSMBr = NULL;
4077 int rc = 0;
4078 int bytes_returned;
4079 __u16 params, byte_count;
4081 UnixQFileInfoRetry:
4082 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4083 (void **) &pSMBr);
4084 if (rc)
4085 return rc;
4087 params = 2 /* level */ + 2 /* fid */;
4088 pSMB->t2.TotalDataCount = 0;
4089 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4090 /* BB find exact max data count below from sess structure BB */
4091 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4092 pSMB->t2.MaxSetupCount = 0;
4093 pSMB->t2.Reserved = 0;
4094 pSMB->t2.Flags = 0;
4095 pSMB->t2.Timeout = 0;
4096 pSMB->t2.Reserved2 = 0;
4097 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4098 Fid) - 4);
4099 pSMB->t2.DataCount = 0;
4100 pSMB->t2.DataOffset = 0;
4101 pSMB->t2.SetupCount = 1;
4102 pSMB->t2.Reserved3 = 0;
4103 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4104 byte_count = params + 1 /* pad */ ;
4105 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4106 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4107 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4108 pSMB->Pad = 0;
4109 pSMB->Fid = netfid;
4110 inc_rfc1001_len(pSMB, byte_count);
4112 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4113 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4114 if (rc) {
4115 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
4116 } else { /* decode response */
4117 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4119 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4120 cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
4121 rc = -EIO; /* bad smb */
4122 } else {
4123 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4124 memcpy((char *) pFindData,
4125 (char *) &pSMBr->hdr.Protocol +
4126 data_offset,
4127 sizeof(FILE_UNIX_BASIC_INFO));
4131 cifs_buf_release(pSMB);
4132 if (rc == -EAGAIN)
4133 goto UnixQFileInfoRetry;
4135 return rc;
4139 CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
4140 const unsigned char *searchName,
4141 FILE_UNIX_BASIC_INFO *pFindData,
4142 const struct nls_table *nls_codepage, int remap)
4144 /* SMB_QUERY_FILE_UNIX_BASIC */
4145 TRANSACTION2_QPI_REQ *pSMB = NULL;
4146 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4147 int rc = 0;
4148 int bytes_returned = 0;
4149 int name_len;
4150 __u16 params, byte_count;
4152 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
4153 UnixQPathInfoRetry:
4154 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4155 (void **) &pSMBr);
4156 if (rc)
4157 return rc;
4159 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4160 name_len =
4161 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4162 PATH_MAX, nls_codepage, remap);
4163 name_len++; /* trailing null */
4164 name_len *= 2;
4165 } else { /* BB improve the check for buffer overruns BB */
4166 name_len = strnlen(searchName, PATH_MAX);
4167 name_len++; /* trailing null */
4168 strncpy(pSMB->FileName, searchName, name_len);
4171 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
4172 pSMB->TotalDataCount = 0;
4173 pSMB->MaxParameterCount = cpu_to_le16(2);
4174 /* BB find exact max SMB PDU from sess structure BB */
4175 pSMB->MaxDataCount = cpu_to_le16(4000);
4176 pSMB->MaxSetupCount = 0;
4177 pSMB->Reserved = 0;
4178 pSMB->Flags = 0;
4179 pSMB->Timeout = 0;
4180 pSMB->Reserved2 = 0;
4181 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4182 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4183 pSMB->DataCount = 0;
4184 pSMB->DataOffset = 0;
4185 pSMB->SetupCount = 1;
4186 pSMB->Reserved3 = 0;
4187 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4188 byte_count = params + 1 /* pad */ ;
4189 pSMB->TotalParameterCount = cpu_to_le16(params);
4190 pSMB->ParameterCount = pSMB->TotalParameterCount;
4191 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4192 pSMB->Reserved4 = 0;
4193 inc_rfc1001_len(pSMB, byte_count);
4194 pSMB->ByteCount = cpu_to_le16(byte_count);
4196 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4197 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4198 if (rc) {
4199 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
4200 } else { /* decode response */
4201 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4203 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4204 cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
4205 rc = -EIO; /* bad smb */
4206 } else {
4207 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4208 memcpy((char *) pFindData,
4209 (char *) &pSMBr->hdr.Protocol +
4210 data_offset,
4211 sizeof(FILE_UNIX_BASIC_INFO));
4214 cifs_buf_release(pSMB);
4215 if (rc == -EAGAIN)
4216 goto UnixQPathInfoRetry;
4218 return rc;
4221 /* xid, tcon, searchName and codepage are input parms, rest are returned */
4223 CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
4224 const char *searchName, struct cifs_sb_info *cifs_sb,
4225 __u16 *pnetfid, __u16 search_flags,
4226 struct cifs_search_info *psrch_inf, bool msearch)
4228 /* level 257 SMB_ */
4229 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4230 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
4231 T2_FFIRST_RSP_PARMS *parms;
4232 int rc = 0;
4233 int bytes_returned = 0;
4234 int name_len, remap;
4235 __u16 params, byte_count;
4236 struct nls_table *nls_codepage;
4238 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
4240 findFirstRetry:
4241 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4242 (void **) &pSMBr);
4243 if (rc)
4244 return rc;
4246 nls_codepage = cifs_sb->local_nls;
4247 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4249 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4250 name_len =
4251 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4252 PATH_MAX, nls_codepage, remap);
4253 /* We can not add the asterik earlier in case
4254 it got remapped to 0xF03A as if it were part of the
4255 directory name instead of a wildcard */
4256 name_len *= 2;
4257 if (msearch) {
4258 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4259 pSMB->FileName[name_len+1] = 0;
4260 pSMB->FileName[name_len+2] = '*';
4261 pSMB->FileName[name_len+3] = 0;
4262 name_len += 4; /* now the trailing null */
4263 /* null terminate just in case */
4264 pSMB->FileName[name_len] = 0;
4265 pSMB->FileName[name_len+1] = 0;
4266 name_len += 2;
4268 } else { /* BB add check for overrun of SMB buf BB */
4269 name_len = strnlen(searchName, PATH_MAX);
4270 /* BB fix here and in unicode clause above ie
4271 if (name_len > buffersize-header)
4272 free buffer exit; BB */
4273 strncpy(pSMB->FileName, searchName, name_len);
4274 if (msearch) {
4275 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4276 pSMB->FileName[name_len+1] = '*';
4277 pSMB->FileName[name_len+2] = 0;
4278 name_len += 3;
4282 params = 12 + name_len /* includes null */ ;
4283 pSMB->TotalDataCount = 0; /* no EAs */
4284 pSMB->MaxParameterCount = cpu_to_le16(10);
4285 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
4286 pSMB->MaxSetupCount = 0;
4287 pSMB->Reserved = 0;
4288 pSMB->Flags = 0;
4289 pSMB->Timeout = 0;
4290 pSMB->Reserved2 = 0;
4291 byte_count = params + 1 /* pad */ ;
4292 pSMB->TotalParameterCount = cpu_to_le16(params);
4293 pSMB->ParameterCount = pSMB->TotalParameterCount;
4294 pSMB->ParameterOffset = cpu_to_le16(
4295 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4296 - 4);
4297 pSMB->DataCount = 0;
4298 pSMB->DataOffset = 0;
4299 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4300 pSMB->Reserved3 = 0;
4301 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4302 pSMB->SearchAttributes =
4303 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4304 ATTR_DIRECTORY);
4305 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4306 pSMB->SearchFlags = cpu_to_le16(search_flags);
4307 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4309 /* BB what should we set StorageType to? Does it matter? BB */
4310 pSMB->SearchStorageType = 0;
4311 inc_rfc1001_len(pSMB, byte_count);
4312 pSMB->ByteCount = cpu_to_le16(byte_count);
4314 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4315 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4316 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
4318 if (rc) {/* BB add logic to retry regular search if Unix search
4319 rejected unexpectedly by server */
4320 /* BB Add code to handle unsupported level rc */
4321 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
4323 cifs_buf_release(pSMB);
4325 /* BB eventually could optimize out free and realloc of buf */
4326 /* for this case */
4327 if (rc == -EAGAIN)
4328 goto findFirstRetry;
4329 } else { /* decode response */
4330 /* BB remember to free buffer if error BB */
4331 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4332 if (rc == 0) {
4333 unsigned int lnoff;
4335 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4336 psrch_inf->unicode = true;
4337 else
4338 psrch_inf->unicode = false;
4340 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
4341 psrch_inf->smallBuf = 0;
4342 psrch_inf->srch_entries_start =
4343 (char *) &pSMBr->hdr.Protocol +
4344 le16_to_cpu(pSMBr->t2.DataOffset);
4345 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4346 le16_to_cpu(pSMBr->t2.ParameterOffset));
4348 if (parms->EndofSearch)
4349 psrch_inf->endOfSearch = true;
4350 else
4351 psrch_inf->endOfSearch = false;
4353 psrch_inf->entries_in_buffer =
4354 le16_to_cpu(parms->SearchCount);
4355 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
4356 psrch_inf->entries_in_buffer;
4357 lnoff = le16_to_cpu(parms->LastNameOffset);
4358 if (CIFSMaxBufSize < lnoff) {
4359 cifs_dbg(VFS, "ignoring corrupt resume name\n");
4360 psrch_inf->last_entry = NULL;
4361 return rc;
4364 psrch_inf->last_entry = psrch_inf->srch_entries_start +
4365 lnoff;
4367 if (pnetfid)
4368 *pnetfid = parms->SearchHandle;
4369 } else {
4370 cifs_buf_release(pSMB);
4374 return rc;
4377 int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4378 __u16 searchHandle, __u16 search_flags,
4379 struct cifs_search_info *psrch_inf)
4381 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4382 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
4383 T2_FNEXT_RSP_PARMS *parms;
4384 char *response_data;
4385 int rc = 0;
4386 int bytes_returned;
4387 unsigned int name_len;
4388 __u16 params, byte_count;
4390 cifs_dbg(FYI, "In FindNext\n");
4392 if (psrch_inf->endOfSearch)
4393 return -ENOENT;
4395 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4396 (void **) &pSMBr);
4397 if (rc)
4398 return rc;
4400 params = 14; /* includes 2 bytes of null string, converted to LE below*/
4401 byte_count = 0;
4402 pSMB->TotalDataCount = 0; /* no EAs */
4403 pSMB->MaxParameterCount = cpu_to_le16(8);
4404 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
4405 pSMB->MaxSetupCount = 0;
4406 pSMB->Reserved = 0;
4407 pSMB->Flags = 0;
4408 pSMB->Timeout = 0;
4409 pSMB->Reserved2 = 0;
4410 pSMB->ParameterOffset = cpu_to_le16(
4411 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4412 pSMB->DataCount = 0;
4413 pSMB->DataOffset = 0;
4414 pSMB->SetupCount = 1;
4415 pSMB->Reserved3 = 0;
4416 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4417 pSMB->SearchHandle = searchHandle; /* always kept as le */
4418 pSMB->SearchCount =
4419 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
4420 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4421 pSMB->ResumeKey = psrch_inf->resume_key;
4422 pSMB->SearchFlags = cpu_to_le16(search_flags);
4424 name_len = psrch_inf->resume_name_len;
4425 params += name_len;
4426 if (name_len < PATH_MAX) {
4427 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4428 byte_count += name_len;
4429 /* 14 byte parm len above enough for 2 byte null terminator */
4430 pSMB->ResumeFileName[name_len] = 0;
4431 pSMB->ResumeFileName[name_len+1] = 0;
4432 } else {
4433 rc = -EINVAL;
4434 goto FNext2_err_exit;
4436 byte_count = params + 1 /* pad */ ;
4437 pSMB->TotalParameterCount = cpu_to_le16(params);
4438 pSMB->ParameterCount = pSMB->TotalParameterCount;
4439 inc_rfc1001_len(pSMB, byte_count);
4440 pSMB->ByteCount = cpu_to_le16(byte_count);
4442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4444 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
4445 if (rc) {
4446 if (rc == -EBADF) {
4447 psrch_inf->endOfSearch = true;
4448 cifs_buf_release(pSMB);
4449 rc = 0; /* search probably was closed at end of search*/
4450 } else
4451 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
4452 } else { /* decode response */
4453 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4455 if (rc == 0) {
4456 unsigned int lnoff;
4458 /* BB fixme add lock for file (srch_info) struct here */
4459 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4460 psrch_inf->unicode = true;
4461 else
4462 psrch_inf->unicode = false;
4463 response_data = (char *) &pSMBr->hdr.Protocol +
4464 le16_to_cpu(pSMBr->t2.ParameterOffset);
4465 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4466 response_data = (char *)&pSMBr->hdr.Protocol +
4467 le16_to_cpu(pSMBr->t2.DataOffset);
4468 if (psrch_inf->smallBuf)
4469 cifs_small_buf_release(
4470 psrch_inf->ntwrk_buf_start);
4471 else
4472 cifs_buf_release(psrch_inf->ntwrk_buf_start);
4473 psrch_inf->srch_entries_start = response_data;
4474 psrch_inf->ntwrk_buf_start = (char *)pSMB;
4475 psrch_inf->smallBuf = 0;
4476 if (parms->EndofSearch)
4477 psrch_inf->endOfSearch = true;
4478 else
4479 psrch_inf->endOfSearch = false;
4480 psrch_inf->entries_in_buffer =
4481 le16_to_cpu(parms->SearchCount);
4482 psrch_inf->index_of_last_entry +=
4483 psrch_inf->entries_in_buffer;
4484 lnoff = le16_to_cpu(parms->LastNameOffset);
4485 if (CIFSMaxBufSize < lnoff) {
4486 cifs_dbg(VFS, "ignoring corrupt resume name\n");
4487 psrch_inf->last_entry = NULL;
4488 return rc;
4489 } else
4490 psrch_inf->last_entry =
4491 psrch_inf->srch_entries_start + lnoff;
4493 /* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4494 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
4496 /* BB fixme add unlock here */
4501 /* BB On error, should we leave previous search buf (and count and
4502 last entry fields) intact or free the previous one? */
4504 /* Note: On -EAGAIN error only caller can retry on handle based calls
4505 since file handle passed in no longer valid */
4506 FNext2_err_exit:
4507 if (rc != 0)
4508 cifs_buf_release(pSMB);
4509 return rc;
4513 CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
4514 const __u16 searchHandle)
4516 int rc = 0;
4517 FINDCLOSE_REQ *pSMB = NULL;
4519 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
4520 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4522 /* no sense returning error if session restarted
4523 as file handle has been closed */
4524 if (rc == -EAGAIN)
4525 return 0;
4526 if (rc)
4527 return rc;
4529 pSMB->FileID = searchHandle;
4530 pSMB->ByteCount = 0;
4531 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
4532 if (rc)
4533 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
4535 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
4537 /* Since session is dead, search handle closed on server already */
4538 if (rc == -EAGAIN)
4539 rc = 0;
4541 return rc;
4545 CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
4546 const char *search_name, __u64 *inode_number,
4547 const struct nls_table *nls_codepage, int remap)
4549 int rc = 0;
4550 TRANSACTION2_QPI_REQ *pSMB = NULL;
4551 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4552 int name_len, bytes_returned;
4553 __u16 params, byte_count;
4555 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
4556 if (tcon == NULL)
4557 return -ENODEV;
4559 GetInodeNumberRetry:
4560 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4561 (void **) &pSMBr);
4562 if (rc)
4563 return rc;
4565 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4566 name_len =
4567 cifsConvertToUTF16((__le16 *) pSMB->FileName,
4568 search_name, PATH_MAX, nls_codepage,
4569 remap);
4570 name_len++; /* trailing null */
4571 name_len *= 2;
4572 } else { /* BB improve the check for buffer overruns BB */
4573 name_len = strnlen(search_name, PATH_MAX);
4574 name_len++; /* trailing null */
4575 strncpy(pSMB->FileName, search_name, name_len);
4578 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4579 pSMB->TotalDataCount = 0;
4580 pSMB->MaxParameterCount = cpu_to_le16(2);
4581 /* BB find exact max data count below from sess structure BB */
4582 pSMB->MaxDataCount = cpu_to_le16(4000);
4583 pSMB->MaxSetupCount = 0;
4584 pSMB->Reserved = 0;
4585 pSMB->Flags = 0;
4586 pSMB->Timeout = 0;
4587 pSMB->Reserved2 = 0;
4588 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4589 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4590 pSMB->DataCount = 0;
4591 pSMB->DataOffset = 0;
4592 pSMB->SetupCount = 1;
4593 pSMB->Reserved3 = 0;
4594 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4595 byte_count = params + 1 /* pad */ ;
4596 pSMB->TotalParameterCount = cpu_to_le16(params);
4597 pSMB->ParameterCount = pSMB->TotalParameterCount;
4598 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4599 pSMB->Reserved4 = 0;
4600 inc_rfc1001_len(pSMB, byte_count);
4601 pSMB->ByteCount = cpu_to_le16(byte_count);
4603 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4604 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4605 if (rc) {
4606 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
4607 } else {
4608 /* decode response */
4609 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4610 /* BB also check enough total bytes returned */
4611 if (rc || get_bcc(&pSMBr->hdr) < 2)
4612 /* If rc should we check for EOPNOSUPP and
4613 disable the srvino flag? or in caller? */
4614 rc = -EIO; /* bad smb */
4615 else {
4616 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4617 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
4618 struct file_internal_info *pfinfo;
4619 /* BB Do we need a cast or hash here ? */
4620 if (count < 8) {
4621 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
4622 rc = -EIO;
4623 goto GetInodeNumOut;
4625 pfinfo = (struct file_internal_info *)
4626 (data_offset + (char *) &pSMBr->hdr.Protocol);
4627 *inode_number = le64_to_cpu(pfinfo->UniqueId);
4630 GetInodeNumOut:
4631 cifs_buf_release(pSMB);
4632 if (rc == -EAGAIN)
4633 goto GetInodeNumberRetry;
4634 return rc;
4637 /* parses DFS refferal V3 structure
4638 * caller is responsible for freeing target_nodes
4639 * returns:
4640 * on success - 0
4641 * on failure - errno
4643 static int
4644 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
4645 unsigned int *num_of_nodes,
4646 struct dfs_info3_param **target_nodes,
4647 const struct nls_table *nls_codepage, int remap,
4648 const char *searchName)
4650 int i, rc = 0;
4651 char *data_end;
4652 bool is_unicode;
4653 struct dfs_referral_level_3 *ref;
4655 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4656 is_unicode = true;
4657 else
4658 is_unicode = false;
4659 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4661 if (*num_of_nodes < 1) {
4662 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4663 *num_of_nodes);
4664 rc = -EINVAL;
4665 goto parse_DFS_referrals_exit;
4668 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
4669 if (ref->VersionNumber != cpu_to_le16(3)) {
4670 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4671 le16_to_cpu(ref->VersionNumber));
4672 rc = -EINVAL;
4673 goto parse_DFS_referrals_exit;
4676 /* get the upper boundary of the resp buffer */
4677 data_end = (char *)(&(pSMBr->PathConsumed)) +
4678 le16_to_cpu(pSMBr->t2.DataCount);
4680 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4681 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
4683 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4684 GFP_KERNEL);
4685 if (*target_nodes == NULL) {
4686 rc = -ENOMEM;
4687 goto parse_DFS_referrals_exit;
4690 /* collect necessary data from referrals */
4691 for (i = 0; i < *num_of_nodes; i++) {
4692 char *temp;
4693 int max_len;
4694 struct dfs_info3_param *node = (*target_nodes)+i;
4696 node->flags = le32_to_cpu(pSMBr->DFSFlags);
4697 if (is_unicode) {
4698 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4699 GFP_KERNEL);
4700 if (tmp == NULL) {
4701 rc = -ENOMEM;
4702 goto parse_DFS_referrals_exit;
4704 cifsConvertToUTF16((__le16 *) tmp, searchName,
4705 PATH_MAX, nls_codepage, remap);
4706 node->path_consumed = cifs_utf16_bytes(tmp,
4707 le16_to_cpu(pSMBr->PathConsumed),
4708 nls_codepage);
4709 kfree(tmp);
4710 } else
4711 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4713 node->server_type = le16_to_cpu(ref->ServerType);
4714 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4716 /* copy DfsPath */
4717 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4718 max_len = data_end - temp;
4719 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4720 is_unicode, nls_codepage);
4721 if (!node->path_name) {
4722 rc = -ENOMEM;
4723 goto parse_DFS_referrals_exit;
4726 /* copy link target UNC */
4727 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4728 max_len = data_end - temp;
4729 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4730 is_unicode, nls_codepage);
4731 if (!node->node_name) {
4732 rc = -ENOMEM;
4733 goto parse_DFS_referrals_exit;
4736 ref++;
4739 parse_DFS_referrals_exit:
4740 if (rc) {
4741 free_dfs_info_array(*target_nodes, *num_of_nodes);
4742 *target_nodes = NULL;
4743 *num_of_nodes = 0;
4745 return rc;
4749 CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
4750 const char *search_name, struct dfs_info3_param **target_nodes,
4751 unsigned int *num_of_nodes,
4752 const struct nls_table *nls_codepage, int remap)
4754 /* TRANS2_GET_DFS_REFERRAL */
4755 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4756 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4757 int rc = 0;
4758 int bytes_returned;
4759 int name_len;
4760 __u16 params, byte_count;
4761 *num_of_nodes = 0;
4762 *target_nodes = NULL;
4764 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
4765 if (ses == NULL)
4766 return -ENODEV;
4767 getDFSRetry:
4768 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4769 (void **) &pSMBr);
4770 if (rc)
4771 return rc;
4773 /* server pointer checked in called function,
4774 but should never be null here anyway */
4775 pSMB->hdr.Mid = get_next_mid(ses->server);
4776 pSMB->hdr.Tid = ses->ipc_tid;
4777 pSMB->hdr.Uid = ses->Suid;
4778 if (ses->capabilities & CAP_STATUS32)
4779 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4780 if (ses->capabilities & CAP_DFS)
4781 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4783 if (ses->capabilities & CAP_UNICODE) {
4784 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4785 name_len =
4786 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4787 search_name, PATH_MAX, nls_codepage,
4788 remap);
4789 name_len++; /* trailing null */
4790 name_len *= 2;
4791 } else { /* BB improve the check for buffer overruns BB */
4792 name_len = strnlen(search_name, PATH_MAX);
4793 name_len++; /* trailing null */
4794 strncpy(pSMB->RequestFileName, search_name, name_len);
4797 if (ses->server) {
4798 if (ses->server->sec_mode &
4799 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4800 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4803 pSMB->hdr.Uid = ses->Suid;
4805 params = 2 /* level */ + name_len /*includes null */ ;
4806 pSMB->TotalDataCount = 0;
4807 pSMB->DataCount = 0;
4808 pSMB->DataOffset = 0;
4809 pSMB->MaxParameterCount = 0;
4810 /* BB find exact max SMB PDU from sess structure BB */
4811 pSMB->MaxDataCount = cpu_to_le16(4000);
4812 pSMB->MaxSetupCount = 0;
4813 pSMB->Reserved = 0;
4814 pSMB->Flags = 0;
4815 pSMB->Timeout = 0;
4816 pSMB->Reserved2 = 0;
4817 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4818 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4819 pSMB->SetupCount = 1;
4820 pSMB->Reserved3 = 0;
4821 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4822 byte_count = params + 3 /* pad */ ;
4823 pSMB->ParameterCount = cpu_to_le16(params);
4824 pSMB->TotalParameterCount = pSMB->ParameterCount;
4825 pSMB->MaxReferralLevel = cpu_to_le16(3);
4826 inc_rfc1001_len(pSMB, byte_count);
4827 pSMB->ByteCount = cpu_to_le16(byte_count);
4829 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4831 if (rc) {
4832 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
4833 goto GetDFSRefExit;
4835 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4837 /* BB Also check if enough total bytes returned? */
4838 if (rc || get_bcc(&pSMBr->hdr) < 17) {
4839 rc = -EIO; /* bad smb */
4840 goto GetDFSRefExit;
4843 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4844 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
4846 /* parse returned result into more usable form */
4847 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4848 target_nodes, nls_codepage, remap,
4849 search_name);
4851 GetDFSRefExit:
4852 cifs_buf_release(pSMB);
4854 if (rc == -EAGAIN)
4855 goto getDFSRetry;
4857 return rc;
4860 /* Query File System Info such as free space to old servers such as Win 9x */
4862 SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4863 struct kstatfs *FSData)
4865 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4866 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4867 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4868 FILE_SYSTEM_ALLOC_INFO *response_data;
4869 int rc = 0;
4870 int bytes_returned = 0;
4871 __u16 params, byte_count;
4873 cifs_dbg(FYI, "OldQFSInfo\n");
4874 oldQFSInfoRetry:
4875 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4876 (void **) &pSMBr);
4877 if (rc)
4878 return rc;
4880 params = 2; /* level */
4881 pSMB->TotalDataCount = 0;
4882 pSMB->MaxParameterCount = cpu_to_le16(2);
4883 pSMB->MaxDataCount = cpu_to_le16(1000);
4884 pSMB->MaxSetupCount = 0;
4885 pSMB->Reserved = 0;
4886 pSMB->Flags = 0;
4887 pSMB->Timeout = 0;
4888 pSMB->Reserved2 = 0;
4889 byte_count = params + 1 /* pad */ ;
4890 pSMB->TotalParameterCount = cpu_to_le16(params);
4891 pSMB->ParameterCount = pSMB->TotalParameterCount;
4892 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4893 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4894 pSMB->DataCount = 0;
4895 pSMB->DataOffset = 0;
4896 pSMB->SetupCount = 1;
4897 pSMB->Reserved3 = 0;
4898 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4899 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4900 inc_rfc1001_len(pSMB, byte_count);
4901 pSMB->ByteCount = cpu_to_le16(byte_count);
4903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4905 if (rc) {
4906 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
4907 } else { /* decode response */
4908 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4910 if (rc || get_bcc(&pSMBr->hdr) < 18)
4911 rc = -EIO; /* bad smb */
4912 else {
4913 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4914 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
4915 get_bcc(&pSMBr->hdr), data_offset);
4917 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4918 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4919 FSData->f_bsize =
4920 le16_to_cpu(response_data->BytesPerSector) *
4921 le32_to_cpu(response_data->
4922 SectorsPerAllocationUnit);
4923 FSData->f_blocks =
4924 le32_to_cpu(response_data->TotalAllocationUnits);
4925 FSData->f_bfree = FSData->f_bavail =
4926 le32_to_cpu(response_data->FreeAllocationUnits);
4927 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4928 (unsigned long long)FSData->f_blocks,
4929 (unsigned long long)FSData->f_bfree,
4930 FSData->f_bsize);
4933 cifs_buf_release(pSMB);
4935 if (rc == -EAGAIN)
4936 goto oldQFSInfoRetry;
4938 return rc;
4942 CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4943 struct kstatfs *FSData)
4945 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4946 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4947 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4948 FILE_SYSTEM_INFO *response_data;
4949 int rc = 0;
4950 int bytes_returned = 0;
4951 __u16 params, byte_count;
4953 cifs_dbg(FYI, "In QFSInfo\n");
4954 QFSInfoRetry:
4955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4956 (void **) &pSMBr);
4957 if (rc)
4958 return rc;
4960 params = 2; /* level */
4961 pSMB->TotalDataCount = 0;
4962 pSMB->MaxParameterCount = cpu_to_le16(2);
4963 pSMB->MaxDataCount = cpu_to_le16(1000);
4964 pSMB->MaxSetupCount = 0;
4965 pSMB->Reserved = 0;
4966 pSMB->Flags = 0;
4967 pSMB->Timeout = 0;
4968 pSMB->Reserved2 = 0;
4969 byte_count = params + 1 /* pad */ ;
4970 pSMB->TotalParameterCount = cpu_to_le16(params);
4971 pSMB->ParameterCount = pSMB->TotalParameterCount;
4972 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4973 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4974 pSMB->DataCount = 0;
4975 pSMB->DataOffset = 0;
4976 pSMB->SetupCount = 1;
4977 pSMB->Reserved3 = 0;
4978 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4979 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4980 inc_rfc1001_len(pSMB, byte_count);
4981 pSMB->ByteCount = cpu_to_le16(byte_count);
4983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4985 if (rc) {
4986 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
4987 } else { /* decode response */
4988 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4990 if (rc || get_bcc(&pSMBr->hdr) < 24)
4991 rc = -EIO; /* bad smb */
4992 else {
4993 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4995 response_data =
4996 (FILE_SYSTEM_INFO
4997 *) (((char *) &pSMBr->hdr.Protocol) +
4998 data_offset);
4999 FSData->f_bsize =
5000 le32_to_cpu(response_data->BytesPerSector) *
5001 le32_to_cpu(response_data->
5002 SectorsPerAllocationUnit);
5003 FSData->f_blocks =
5004 le64_to_cpu(response_data->TotalAllocationUnits);
5005 FSData->f_bfree = FSData->f_bavail =
5006 le64_to_cpu(response_data->FreeAllocationUnits);
5007 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5008 (unsigned long long)FSData->f_blocks,
5009 (unsigned long long)FSData->f_bfree,
5010 FSData->f_bsize);
5013 cifs_buf_release(pSMB);
5015 if (rc == -EAGAIN)
5016 goto QFSInfoRetry;
5018 return rc;
5022 CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
5024 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5025 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5026 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5027 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5028 int rc = 0;
5029 int bytes_returned = 0;
5030 __u16 params, byte_count;
5032 cifs_dbg(FYI, "In QFSAttributeInfo\n");
5033 QFSAttributeRetry:
5034 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5035 (void **) &pSMBr);
5036 if (rc)
5037 return rc;
5039 params = 2; /* level */
5040 pSMB->TotalDataCount = 0;
5041 pSMB->MaxParameterCount = cpu_to_le16(2);
5042 /* BB find exact max SMB PDU from sess structure BB */
5043 pSMB->MaxDataCount = cpu_to_le16(1000);
5044 pSMB->MaxSetupCount = 0;
5045 pSMB->Reserved = 0;
5046 pSMB->Flags = 0;
5047 pSMB->Timeout = 0;
5048 pSMB->Reserved2 = 0;
5049 byte_count = params + 1 /* pad */ ;
5050 pSMB->TotalParameterCount = cpu_to_le16(params);
5051 pSMB->ParameterCount = pSMB->TotalParameterCount;
5052 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5053 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5054 pSMB->DataCount = 0;
5055 pSMB->DataOffset = 0;
5056 pSMB->SetupCount = 1;
5057 pSMB->Reserved3 = 0;
5058 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5059 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
5060 inc_rfc1001_len(pSMB, byte_count);
5061 pSMB->ByteCount = cpu_to_le16(byte_count);
5063 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5064 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5065 if (rc) {
5066 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
5067 } else { /* decode response */
5068 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5070 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5071 /* BB also check if enough bytes returned */
5072 rc = -EIO; /* bad smb */
5073 } else {
5074 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5075 response_data =
5076 (FILE_SYSTEM_ATTRIBUTE_INFO
5077 *) (((char *) &pSMBr->hdr.Protocol) +
5078 data_offset);
5079 memcpy(&tcon->fsAttrInfo, response_data,
5080 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
5083 cifs_buf_release(pSMB);
5085 if (rc == -EAGAIN)
5086 goto QFSAttributeRetry;
5088 return rc;
5092 CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
5094 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5095 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5096 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5097 FILE_SYSTEM_DEVICE_INFO *response_data;
5098 int rc = 0;
5099 int bytes_returned = 0;
5100 __u16 params, byte_count;
5102 cifs_dbg(FYI, "In QFSDeviceInfo\n");
5103 QFSDeviceRetry:
5104 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5105 (void **) &pSMBr);
5106 if (rc)
5107 return rc;
5109 params = 2; /* level */
5110 pSMB->TotalDataCount = 0;
5111 pSMB->MaxParameterCount = cpu_to_le16(2);
5112 /* BB find exact max SMB PDU from sess structure BB */
5113 pSMB->MaxDataCount = cpu_to_le16(1000);
5114 pSMB->MaxSetupCount = 0;
5115 pSMB->Reserved = 0;
5116 pSMB->Flags = 0;
5117 pSMB->Timeout = 0;
5118 pSMB->Reserved2 = 0;
5119 byte_count = params + 1 /* pad */ ;
5120 pSMB->TotalParameterCount = cpu_to_le16(params);
5121 pSMB->ParameterCount = pSMB->TotalParameterCount;
5122 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5123 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5125 pSMB->DataCount = 0;
5126 pSMB->DataOffset = 0;
5127 pSMB->SetupCount = 1;
5128 pSMB->Reserved3 = 0;
5129 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5130 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
5131 inc_rfc1001_len(pSMB, byte_count);
5132 pSMB->ByteCount = cpu_to_le16(byte_count);
5134 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5135 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5136 if (rc) {
5137 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
5138 } else { /* decode response */
5139 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5141 if (rc || get_bcc(&pSMBr->hdr) <
5142 sizeof(FILE_SYSTEM_DEVICE_INFO))
5143 rc = -EIO; /* bad smb */
5144 else {
5145 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5146 response_data =
5147 (FILE_SYSTEM_DEVICE_INFO *)
5148 (((char *) &pSMBr->hdr.Protocol) +
5149 data_offset);
5150 memcpy(&tcon->fsDevInfo, response_data,
5151 sizeof(FILE_SYSTEM_DEVICE_INFO));
5154 cifs_buf_release(pSMB);
5156 if (rc == -EAGAIN)
5157 goto QFSDeviceRetry;
5159 return rc;
5163 CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
5165 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5166 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5167 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5168 FILE_SYSTEM_UNIX_INFO *response_data;
5169 int rc = 0;
5170 int bytes_returned = 0;
5171 __u16 params, byte_count;
5173 cifs_dbg(FYI, "In QFSUnixInfo\n");
5174 QFSUnixRetry:
5175 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5176 (void **) &pSMB, (void **) &pSMBr);
5177 if (rc)
5178 return rc;
5180 params = 2; /* level */
5181 pSMB->TotalDataCount = 0;
5182 pSMB->DataCount = 0;
5183 pSMB->DataOffset = 0;
5184 pSMB->MaxParameterCount = cpu_to_le16(2);
5185 /* BB find exact max SMB PDU from sess structure BB */
5186 pSMB->MaxDataCount = cpu_to_le16(100);
5187 pSMB->MaxSetupCount = 0;
5188 pSMB->Reserved = 0;
5189 pSMB->Flags = 0;
5190 pSMB->Timeout = 0;
5191 pSMB->Reserved2 = 0;
5192 byte_count = params + 1 /* pad */ ;
5193 pSMB->ParameterCount = cpu_to_le16(params);
5194 pSMB->TotalParameterCount = pSMB->ParameterCount;
5195 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5196 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5197 pSMB->SetupCount = 1;
5198 pSMB->Reserved3 = 0;
5199 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5200 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
5201 inc_rfc1001_len(pSMB, byte_count);
5202 pSMB->ByteCount = cpu_to_le16(byte_count);
5204 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5205 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5206 if (rc) {
5207 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
5208 } else { /* decode response */
5209 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5211 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5212 rc = -EIO; /* bad smb */
5213 } else {
5214 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5215 response_data =
5216 (FILE_SYSTEM_UNIX_INFO
5217 *) (((char *) &pSMBr->hdr.Protocol) +
5218 data_offset);
5219 memcpy(&tcon->fsUnixInfo, response_data,
5220 sizeof(FILE_SYSTEM_UNIX_INFO));
5223 cifs_buf_release(pSMB);
5225 if (rc == -EAGAIN)
5226 goto QFSUnixRetry;
5229 return rc;
5233 CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
5235 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5236 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5237 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5238 int rc = 0;
5239 int bytes_returned = 0;
5240 __u16 params, param_offset, offset, byte_count;
5242 cifs_dbg(FYI, "In SETFSUnixInfo\n");
5243 SETFSUnixRetry:
5244 /* BB switch to small buf init to save memory */
5245 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5246 (void **) &pSMB, (void **) &pSMBr);
5247 if (rc)
5248 return rc;
5250 params = 4; /* 2 bytes zero followed by info level. */
5251 pSMB->MaxSetupCount = 0;
5252 pSMB->Reserved = 0;
5253 pSMB->Flags = 0;
5254 pSMB->Timeout = 0;
5255 pSMB->Reserved2 = 0;
5256 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5257 - 4;
5258 offset = param_offset + params;
5260 pSMB->MaxParameterCount = cpu_to_le16(4);
5261 /* BB find exact max SMB PDU from sess structure BB */
5262 pSMB->MaxDataCount = cpu_to_le16(100);
5263 pSMB->SetupCount = 1;
5264 pSMB->Reserved3 = 0;
5265 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5266 byte_count = 1 /* pad */ + params + 12;
5268 pSMB->DataCount = cpu_to_le16(12);
5269 pSMB->ParameterCount = cpu_to_le16(params);
5270 pSMB->TotalDataCount = pSMB->DataCount;
5271 pSMB->TotalParameterCount = pSMB->ParameterCount;
5272 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5273 pSMB->DataOffset = cpu_to_le16(offset);
5275 /* Params. */
5276 pSMB->FileNum = 0;
5277 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5279 /* Data. */
5280 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5281 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5282 pSMB->ClientUnixCap = cpu_to_le64(cap);
5284 inc_rfc1001_len(pSMB, byte_count);
5285 pSMB->ByteCount = cpu_to_le16(byte_count);
5287 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5288 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5289 if (rc) {
5290 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
5291 } else { /* decode response */
5292 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5293 if (rc)
5294 rc = -EIO; /* bad smb */
5296 cifs_buf_release(pSMB);
5298 if (rc == -EAGAIN)
5299 goto SETFSUnixRetry;
5301 return rc;
5307 CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
5308 struct kstatfs *FSData)
5310 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5311 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5312 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5313 FILE_SYSTEM_POSIX_INFO *response_data;
5314 int rc = 0;
5315 int bytes_returned = 0;
5316 __u16 params, byte_count;
5318 cifs_dbg(FYI, "In QFSPosixInfo\n");
5319 QFSPosixRetry:
5320 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5321 (void **) &pSMBr);
5322 if (rc)
5323 return rc;
5325 params = 2; /* level */
5326 pSMB->TotalDataCount = 0;
5327 pSMB->DataCount = 0;
5328 pSMB->DataOffset = 0;
5329 pSMB->MaxParameterCount = cpu_to_le16(2);
5330 /* BB find exact max SMB PDU from sess structure BB */
5331 pSMB->MaxDataCount = cpu_to_le16(100);
5332 pSMB->MaxSetupCount = 0;
5333 pSMB->Reserved = 0;
5334 pSMB->Flags = 0;
5335 pSMB->Timeout = 0;
5336 pSMB->Reserved2 = 0;
5337 byte_count = params + 1 /* pad */ ;
5338 pSMB->ParameterCount = cpu_to_le16(params);
5339 pSMB->TotalParameterCount = pSMB->ParameterCount;
5340 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5341 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5342 pSMB->SetupCount = 1;
5343 pSMB->Reserved3 = 0;
5344 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5345 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
5346 inc_rfc1001_len(pSMB, byte_count);
5347 pSMB->ByteCount = cpu_to_le16(byte_count);
5349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5351 if (rc) {
5352 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
5353 } else { /* decode response */
5354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5356 if (rc || get_bcc(&pSMBr->hdr) < 13) {
5357 rc = -EIO; /* bad smb */
5358 } else {
5359 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5360 response_data =
5361 (FILE_SYSTEM_POSIX_INFO
5362 *) (((char *) &pSMBr->hdr.Protocol) +
5363 data_offset);
5364 FSData->f_bsize =
5365 le32_to_cpu(response_data->BlockSize);
5366 FSData->f_blocks =
5367 le64_to_cpu(response_data->TotalBlocks);
5368 FSData->f_bfree =
5369 le64_to_cpu(response_data->BlocksAvail);
5370 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
5371 FSData->f_bavail = FSData->f_bfree;
5372 } else {
5373 FSData->f_bavail =
5374 le64_to_cpu(response_data->UserBlocksAvail);
5376 if (response_data->TotalFileNodes != cpu_to_le64(-1))
5377 FSData->f_files =
5378 le64_to_cpu(response_data->TotalFileNodes);
5379 if (response_data->FreeFileNodes != cpu_to_le64(-1))
5380 FSData->f_ffree =
5381 le64_to_cpu(response_data->FreeFileNodes);
5384 cifs_buf_release(pSMB);
5386 if (rc == -EAGAIN)
5387 goto QFSPosixRetry;
5389 return rc;
5394 * We can not use write of zero bytes trick to set file size due to need for
5395 * large file support. Also note that this SetPathInfo is preferred to
5396 * SetFileInfo based method in next routine which is only needed to work around
5397 * a sharing violation bugin Samba which this routine can run into.
5400 CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5401 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5402 bool set_allocation)
5404 struct smb_com_transaction2_spi_req *pSMB = NULL;
5405 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5406 struct file_end_of_file_info *parm_data;
5407 int name_len;
5408 int rc = 0;
5409 int bytes_returned = 0;
5410 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5412 __u16 params, byte_count, data_count, param_offset, offset;
5414 cifs_dbg(FYI, "In SetEOF\n");
5415 SetEOFRetry:
5416 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5417 (void **) &pSMBr);
5418 if (rc)
5419 return rc;
5421 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5422 name_len =
5423 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5424 PATH_MAX, cifs_sb->local_nls, remap);
5425 name_len++; /* trailing null */
5426 name_len *= 2;
5427 } else { /* BB improve the check for buffer overruns BB */
5428 name_len = strnlen(file_name, PATH_MAX);
5429 name_len++; /* trailing null */
5430 strncpy(pSMB->FileName, file_name, name_len);
5432 params = 6 + name_len;
5433 data_count = sizeof(struct file_end_of_file_info);
5434 pSMB->MaxParameterCount = cpu_to_le16(2);
5435 pSMB->MaxDataCount = cpu_to_le16(4100);
5436 pSMB->MaxSetupCount = 0;
5437 pSMB->Reserved = 0;
5438 pSMB->Flags = 0;
5439 pSMB->Timeout = 0;
5440 pSMB->Reserved2 = 0;
5441 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5442 InformationLevel) - 4;
5443 offset = param_offset + params;
5444 if (set_allocation) {
5445 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5446 pSMB->InformationLevel =
5447 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5448 else
5449 pSMB->InformationLevel =
5450 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5451 } else /* Set File Size */ {
5452 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5453 pSMB->InformationLevel =
5454 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
5455 else
5456 pSMB->InformationLevel =
5457 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
5460 parm_data =
5461 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5462 offset);
5463 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5464 pSMB->DataOffset = cpu_to_le16(offset);
5465 pSMB->SetupCount = 1;
5466 pSMB->Reserved3 = 0;
5467 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5468 byte_count = 3 /* pad */ + params + data_count;
5469 pSMB->DataCount = cpu_to_le16(data_count);
5470 pSMB->TotalDataCount = pSMB->DataCount;
5471 pSMB->ParameterCount = cpu_to_le16(params);
5472 pSMB->TotalParameterCount = pSMB->ParameterCount;
5473 pSMB->Reserved4 = 0;
5474 inc_rfc1001_len(pSMB, byte_count);
5475 parm_data->FileSize = cpu_to_le64(size);
5476 pSMB->ByteCount = cpu_to_le16(byte_count);
5477 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5478 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5479 if (rc)
5480 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
5482 cifs_buf_release(pSMB);
5484 if (rc == -EAGAIN)
5485 goto SetEOFRetry;
5487 return rc;
5491 CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5492 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
5494 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5495 struct file_end_of_file_info *parm_data;
5496 int rc = 0;
5497 __u16 params, param_offset, offset, byte_count, count;
5499 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5500 (long long)size);
5501 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5503 if (rc)
5504 return rc;
5506 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5507 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
5509 params = 6;
5510 pSMB->MaxSetupCount = 0;
5511 pSMB->Reserved = 0;
5512 pSMB->Flags = 0;
5513 pSMB->Timeout = 0;
5514 pSMB->Reserved2 = 0;
5515 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5516 offset = param_offset + params;
5518 count = sizeof(struct file_end_of_file_info);
5519 pSMB->MaxParameterCount = cpu_to_le16(2);
5520 /* BB find exact max SMB PDU from sess structure BB */
5521 pSMB->MaxDataCount = cpu_to_le16(1000);
5522 pSMB->SetupCount = 1;
5523 pSMB->Reserved3 = 0;
5524 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5525 byte_count = 3 /* pad */ + params + count;
5526 pSMB->DataCount = cpu_to_le16(count);
5527 pSMB->ParameterCount = cpu_to_le16(params);
5528 pSMB->TotalDataCount = pSMB->DataCount;
5529 pSMB->TotalParameterCount = pSMB->ParameterCount;
5530 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5531 parm_data =
5532 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5533 + offset);
5534 pSMB->DataOffset = cpu_to_le16(offset);
5535 parm_data->FileSize = cpu_to_le64(size);
5536 pSMB->Fid = cfile->fid.netfid;
5537 if (set_allocation) {
5538 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5539 pSMB->InformationLevel =
5540 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5541 else
5542 pSMB->InformationLevel =
5543 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5544 } else /* Set File Size */ {
5545 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5546 pSMB->InformationLevel =
5547 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
5548 else
5549 pSMB->InformationLevel =
5550 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
5552 pSMB->Reserved4 = 0;
5553 inc_rfc1001_len(pSMB, byte_count);
5554 pSMB->ByteCount = cpu_to_le16(byte_count);
5555 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5556 if (rc) {
5557 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5558 rc);
5561 /* Note: On -EAGAIN error only caller can retry on handle based calls
5562 since file handle passed in no longer valid */
5564 return rc;
5567 /* Some legacy servers such as NT4 require that the file times be set on
5568 an open handle, rather than by pathname - this is awkward due to
5569 potential access conflicts on the open, but it is unavoidable for these
5570 old servers since the only other choice is to go from 100 nanosecond DCE
5571 time and resort to the original setpathinfo level which takes the ancient
5572 DOS time format with 2 second granularity */
5574 CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
5575 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
5577 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5578 char *data_offset;
5579 int rc = 0;
5580 __u16 params, param_offset, offset, byte_count, count;
5582 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
5583 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5585 if (rc)
5586 return rc;
5588 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5589 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5591 params = 6;
5592 pSMB->MaxSetupCount = 0;
5593 pSMB->Reserved = 0;
5594 pSMB->Flags = 0;
5595 pSMB->Timeout = 0;
5596 pSMB->Reserved2 = 0;
5597 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5598 offset = param_offset + params;
5600 data_offset = (char *)pSMB +
5601 offsetof(struct smb_hdr, Protocol) + offset;
5603 count = sizeof(FILE_BASIC_INFO);
5604 pSMB->MaxParameterCount = cpu_to_le16(2);
5605 /* BB find max SMB PDU from sess */
5606 pSMB->MaxDataCount = cpu_to_le16(1000);
5607 pSMB->SetupCount = 1;
5608 pSMB->Reserved3 = 0;
5609 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5610 byte_count = 3 /* pad */ + params + count;
5611 pSMB->DataCount = cpu_to_le16(count);
5612 pSMB->ParameterCount = cpu_to_le16(params);
5613 pSMB->TotalDataCount = pSMB->DataCount;
5614 pSMB->TotalParameterCount = pSMB->ParameterCount;
5615 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5616 pSMB->DataOffset = cpu_to_le16(offset);
5617 pSMB->Fid = fid;
5618 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5619 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5620 else
5621 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5622 pSMB->Reserved4 = 0;
5623 inc_rfc1001_len(pSMB, byte_count);
5624 pSMB->ByteCount = cpu_to_le16(byte_count);
5625 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5626 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5627 if (rc)
5628 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5629 rc);
5631 /* Note: On -EAGAIN error only caller can retry on handle based calls
5632 since file handle passed in no longer valid */
5634 return rc;
5638 CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
5639 bool delete_file, __u16 fid, __u32 pid_of_opener)
5641 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5642 char *data_offset;
5643 int rc = 0;
5644 __u16 params, param_offset, offset, byte_count, count;
5646 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
5647 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5649 if (rc)
5650 return rc;
5652 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5653 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5655 params = 6;
5656 pSMB->MaxSetupCount = 0;
5657 pSMB->Reserved = 0;
5658 pSMB->Flags = 0;
5659 pSMB->Timeout = 0;
5660 pSMB->Reserved2 = 0;
5661 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5662 offset = param_offset + params;
5664 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5666 count = 1;
5667 pSMB->MaxParameterCount = cpu_to_le16(2);
5668 /* BB find max SMB PDU from sess */
5669 pSMB->MaxDataCount = cpu_to_le16(1000);
5670 pSMB->SetupCount = 1;
5671 pSMB->Reserved3 = 0;
5672 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5673 byte_count = 3 /* pad */ + params + count;
5674 pSMB->DataCount = cpu_to_le16(count);
5675 pSMB->ParameterCount = cpu_to_le16(params);
5676 pSMB->TotalDataCount = pSMB->DataCount;
5677 pSMB->TotalParameterCount = pSMB->ParameterCount;
5678 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5679 pSMB->DataOffset = cpu_to_le16(offset);
5680 pSMB->Fid = fid;
5681 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5682 pSMB->Reserved4 = 0;
5683 inc_rfc1001_len(pSMB, byte_count);
5684 pSMB->ByteCount = cpu_to_le16(byte_count);
5685 *data_offset = delete_file ? 1 : 0;
5686 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5687 if (rc)
5688 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
5690 return rc;
5694 CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
5695 const char *fileName, const FILE_BASIC_INFO *data,
5696 const struct nls_table *nls_codepage, int remap)
5698 TRANSACTION2_SPI_REQ *pSMB = NULL;
5699 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5700 int name_len;
5701 int rc = 0;
5702 int bytes_returned = 0;
5703 char *data_offset;
5704 __u16 params, param_offset, offset, byte_count, count;
5706 cifs_dbg(FYI, "In SetTimes\n");
5708 SetTimesRetry:
5709 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5710 (void **) &pSMBr);
5711 if (rc)
5712 return rc;
5714 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5715 name_len =
5716 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5717 PATH_MAX, nls_codepage, remap);
5718 name_len++; /* trailing null */
5719 name_len *= 2;
5720 } else { /* BB improve the check for buffer overruns BB */
5721 name_len = strnlen(fileName, PATH_MAX);
5722 name_len++; /* trailing null */
5723 strncpy(pSMB->FileName, fileName, name_len);
5726 params = 6 + name_len;
5727 count = sizeof(FILE_BASIC_INFO);
5728 pSMB->MaxParameterCount = cpu_to_le16(2);
5729 /* BB find max SMB PDU from sess structure BB */
5730 pSMB->MaxDataCount = cpu_to_le16(1000);
5731 pSMB->MaxSetupCount = 0;
5732 pSMB->Reserved = 0;
5733 pSMB->Flags = 0;
5734 pSMB->Timeout = 0;
5735 pSMB->Reserved2 = 0;
5736 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5737 InformationLevel) - 4;
5738 offset = param_offset + params;
5739 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5740 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5741 pSMB->DataOffset = cpu_to_le16(offset);
5742 pSMB->SetupCount = 1;
5743 pSMB->Reserved3 = 0;
5744 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5745 byte_count = 3 /* pad */ + params + count;
5747 pSMB->DataCount = cpu_to_le16(count);
5748 pSMB->ParameterCount = cpu_to_le16(params);
5749 pSMB->TotalDataCount = pSMB->DataCount;
5750 pSMB->TotalParameterCount = pSMB->ParameterCount;
5751 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5752 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5753 else
5754 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5755 pSMB->Reserved4 = 0;
5756 inc_rfc1001_len(pSMB, byte_count);
5757 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5758 pSMB->ByteCount = cpu_to_le16(byte_count);
5759 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5760 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5761 if (rc)
5762 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
5764 cifs_buf_release(pSMB);
5766 if (rc == -EAGAIN)
5767 goto SetTimesRetry;
5769 return rc;
5772 /* Can not be used to set time stamps yet (due to old DOS time format) */
5773 /* Can be used to set attributes */
5774 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5775 handling it anyway and NT4 was what we thought it would be needed for
5776 Do not delete it until we prove whether needed for Win9x though */
5778 CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
5779 __u16 dos_attrs, const struct nls_table *nls_codepage)
5781 SETATTR_REQ *pSMB = NULL;
5782 SETATTR_RSP *pSMBr = NULL;
5783 int rc = 0;
5784 int bytes_returned;
5785 int name_len;
5787 cifs_dbg(FYI, "In SetAttrLegacy\n");
5789 SetAttrLgcyRetry:
5790 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5791 (void **) &pSMBr);
5792 if (rc)
5793 return rc;
5795 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5796 name_len =
5797 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5798 PATH_MAX, nls_codepage);
5799 name_len++; /* trailing null */
5800 name_len *= 2;
5801 } else { /* BB improve the check for buffer overruns BB */
5802 name_len = strnlen(fileName, PATH_MAX);
5803 name_len++; /* trailing null */
5804 strncpy(pSMB->fileName, fileName, name_len);
5806 pSMB->attr = cpu_to_le16(dos_attrs);
5807 pSMB->BufferFormat = 0x04;
5808 inc_rfc1001_len(pSMB, name_len + 1);
5809 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5810 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5811 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5812 if (rc)
5813 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
5815 cifs_buf_release(pSMB);
5817 if (rc == -EAGAIN)
5818 goto SetAttrLgcyRetry;
5820 return rc;
5822 #endif /* temporarily unneeded SetAttr legacy function */
5824 static void
5825 cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5826 const struct cifs_unix_set_info_args *args)
5828 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
5829 u64 mode = args->mode;
5831 if (uid_valid(args->uid))
5832 uid = from_kuid(&init_user_ns, args->uid);
5833 if (gid_valid(args->gid))
5834 gid = from_kgid(&init_user_ns, args->gid);
5837 * Samba server ignores set of file size to zero due to bugs in some
5838 * older clients, but we should be precise - we use SetFileSize to
5839 * set file size and do not want to truncate file size to zero
5840 * accidentally as happened on one Samba server beta by putting
5841 * zero instead of -1 here
5843 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5844 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5845 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5846 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5847 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5848 data_offset->Uid = cpu_to_le64(uid);
5849 data_offset->Gid = cpu_to_le64(gid);
5850 /* better to leave device as zero when it is */
5851 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5852 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5853 data_offset->Permissions = cpu_to_le64(mode);
5855 if (S_ISREG(mode))
5856 data_offset->Type = cpu_to_le32(UNIX_FILE);
5857 else if (S_ISDIR(mode))
5858 data_offset->Type = cpu_to_le32(UNIX_DIR);
5859 else if (S_ISLNK(mode))
5860 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5861 else if (S_ISCHR(mode))
5862 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5863 else if (S_ISBLK(mode))
5864 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5865 else if (S_ISFIFO(mode))
5866 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5867 else if (S_ISSOCK(mode))
5868 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5872 CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
5873 const struct cifs_unix_set_info_args *args,
5874 u16 fid, u32 pid_of_opener)
5876 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5877 char *data_offset;
5878 int rc = 0;
5879 u16 params, param_offset, offset, byte_count, count;
5881 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
5882 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5884 if (rc)
5885 return rc;
5887 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5888 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5890 params = 6;
5891 pSMB->MaxSetupCount = 0;
5892 pSMB->Reserved = 0;
5893 pSMB->Flags = 0;
5894 pSMB->Timeout = 0;
5895 pSMB->Reserved2 = 0;
5896 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5897 offset = param_offset + params;
5899 data_offset = (char *)pSMB +
5900 offsetof(struct smb_hdr, Protocol) + offset;
5902 count = sizeof(FILE_UNIX_BASIC_INFO);
5904 pSMB->MaxParameterCount = cpu_to_le16(2);
5905 /* BB find max SMB PDU from sess */
5906 pSMB->MaxDataCount = cpu_to_le16(1000);
5907 pSMB->SetupCount = 1;
5908 pSMB->Reserved3 = 0;
5909 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5910 byte_count = 3 /* pad */ + params + count;
5911 pSMB->DataCount = cpu_to_le16(count);
5912 pSMB->ParameterCount = cpu_to_le16(params);
5913 pSMB->TotalDataCount = pSMB->DataCount;
5914 pSMB->TotalParameterCount = pSMB->ParameterCount;
5915 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5916 pSMB->DataOffset = cpu_to_le16(offset);
5917 pSMB->Fid = fid;
5918 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5919 pSMB->Reserved4 = 0;
5920 inc_rfc1001_len(pSMB, byte_count);
5921 pSMB->ByteCount = cpu_to_le16(byte_count);
5923 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
5925 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5926 if (rc)
5927 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5928 rc);
5930 /* Note: On -EAGAIN error only caller can retry on handle based calls
5931 since file handle passed in no longer valid */
5933 return rc;
5937 CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
5938 const char *file_name,
5939 const struct cifs_unix_set_info_args *args,
5940 const struct nls_table *nls_codepage, int remap)
5942 TRANSACTION2_SPI_REQ *pSMB = NULL;
5943 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5944 int name_len;
5945 int rc = 0;
5946 int bytes_returned = 0;
5947 FILE_UNIX_BASIC_INFO *data_offset;
5948 __u16 params, param_offset, offset, count, byte_count;
5950 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
5951 setPermsRetry:
5952 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5953 (void **) &pSMBr);
5954 if (rc)
5955 return rc;
5957 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5958 name_len =
5959 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5960 PATH_MAX, nls_codepage, remap);
5961 name_len++; /* trailing null */
5962 name_len *= 2;
5963 } else { /* BB improve the check for buffer overruns BB */
5964 name_len = strnlen(file_name, PATH_MAX);
5965 name_len++; /* trailing null */
5966 strncpy(pSMB->FileName, file_name, name_len);
5969 params = 6 + name_len;
5970 count = sizeof(FILE_UNIX_BASIC_INFO);
5971 pSMB->MaxParameterCount = cpu_to_le16(2);
5972 /* BB find max SMB PDU from sess structure BB */
5973 pSMB->MaxDataCount = cpu_to_le16(1000);
5974 pSMB->MaxSetupCount = 0;
5975 pSMB->Reserved = 0;
5976 pSMB->Flags = 0;
5977 pSMB->Timeout = 0;
5978 pSMB->Reserved2 = 0;
5979 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5980 InformationLevel) - 4;
5981 offset = param_offset + params;
5982 data_offset =
5983 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5984 offset);
5985 memset(data_offset, 0, count);
5986 pSMB->DataOffset = cpu_to_le16(offset);
5987 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5988 pSMB->SetupCount = 1;
5989 pSMB->Reserved3 = 0;
5990 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5991 byte_count = 3 /* pad */ + params + count;
5992 pSMB->ParameterCount = cpu_to_le16(params);
5993 pSMB->DataCount = cpu_to_le16(count);
5994 pSMB->TotalParameterCount = pSMB->ParameterCount;
5995 pSMB->TotalDataCount = pSMB->DataCount;
5996 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5997 pSMB->Reserved4 = 0;
5998 inc_rfc1001_len(pSMB, byte_count);
6000 cifs_fill_unix_set_info(data_offset, args);
6002 pSMB->ByteCount = cpu_to_le16(byte_count);
6003 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6004 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6005 if (rc)
6006 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
6008 cifs_buf_release(pSMB);
6009 if (rc == -EAGAIN)
6010 goto setPermsRetry;
6011 return rc;
6014 #ifdef CONFIG_CIFS_XATTR
6016 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6017 * function used by listxattr and getxattr type calls. When ea_name is set,
6018 * it looks for that attribute name and stuffs that value into the EAData
6019 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6020 * buffer. In both cases, the return value is either the length of the
6021 * resulting data or a negative error code. If EAData is a NULL pointer then
6022 * the data isn't copied to it, but the length is returned.
6024 ssize_t
6025 CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
6026 const unsigned char *searchName, const unsigned char *ea_name,
6027 char *EAData, size_t buf_size,
6028 const struct nls_table *nls_codepage, int remap)
6030 /* BB assumes one setup word */
6031 TRANSACTION2_QPI_REQ *pSMB = NULL;
6032 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6033 int rc = 0;
6034 int bytes_returned;
6035 int list_len;
6036 struct fealist *ea_response_data;
6037 struct fea *temp_fea;
6038 char *temp_ptr;
6039 char *end_of_smb;
6040 __u16 params, byte_count, data_offset;
6041 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
6043 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
6044 QAllEAsRetry:
6045 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6046 (void **) &pSMBr);
6047 if (rc)
6048 return rc;
6050 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6051 list_len =
6052 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6053 PATH_MAX, nls_codepage, remap);
6054 list_len++; /* trailing null */
6055 list_len *= 2;
6056 } else { /* BB improve the check for buffer overruns BB */
6057 list_len = strnlen(searchName, PATH_MAX);
6058 list_len++; /* trailing null */
6059 strncpy(pSMB->FileName, searchName, list_len);
6062 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
6063 pSMB->TotalDataCount = 0;
6064 pSMB->MaxParameterCount = cpu_to_le16(2);
6065 /* BB find exact max SMB PDU from sess structure BB */
6066 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
6067 pSMB->MaxSetupCount = 0;
6068 pSMB->Reserved = 0;
6069 pSMB->Flags = 0;
6070 pSMB->Timeout = 0;
6071 pSMB->Reserved2 = 0;
6072 pSMB->ParameterOffset = cpu_to_le16(offsetof(
6073 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
6074 pSMB->DataCount = 0;
6075 pSMB->DataOffset = 0;
6076 pSMB->SetupCount = 1;
6077 pSMB->Reserved3 = 0;
6078 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6079 byte_count = params + 1 /* pad */ ;
6080 pSMB->TotalParameterCount = cpu_to_le16(params);
6081 pSMB->ParameterCount = pSMB->TotalParameterCount;
6082 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6083 pSMB->Reserved4 = 0;
6084 inc_rfc1001_len(pSMB, byte_count);
6085 pSMB->ByteCount = cpu_to_le16(byte_count);
6087 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6088 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6089 if (rc) {
6090 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
6091 goto QAllEAsOut;
6095 /* BB also check enough total bytes returned */
6096 /* BB we need to improve the validity checking
6097 of these trans2 responses */
6099 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
6100 if (rc || get_bcc(&pSMBr->hdr) < 4) {
6101 rc = -EIO; /* bad smb */
6102 goto QAllEAsOut;
6105 /* check that length of list is not more than bcc */
6106 /* check that each entry does not go beyond length
6107 of list */
6108 /* check that each element of each entry does not
6109 go beyond end of list */
6110 /* validate_trans2_offsets() */
6111 /* BB check if start of smb + data_offset > &bcc+ bcc */
6113 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6114 ea_response_data = (struct fealist *)
6115 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6117 list_len = le32_to_cpu(ea_response_data->list_len);
6118 cifs_dbg(FYI, "ea length %d\n", list_len);
6119 if (list_len <= 8) {
6120 cifs_dbg(FYI, "empty EA list returned from server\n");
6121 goto QAllEAsOut;
6124 /* make sure list_len doesn't go past end of SMB */
6125 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
6126 if ((char *)ea_response_data + list_len > end_of_smb) {
6127 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
6128 rc = -EIO;
6129 goto QAllEAsOut;
6132 /* account for ea list len */
6133 list_len -= 4;
6134 temp_fea = ea_response_data->list;
6135 temp_ptr = (char *)temp_fea;
6136 while (list_len > 0) {
6137 unsigned int name_len;
6138 __u16 value_len;
6140 list_len -= 4;
6141 temp_ptr += 4;
6142 /* make sure we can read name_len and value_len */
6143 if (list_len < 0) {
6144 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
6145 rc = -EIO;
6146 goto QAllEAsOut;
6149 name_len = temp_fea->name_len;
6150 value_len = le16_to_cpu(temp_fea->value_len);
6151 list_len -= name_len + 1 + value_len;
6152 if (list_len < 0) {
6153 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
6154 rc = -EIO;
6155 goto QAllEAsOut;
6158 if (ea_name) {
6159 if (ea_name_len == name_len &&
6160 memcmp(ea_name, temp_ptr, name_len) == 0) {
6161 temp_ptr += name_len + 1;
6162 rc = value_len;
6163 if (buf_size == 0)
6164 goto QAllEAsOut;
6165 if ((size_t)value_len > buf_size) {
6166 rc = -ERANGE;
6167 goto QAllEAsOut;
6169 memcpy(EAData, temp_ptr, value_len);
6170 goto QAllEAsOut;
6172 } else {
6173 /* account for prefix user. and trailing null */
6174 rc += (5 + 1 + name_len);
6175 if (rc < (int) buf_size) {
6176 memcpy(EAData, "user.", 5);
6177 EAData += 5;
6178 memcpy(EAData, temp_ptr, name_len);
6179 EAData += name_len;
6180 /* null terminate name */
6181 *EAData = 0;
6182 ++EAData;
6183 } else if (buf_size == 0) {
6184 /* skip copy - calc size only */
6185 } else {
6186 /* stop before overrun buffer */
6187 rc = -ERANGE;
6188 break;
6191 temp_ptr += name_len + 1 + value_len;
6192 temp_fea = (struct fea *)temp_ptr;
6195 /* didn't find the named attribute */
6196 if (ea_name)
6197 rc = -ENODATA;
6199 QAllEAsOut:
6200 cifs_buf_release(pSMB);
6201 if (rc == -EAGAIN)
6202 goto QAllEAsRetry;
6204 return (ssize_t)rc;
6208 CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6209 const char *fileName, const char *ea_name, const void *ea_value,
6210 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6211 int remap)
6213 struct smb_com_transaction2_spi_req *pSMB = NULL;
6214 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6215 struct fealist *parm_data;
6216 int name_len;
6217 int rc = 0;
6218 int bytes_returned = 0;
6219 __u16 params, param_offset, byte_count, offset, count;
6221 cifs_dbg(FYI, "In SetEA\n");
6222 SetEARetry:
6223 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6224 (void **) &pSMBr);
6225 if (rc)
6226 return rc;
6228 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6229 name_len =
6230 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6231 PATH_MAX, nls_codepage, remap);
6232 name_len++; /* trailing null */
6233 name_len *= 2;
6234 } else { /* BB improve the check for buffer overruns BB */
6235 name_len = strnlen(fileName, PATH_MAX);
6236 name_len++; /* trailing null */
6237 strncpy(pSMB->FileName, fileName, name_len);
6240 params = 6 + name_len;
6242 /* done calculating parms using name_len of file name,
6243 now use name_len to calculate length of ea name
6244 we are going to create in the inode xattrs */
6245 if (ea_name == NULL)
6246 name_len = 0;
6247 else
6248 name_len = strnlen(ea_name, 255);
6250 count = sizeof(*parm_data) + ea_value_len + name_len;
6251 pSMB->MaxParameterCount = cpu_to_le16(2);
6252 /* BB find max SMB PDU from sess */
6253 pSMB->MaxDataCount = cpu_to_le16(1000);
6254 pSMB->MaxSetupCount = 0;
6255 pSMB->Reserved = 0;
6256 pSMB->Flags = 0;
6257 pSMB->Timeout = 0;
6258 pSMB->Reserved2 = 0;
6259 param_offset = offsetof(struct smb_com_transaction2_spi_req,
6260 InformationLevel) - 4;
6261 offset = param_offset + params;
6262 pSMB->InformationLevel =
6263 cpu_to_le16(SMB_SET_FILE_EA);
6265 parm_data =
6266 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6267 offset);
6268 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6269 pSMB->DataOffset = cpu_to_le16(offset);
6270 pSMB->SetupCount = 1;
6271 pSMB->Reserved3 = 0;
6272 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6273 byte_count = 3 /* pad */ + params + count;
6274 pSMB->DataCount = cpu_to_le16(count);
6275 parm_data->list_len = cpu_to_le32(count);
6276 parm_data->list[0].EA_flags = 0;
6277 /* we checked above that name len is less than 255 */
6278 parm_data->list[0].name_len = (__u8)name_len;
6279 /* EA names are always ASCII */
6280 if (ea_name)
6281 strncpy(parm_data->list[0].name, ea_name, name_len);
6282 parm_data->list[0].name[name_len] = 0;
6283 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6284 /* caller ensures that ea_value_len is less than 64K but
6285 we need to ensure that it fits within the smb */
6287 /*BB add length check to see if it would fit in
6288 negotiated SMB buffer size BB */
6289 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6290 if (ea_value_len)
6291 memcpy(parm_data->list[0].name+name_len+1,
6292 ea_value, ea_value_len);
6294 pSMB->TotalDataCount = pSMB->DataCount;
6295 pSMB->ParameterCount = cpu_to_le16(params);
6296 pSMB->TotalParameterCount = pSMB->ParameterCount;
6297 pSMB->Reserved4 = 0;
6298 inc_rfc1001_len(pSMB, byte_count);
6299 pSMB->ByteCount = cpu_to_le16(byte_count);
6300 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6301 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6302 if (rc)
6303 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
6305 cifs_buf_release(pSMB);
6307 if (rc == -EAGAIN)
6308 goto SetEARetry;
6310 return rc;
6312 #endif
6314 #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6316 * Years ago the kernel added a "dnotify" function for Samba server,
6317 * to allow network clients (such as Windows) to display updated
6318 * lists of files in directory listings automatically when
6319 * files are added by one user when another user has the
6320 * same directory open on their desktop. The Linux cifs kernel
6321 * client hooked into the kernel side of this interface for
6322 * the same reason, but ironically when the VFS moved from
6323 * "dnotify" to "inotify" it became harder to plug in Linux
6324 * network file system clients (the most obvious use case
6325 * for notify interfaces is when multiple users can update
6326 * the contents of the same directory - exactly what network
6327 * file systems can do) although the server (Samba) could
6328 * still use it. For the short term we leave the worker
6329 * function ifdeffed out (below) until inotify is fixed
6330 * in the VFS to make it easier to plug in network file
6331 * system clients. If inotify turns out to be permanently
6332 * incompatible for network fs clients, we could instead simply
6333 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6335 int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
6336 const int notify_subdirs, const __u16 netfid,
6337 __u32 filter, struct file *pfile, int multishot,
6338 const struct nls_table *nls_codepage)
6340 int rc = 0;
6341 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6342 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6343 struct dir_notify_req *dnotify_req;
6344 int bytes_returned;
6346 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
6347 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6348 (void **) &pSMBr);
6349 if (rc)
6350 return rc;
6352 pSMB->TotalParameterCount = 0 ;
6353 pSMB->TotalDataCount = 0;
6354 pSMB->MaxParameterCount = cpu_to_le32(2);
6355 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
6356 pSMB->MaxSetupCount = 4;
6357 pSMB->Reserved = 0;
6358 pSMB->ParameterOffset = 0;
6359 pSMB->DataCount = 0;
6360 pSMB->DataOffset = 0;
6361 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6362 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6363 pSMB->ParameterCount = pSMB->TotalParameterCount;
6364 if (notify_subdirs)
6365 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6366 pSMB->Reserved2 = 0;
6367 pSMB->CompletionFilter = cpu_to_le32(filter);
6368 pSMB->Fid = netfid; /* file handle always le */
6369 pSMB->ByteCount = 0;
6371 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6372 (struct smb_hdr *)pSMBr, &bytes_returned,
6373 CIFS_ASYNC_OP);
6374 if (rc) {
6375 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
6376 } else {
6377 /* Add file to outstanding requests */
6378 /* BB change to kmem cache alloc */
6379 dnotify_req = kmalloc(
6380 sizeof(struct dir_notify_req),
6381 GFP_KERNEL);
6382 if (dnotify_req) {
6383 dnotify_req->Pid = pSMB->hdr.Pid;
6384 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6385 dnotify_req->Mid = pSMB->hdr.Mid;
6386 dnotify_req->Tid = pSMB->hdr.Tid;
6387 dnotify_req->Uid = pSMB->hdr.Uid;
6388 dnotify_req->netfid = netfid;
6389 dnotify_req->pfile = pfile;
6390 dnotify_req->filter = filter;
6391 dnotify_req->multishot = multishot;
6392 spin_lock(&GlobalMid_Lock);
6393 list_add_tail(&dnotify_req->lhead,
6394 &GlobalDnotifyReqList);
6395 spin_unlock(&GlobalMid_Lock);
6396 } else
6397 rc = -ENOMEM;
6399 cifs_buf_release(pSMB);
6400 return rc;
6402 #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */