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