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