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