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