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