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