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