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