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