]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/cifs/cifssmb.c
[CIFS] Can't rely on iov length and base when kernel_recvmsg returns error
[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 1311 pfile_info->NumberOfLinks = cpu_to_le32(1);
9a8165fc 1312 pfile_info->DeletePending = 0;
a9d02ad4
SF
1313 }
1314 }
1315
1316 cifs_buf_release(pSMB);
1317 if (rc == -EAGAIN)
1318 goto OldOpenRetry;
1319 return rc;
1320}
1321
1da177e4
LT
1322int
1323CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1324 const char *fileName, const int openDisposition,
ad7a2926
SF
1325 const int access_flags, const int create_options, __u16 *netfid,
1326 int *pOplock, FILE_ALL_INFO *pfile_info,
737b758c 1327 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1328{
1329 int rc = -EACCES;
1330 OPEN_REQ *pSMB = NULL;
1331 OPEN_RSP *pSMBr = NULL;
1332 int bytes_returned;
1333 int name_len;
1334 __u16 count;
1335
1336openRetry:
1337 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1338 (void **) &pSMBr);
1339 if (rc)
1340 return rc;
1341
1342 pSMB->AndXCommand = 0xFF; /* none */
1343
1344 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1345 count = 1; /* account for one byte pad to word boundary */
1346 name_len =
b1a45695 1347 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
737b758c 1348 fileName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1349 name_len++; /* trailing null */
1350 name_len *= 2;
1351 pSMB->NameLength = cpu_to_le16(name_len);
09d1db5c 1352 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
1353 count = 0; /* no pad */
1354 name_len = strnlen(fileName, PATH_MAX);
1355 name_len++; /* trailing null */
1356 pSMB->NameLength = cpu_to_le16(name_len);
1357 strncpy(pSMB->fileName, fileName, name_len);
1358 }
1359 if (*pOplock & REQ_OPLOCK)
1360 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
26f57364 1361 else if (*pOplock & REQ_BATCHOPLOCK)
1da177e4 1362 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1da177e4
LT
1363 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1364 pSMB->AllocationSize = 0;
eda3c029
SF
1365 /* set file as system file if special file such
1366 as fifo and server expecting SFU style and
1367 no Unix extensions */
790fe579 1368 if (create_options & CREATE_OPTION_SPECIAL)
eda3c029
SF
1369 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1370 else
1371 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
67750fb9 1372
1da177e4
LT
1373 /* XP does not handle ATTR_POSIX_SEMANTICS */
1374 /* but it helps speed up case sensitive checks for other
1375 servers such as Samba */
1376 if (tcon->ses->capabilities & CAP_UNIX)
1377 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1378
67750fb9
JL
1379 if (create_options & CREATE_OPTION_READONLY)
1380 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1381
1da177e4
LT
1382 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1383 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
eda3c029 1384 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
09d1db5c
SF
1385 /* BB Expirement with various impersonation levels and verify */
1386 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1da177e4
LT
1387 pSMB->SecurityFlags =
1388 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1389
1390 count += name_len;
1391 pSMB->hdr.smb_buf_length += count;
1392
1393 pSMB->ByteCount = cpu_to_le16(count);
1394 /* long_op set to 1 to allow for oplock break timeouts */
1395 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
133672ef 1396 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
a4544347 1397 cifs_stats_inc(&tcon->num_opens);
1da177e4
LT
1398 if (rc) {
1399 cFYI(1, ("Error in Open = %d", rc));
1400 } else {
09d1db5c 1401 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1da177e4
LT
1402 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1403 /* Let caller know file was created so we can set the mode. */
1404 /* Do we care about the CreateAction in any other cases? */
790fe579 1405 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
50c2f753 1406 *pOplock |= CIFS_CREATE_ACTION;
790fe579 1407 if (pfile_info) {
50c2f753 1408 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1da177e4
LT
1409 36 /* CreationTime to Attributes */);
1410 /* the file_info buf is endian converted by caller */
1411 pfile_info->AllocationSize = pSMBr->AllocationSize;
1412 pfile_info->EndOfFile = pSMBr->EndOfFile;
1413 pfile_info->NumberOfLinks = cpu_to_le32(1);
9a8165fc 1414 pfile_info->DeletePending = 0;
1da177e4 1415 }
1da177e4 1416 }
a5a2b489 1417
1da177e4
LT
1418 cifs_buf_release(pSMB);
1419 if (rc == -EAGAIN)
1420 goto openRetry;
1421 return rc;
1422}
1423
1da177e4 1424int
50c2f753
SF
1425CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1426 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1427 char **buf, int *pbuf_type)
1da177e4
LT
1428{
1429 int rc = -EACCES;
1430 READ_REQ *pSMB = NULL;
1431 READ_RSP *pSMBr = NULL;
1432 char *pReadData = NULL;
bfa0d75a 1433 int wct;
ec637e3f
SF
1434 int resp_buf_type = 0;
1435 struct kvec iov[1];
1da177e4 1436
790fe579
SF
1437 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1438 if (tcon->ses->capabilities & CAP_LARGE_FILES)
bfa0d75a
SF
1439 wct = 12;
1440 else
1441 wct = 10; /* old style read */
1da177e4
LT
1442
1443 *nbytes = 0;
ec637e3f 1444 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1da177e4
LT
1445 if (rc)
1446 return rc;
1447
1448 /* tcon and ses pointer are checked in smb_init */
1449 if (tcon->ses->server == NULL)
1450 return -ECONNABORTED;
1451
ec637e3f 1452 pSMB->AndXCommand = 0xFF; /* none */
1da177e4
LT
1453 pSMB->Fid = netfid;
1454 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
790fe579 1455 if (wct == 12)
bfa0d75a 1456 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
790fe579 1457 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
ec637e3f 1458 return -EIO;
bfa0d75a 1459
1da177e4
LT
1460 pSMB->Remaining = 0;
1461 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1462 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
790fe579 1463 if (wct == 12)
bfa0d75a
SF
1464 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1465 else {
1466 /* old style read */
50c2f753 1467 struct smb_com_readx_req *pSMBW =
bfa0d75a 1468 (struct smb_com_readx_req *)pSMB;
ec637e3f 1469 pSMBW->ByteCount = 0;
bfa0d75a 1470 }
ec637e3f
SF
1471
1472 iov[0].iov_base = (char *)pSMB;
1473 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
a761ac57 1474 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
133672ef 1475 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
a4544347 1476 cifs_stats_inc(&tcon->num_reads);
ec637e3f 1477 pSMBr = (READ_RSP *)iov[0].iov_base;
1da177e4
LT
1478 if (rc) {
1479 cERROR(1, ("Send error in read = %d", rc));
1480 } else {
1481 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1482 data_length = data_length << 16;
1483 data_length += le16_to_cpu(pSMBr->DataLength);
1484 *nbytes = data_length;
1485
1486 /*check that DataLength would not go beyond end of SMB */
ec637e3f 1487 if ((data_length > CIFSMaxBufSize)
1da177e4 1488 || (data_length > count)) {
50c2f753
SF
1489 cFYI(1, ("bad length %d for count %d",
1490 data_length, count));
1da177e4
LT
1491 rc = -EIO;
1492 *nbytes = 0;
1493 } else {
ec637e3f 1494 pReadData = (char *) (&pSMBr->hdr.Protocol) +
26f57364
SF
1495 le16_to_cpu(pSMBr->DataOffset);
1496/* if (rc = copy_to_user(buf, pReadData, data_length)) {
50c2f753
SF
1497 cERROR(1,("Faulting on read rc = %d",rc));
1498 rc = -EFAULT;
26f57364 1499 }*/ /* can not use copy_to_user when using page cache*/
790fe579 1500 if (*buf)
50c2f753 1501 memcpy(*buf, pReadData, data_length);
1da177e4
LT
1502 }
1503 }
1da177e4 1504
4b8f930f 1505/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
790fe579
SF
1506 if (*buf) {
1507 if (resp_buf_type == CIFS_SMALL_BUFFER)
ec637e3f 1508 cifs_small_buf_release(iov[0].iov_base);
790fe579 1509 else if (resp_buf_type == CIFS_LARGE_BUFFER)
ec637e3f 1510 cifs_buf_release(iov[0].iov_base);
790fe579 1511 } else if (resp_buf_type != CIFS_NO_BUFFER) {
50c2f753
SF
1512 /* return buffer to caller to free */
1513 *buf = iov[0].iov_base;
790fe579 1514 if (resp_buf_type == CIFS_SMALL_BUFFER)
ec637e3f 1515 *pbuf_type = CIFS_SMALL_BUFFER;
790fe579 1516 else if (resp_buf_type == CIFS_LARGE_BUFFER)
ec637e3f 1517 *pbuf_type = CIFS_LARGE_BUFFER;
6cec2aed 1518 } /* else no valid buffer on return - leave as null */
ec637e3f
SF
1519
1520 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
1521 since file handle passed in no longer valid */
1522 return rc;
1523}
1524
ec637e3f 1525
1da177e4
LT
1526int
1527CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1528 const int netfid, const unsigned int count,
1529 const __u64 offset, unsigned int *nbytes, const char *buf,
50c2f753 1530 const char __user *ubuf, const int long_op)
1da177e4
LT
1531{
1532 int rc = -EACCES;
1533 WRITE_REQ *pSMB = NULL;
1534 WRITE_RSP *pSMBr = NULL;
1c955187 1535 int bytes_returned, wct;
1da177e4
LT
1536 __u32 bytes_sent;
1537 __u16 byte_count;
1538
61de800d 1539 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
790fe579 1540 if (tcon->ses == NULL)
1c955187
SF
1541 return -ECONNABORTED;
1542
790fe579 1543 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1c955187
SF
1544 wct = 14;
1545 else
1546 wct = 12;
1547
1548 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1da177e4
LT
1549 (void **) &pSMBr);
1550 if (rc)
1551 return rc;
1552 /* tcon and ses pointer are checked in smb_init */
1553 if (tcon->ses->server == NULL)
1554 return -ECONNABORTED;
1555
1556 pSMB->AndXCommand = 0xFF; /* none */
1557 pSMB->Fid = netfid;
1558 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
790fe579 1559 if (wct == 14)
1c955187 1560 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
790fe579 1561 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1c955187 1562 return -EIO;
50c2f753 1563
1da177e4
LT
1564 pSMB->Reserved = 0xFFFFFFFF;
1565 pSMB->WriteMode = 0;
1566 pSMB->Remaining = 0;
1567
50c2f753 1568 /* Can increase buffer size if buffer is big enough in some cases ie we
1da177e4
LT
1569 can send more if LARGE_WRITE_X capability returned by the server and if
1570 our buffer is big enough or if we convert to iovecs on socket writes
1571 and eliminate the copy to the CIFS buffer */
790fe579 1572 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1da177e4
LT
1573 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1574 } else {
1575 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1576 & ~0xFF;
1577 }
1578
1579 if (bytes_sent > count)
1580 bytes_sent = count;
1581 pSMB->DataOffset =
50c2f753 1582 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
790fe579 1583 if (buf)
50c2f753 1584 memcpy(pSMB->Data, buf, bytes_sent);
790fe579
SF
1585 else if (ubuf) {
1586 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1da177e4
LT
1587 cifs_buf_release(pSMB);
1588 return -EFAULT;
1589 }
e30dcf3a 1590 } else if (count != 0) {
1da177e4
LT
1591 /* No buffer */
1592 cifs_buf_release(pSMB);
1593 return -EINVAL;
e30dcf3a 1594 } /* else setting file size with write of zero bytes */
790fe579 1595 if (wct == 14)
e30dcf3a 1596 byte_count = bytes_sent + 1; /* pad */
ad7a2926 1597 else /* wct == 12 */
e30dcf3a 1598 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
ad7a2926 1599
1da177e4
LT
1600 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1601 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
e30dcf3a 1602 pSMB->hdr.smb_buf_length += byte_count;
1c955187 1603
790fe579 1604 if (wct == 14)
1c955187 1605 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753
SF
1606 else { /* old style write has byte count 4 bytes earlier
1607 so 4 bytes pad */
1608 struct smb_com_writex_req *pSMBW =
1c955187
SF
1609 (struct smb_com_writex_req *)pSMB;
1610 pSMBW->ByteCount = cpu_to_le16(byte_count);
1611 }
1da177e4
LT
1612
1613 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1614 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
a4544347 1615 cifs_stats_inc(&tcon->num_writes);
1da177e4
LT
1616 if (rc) {
1617 cFYI(1, ("Send error in write = %d", rc));
1618 *nbytes = 0;
1619 } else {
1620 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1621 *nbytes = (*nbytes) << 16;
1622 *nbytes += le16_to_cpu(pSMBr->Count);
1623 }
1624
1625 cifs_buf_release(pSMB);
1626
50c2f753 1627 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
1628 since file handle passed in no longer valid */
1629
1630 return rc;
1631}
1632
d6e04ae6
SF
1633int
1634CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1da177e4 1635 const int netfid, const unsigned int count,
3e84469d
SF
1636 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1637 int n_vec, const int long_op)
1da177e4
LT
1638{
1639 int rc = -EACCES;
1640 WRITE_REQ *pSMB = NULL;
ec637e3f 1641 int wct;
d6e04ae6 1642 int smb_hdr_len;
ec637e3f 1643 int resp_buf_type = 0;
1da177e4 1644
790fe579 1645 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
ff7feac9 1646
790fe579 1647 if (tcon->ses->capabilities & CAP_LARGE_FILES)
8cc64c6e
SF
1648 wct = 14;
1649 else
1650 wct = 12;
1651 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1da177e4
LT
1652 if (rc)
1653 return rc;
1da177e4
LT
1654 /* tcon and ses pointer are checked in smb_init */
1655 if (tcon->ses->server == NULL)
1656 return -ECONNABORTED;
1657
d6e04ae6 1658 pSMB->AndXCommand = 0xFF; /* none */
1da177e4
LT
1659 pSMB->Fid = netfid;
1660 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
790fe579 1661 if (wct == 14)
8cc64c6e 1662 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
790fe579 1663 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
8cc64c6e 1664 return -EIO;
1da177e4
LT
1665 pSMB->Reserved = 0xFFFFFFFF;
1666 pSMB->WriteMode = 0;
1667 pSMB->Remaining = 0;
d6e04ae6 1668
1da177e4 1669 pSMB->DataOffset =
50c2f753 1670 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1da177e4 1671
3e84469d
SF
1672 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1673 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
d6e04ae6 1674 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
790fe579 1675 if (wct == 14)
8cc64c6e
SF
1676 pSMB->hdr.smb_buf_length += count+1;
1677 else /* wct == 12 */
790fe579
SF
1678 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1679 if (wct == 14)
8cc64c6e
SF
1680 pSMB->ByteCount = cpu_to_le16(count + 1);
1681 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
50c2f753 1682 struct smb_com_writex_req *pSMBW =
8cc64c6e
SF
1683 (struct smb_com_writex_req *)pSMB;
1684 pSMBW->ByteCount = cpu_to_le16(count + 5);
1685 }
3e84469d 1686 iov[0].iov_base = pSMB;
790fe579 1687 if (wct == 14)
ec637e3f
SF
1688 iov[0].iov_len = smb_hdr_len + 4;
1689 else /* wct == 12 pad bigger by four bytes */
1690 iov[0].iov_len = smb_hdr_len + 8;
50c2f753 1691
1da177e4 1692
ec637e3f 1693 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
133672ef 1694 long_op);
a4544347 1695 cifs_stats_inc(&tcon->num_writes);
1da177e4 1696 if (rc) {
8cc64c6e 1697 cFYI(1, ("Send error Write2 = %d", rc));
1da177e4 1698 *nbytes = 0;
790fe579 1699 } else if (resp_buf_type == 0) {
ec637e3f
SF
1700 /* presumably this can not happen, but best to be safe */
1701 rc = -EIO;
1702 *nbytes = 0;
d6e04ae6 1703 } else {
ad7a2926 1704 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
d6e04ae6
SF
1705 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1706 *nbytes = (*nbytes) << 16;
1707 *nbytes += le16_to_cpu(pSMBr->Count);
50c2f753 1708 }
1da177e4 1709
4b8f930f 1710/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
790fe579 1711 if (resp_buf_type == CIFS_SMALL_BUFFER)
ec637e3f 1712 cifs_small_buf_release(iov[0].iov_base);
790fe579 1713 else if (resp_buf_type == CIFS_LARGE_BUFFER)
ec637e3f 1714 cifs_buf_release(iov[0].iov_base);
1da177e4 1715
50c2f753 1716 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
1717 since file handle passed in no longer valid */
1718
1719 return rc;
1720}
d6e04ae6
SF
1721
1722
1da177e4
LT
1723int
1724CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1725 const __u16 smb_file_id, const __u64 len,
1726 const __u64 offset, const __u32 numUnlock,
4b18f2a9 1727 const __u32 numLock, const __u8 lockType, const bool waitFlag)
1da177e4
LT
1728{
1729 int rc = 0;
1730 LOCK_REQ *pSMB = NULL;
aaa9bbe0 1731/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1da177e4
LT
1732 int bytes_returned;
1733 int timeout = 0;
1734 __u16 count;
1735
4b18f2a9 1736 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
46810cbf
SF
1737 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1738
1da177e4
LT
1739 if (rc)
1740 return rc;
1741
790fe579 1742 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
133672ef 1743 timeout = CIFS_ASYNC_OP; /* no response expected */
1da177e4 1744 pSMB->Timeout = 0;
4b18f2a9 1745 } else if (waitFlag) {
133672ef 1746 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1da177e4
LT
1747 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1748 } else {
1749 pSMB->Timeout = 0;
1750 }
1751
1752 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1753 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1754 pSMB->LockType = lockType;
1755 pSMB->AndXCommand = 0xFF; /* none */
1756 pSMB->Fid = smb_file_id; /* netfid stays le */
1757
790fe579 1758 if ((numLock != 0) || (numUnlock != 0)) {
1da177e4
LT
1759 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1760 /* BB where to store pid high? */
1761 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1762 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1763 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1764 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1765 count = sizeof(LOCKING_ANDX_RANGE);
1766 } else {
1767 /* oplock break */
1768 count = 0;
1769 }
1770 pSMB->hdr.smb_buf_length += count;
1771 pSMB->ByteCount = cpu_to_le16(count);
1772
7ee1af76
JA
1773 if (waitFlag) {
1774 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
aaa9bbe0 1775 (struct smb_hdr *) pSMB, &bytes_returned);
133672ef 1776 cifs_small_buf_release(pSMB);
7ee1af76 1777 } else {
133672ef
SF
1778 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1779 timeout);
1780 /* SMB buffer freed by function above */
7ee1af76 1781 }
a4544347 1782 cifs_stats_inc(&tcon->num_locks);
ad7a2926 1783 if (rc)
1da177e4 1784 cFYI(1, ("Send error in Lock = %d", rc));
1da177e4 1785
50c2f753 1786 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
1787 since file handle passed in no longer valid */
1788 return rc;
1789}
1790
08547b03
SF
1791int
1792CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1793 const __u16 smb_file_id, const int get_flag, const __u64 len,
50c2f753 1794 struct file_lock *pLockData, const __u16 lock_type,
4b18f2a9 1795 const bool waitFlag)
08547b03
SF
1796{
1797 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1798 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
08547b03
SF
1799 struct cifs_posix_lock *parm_data;
1800 int rc = 0;
3a5ff61c 1801 int timeout = 0;
08547b03 1802 int bytes_returned = 0;
133672ef 1803 int resp_buf_type = 0;
08547b03 1804 __u16 params, param_offset, offset, byte_count, count;
133672ef 1805 struct kvec iov[1];
08547b03
SF
1806
1807 cFYI(1, ("Posix Lock"));
fc94cdb9 1808
790fe579 1809 if (pLockData == NULL)
ed5f0370 1810 return -EINVAL;
fc94cdb9 1811
08547b03
SF
1812 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1813
1814 if (rc)
1815 return rc;
1816
1817 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1818
50c2f753 1819 params = 6;
08547b03
SF
1820 pSMB->MaxSetupCount = 0;
1821 pSMB->Reserved = 0;
1822 pSMB->Flags = 0;
08547b03
SF
1823 pSMB->Reserved2 = 0;
1824 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1825 offset = param_offset + params;
1826
08547b03
SF
1827 count = sizeof(struct cifs_posix_lock);
1828 pSMB->MaxParameterCount = cpu_to_le16(2);
ad7a2926 1829 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
08547b03
SF
1830 pSMB->SetupCount = 1;
1831 pSMB->Reserved3 = 0;
790fe579 1832 if (get_flag)
08547b03
SF
1833 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1834 else
1835 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1836 byte_count = 3 /* pad */ + params + count;
1837 pSMB->DataCount = cpu_to_le16(count);
1838 pSMB->ParameterCount = cpu_to_le16(params);
1839 pSMB->TotalDataCount = pSMB->DataCount;
1840 pSMB->TotalParameterCount = pSMB->ParameterCount;
1841 pSMB->ParameterOffset = cpu_to_le16(param_offset);
50c2f753 1842 parm_data = (struct cifs_posix_lock *)
08547b03
SF
1843 (((char *) &pSMB->hdr.Protocol) + offset);
1844
1845 parm_data->lock_type = cpu_to_le16(lock_type);
790fe579 1846 if (waitFlag) {
133672ef 1847 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
cec6815a 1848 parm_data->lock_flags = cpu_to_le16(1);
3a5ff61c
SF
1849 pSMB->Timeout = cpu_to_le32(-1);
1850 } else
1851 pSMB->Timeout = 0;
1852
08547b03 1853 parm_data->pid = cpu_to_le32(current->tgid);
fc94cdb9 1854 parm_data->start = cpu_to_le64(pLockData->fl_start);
cec6815a 1855 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
08547b03
SF
1856
1857 pSMB->DataOffset = cpu_to_le16(offset);
f26282c9 1858 pSMB->Fid = smb_file_id;
08547b03
SF
1859 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1860 pSMB->Reserved4 = 0;
1861 pSMB->hdr.smb_buf_length += byte_count;
1862 pSMB->ByteCount = cpu_to_le16(byte_count);
7ee1af76
JA
1863 if (waitFlag) {
1864 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1865 (struct smb_hdr *) pSMBr, &bytes_returned);
1866 } else {
133672ef
SF
1867 iov[0].iov_base = (char *)pSMB;
1868 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1869 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1870 &resp_buf_type, timeout);
1871 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1872 not try to free it twice below on exit */
1873 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
7ee1af76
JA
1874 }
1875
08547b03
SF
1876 if (rc) {
1877 cFYI(1, ("Send error in Posix Lock = %d", rc));
fc94cdb9
SF
1878 } else if (get_flag) {
1879 /* lock structure can be returned on get */
1880 __u16 data_offset;
1881 __u16 data_count;
1882 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1883
1884 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1885 rc = -EIO; /* bad smb */
1886 goto plk_err_exit;
1887 }
790fe579 1888 if (pLockData == NULL) {
fc94cdb9
SF
1889 rc = -EINVAL;
1890 goto plk_err_exit;
1891 }
1892 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1893 data_count = le16_to_cpu(pSMBr->t2.DataCount);
790fe579 1894 if (data_count < sizeof(struct cifs_posix_lock)) {
fc94cdb9
SF
1895 rc = -EIO;
1896 goto plk_err_exit;
1897 }
1898 parm_data = (struct cifs_posix_lock *)
1899 ((char *)&pSMBr->hdr.Protocol + data_offset);
790fe579 1900 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
fc94cdb9 1901 pLockData->fl_type = F_UNLCK;
08547b03 1902 }
50c2f753 1903
fc94cdb9 1904plk_err_exit:
08547b03
SF
1905 if (pSMB)
1906 cifs_small_buf_release(pSMB);
1907
133672ef
SF
1908 if (resp_buf_type == CIFS_SMALL_BUFFER)
1909 cifs_small_buf_release(iov[0].iov_base);
1910 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1911 cifs_buf_release(iov[0].iov_base);
1912
08547b03
SF
1913 /* Note: On -EAGAIN error only caller can retry on handle based calls
1914 since file handle passed in no longer valid */
1915
1916 return rc;
1917}
1918
1919
1da177e4
LT
1920int
1921CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1922{
1923 int rc = 0;
1924 CLOSE_REQ *pSMB = NULL;
1da177e4
LT
1925 cFYI(1, ("In CIFSSMBClose"));
1926
1927/* do not retry on dead session on close */
1928 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
790fe579 1929 if (rc == -EAGAIN)
1da177e4
LT
1930 return 0;
1931 if (rc)
1932 return rc;
1933
1da177e4 1934 pSMB->FileID = (__u16) smb_file_id;
b815f1e5 1935 pSMB->LastWriteTime = 0xFFFFFFFF;
1da177e4 1936 pSMB->ByteCount = 0;
133672ef 1937 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
a4544347 1938 cifs_stats_inc(&tcon->num_closes);
1da177e4 1939 if (rc) {
790fe579 1940 if (rc != -EINTR) {
1da177e4
LT
1941 /* EINTR is expected when user ctl-c to kill app */
1942 cERROR(1, ("Send error in Close = %d", rc));
1943 }
1944 }
1945
1da177e4 1946 /* Since session is dead, file will be closed on server already */
790fe579 1947 if (rc == -EAGAIN)
1da177e4
LT
1948 rc = 0;
1949
1950 return rc;
1951}
1952
1953int
1954CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1955 const char *fromName, const char *toName,
737b758c 1956 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1957{
1958 int rc = 0;
1959 RENAME_REQ *pSMB = NULL;
1960 RENAME_RSP *pSMBr = NULL;
1961 int bytes_returned;
1962 int name_len, name_len2;
1963 __u16 count;
1964
1965 cFYI(1, ("In CIFSSMBRename"));
1966renameRetry:
1967 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1968 (void **) &pSMBr);
1969 if (rc)
1970 return rc;
1971
1972 pSMB->BufferFormat = 0x04;
1973 pSMB->SearchAttributes =
1974 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1975 ATTR_DIRECTORY);
1976
1977 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1978 name_len =
50c2f753 1979 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
737b758c 1980 PATH_MAX, nls_codepage, remap);
1da177e4
LT
1981 name_len++; /* trailing null */
1982 name_len *= 2;
1983 pSMB->OldFileName[name_len] = 0x04; /* pad */
1984 /* protocol requires ASCII signature byte on Unicode string */
1985 pSMB->OldFileName[name_len + 1] = 0x00;
1986 name_len2 =
582d21e5 1987 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
737b758c 1988 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1989 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1990 name_len2 *= 2; /* convert to bytes */
50c2f753 1991 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
1992 name_len = strnlen(fromName, PATH_MAX);
1993 name_len++; /* trailing null */
1994 strncpy(pSMB->OldFileName, fromName, name_len);
1995 name_len2 = strnlen(toName, PATH_MAX);
1996 name_len2++; /* trailing null */
1997 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1998 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1999 name_len2++; /* trailing null */
2000 name_len2++; /* signature byte */
2001 }
2002
2003 count = 1 /* 1st signature byte */ + name_len + name_len2;
2004 pSMB->hdr.smb_buf_length += count;
2005 pSMB->ByteCount = cpu_to_le16(count);
2006
2007 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2008 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2009 cifs_stats_inc(&tcon->num_renames);
ad7a2926 2010 if (rc)
1da177e4 2011 cFYI(1, ("Send error in rename = %d", rc));
1da177e4 2012
1da177e4
LT
2013 cifs_buf_release(pSMB);
2014
2015 if (rc == -EAGAIN)
2016 goto renameRetry;
2017
2018 return rc;
2019}
2020
50c2f753 2021int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
391e5755 2022 int netfid, const char *target_name,
50c2f753 2023 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2024{
2025 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2026 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
50c2f753 2027 struct set_file_rename *rename_info;
1da177e4
LT
2028 char *data_offset;
2029 char dummy_string[30];
2030 int rc = 0;
2031 int bytes_returned = 0;
2032 int len_of_str;
2033 __u16 params, param_offset, offset, count, byte_count;
2034
2035 cFYI(1, ("Rename to File by handle"));
2036 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2037 (void **) &pSMBr);
2038 if (rc)
2039 return rc;
2040
2041 params = 6;
2042 pSMB->MaxSetupCount = 0;
2043 pSMB->Reserved = 0;
2044 pSMB->Flags = 0;
2045 pSMB->Timeout = 0;
2046 pSMB->Reserved2 = 0;
2047 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2048 offset = param_offset + params;
2049
2050 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2051 rename_info = (struct set_file_rename *) data_offset;
2052 pSMB->MaxParameterCount = cpu_to_le16(2);
ad7a2926 2053 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1da177e4
LT
2054 pSMB->SetupCount = 1;
2055 pSMB->Reserved3 = 0;
2056 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2057 byte_count = 3 /* pad */ + params;
2058 pSMB->ParameterCount = cpu_to_le16(params);
2059 pSMB->TotalParameterCount = pSMB->ParameterCount;
2060 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2061 pSMB->DataOffset = cpu_to_le16(offset);
2062 /* construct random name ".cifs_tmp<inodenum><mid>" */
2063 rename_info->overwrite = cpu_to_le32(1);
2064 rename_info->root_fid = 0;
2065 /* unicode only call */
790fe579 2066 if (target_name == NULL) {
50c2f753
SF
2067 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2068 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
737b758c 2069 dummy_string, 24, nls_codepage, remap);
1da177e4 2070 } else {
b1a45695 2071 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
50c2f753
SF
2072 target_name, PATH_MAX, nls_codepage,
2073 remap);
1da177e4
LT
2074 }
2075 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
391e5755 2076 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
1da177e4
LT
2077 byte_count += count;
2078 pSMB->DataCount = cpu_to_le16(count);
2079 pSMB->TotalDataCount = pSMB->DataCount;
2080 pSMB->Fid = netfid;
2081 pSMB->InformationLevel =
2082 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2083 pSMB->Reserved4 = 0;
2084 pSMB->hdr.smb_buf_length += byte_count;
2085 pSMB->ByteCount = cpu_to_le16(byte_count);
2086 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
50c2f753 2087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2088 cifs_stats_inc(&pTcon->num_t2renames);
ad7a2926 2089 if (rc)
790fe579 2090 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
a5a2b489 2091
1da177e4
LT
2092 cifs_buf_release(pSMB);
2093
2094 /* Note: On -EAGAIN error only caller can retry on handle based calls
2095 since file handle passed in no longer valid */
2096
2097 return rc;
2098}
2099
2100int
50c2f753
SF
2101CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2102 const __u16 target_tid, const char *toName, const int flags,
2103 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2104{
2105 int rc = 0;
2106 COPY_REQ *pSMB = NULL;
2107 COPY_RSP *pSMBr = NULL;
2108 int bytes_returned;
2109 int name_len, name_len2;
2110 __u16 count;
2111
2112 cFYI(1, ("In CIFSSMBCopy"));
2113copyRetry:
2114 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2115 (void **) &pSMBr);
2116 if (rc)
2117 return rc;
2118
2119 pSMB->BufferFormat = 0x04;
2120 pSMB->Tid2 = target_tid;
2121
2122 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2123
2124 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
50c2f753 2125 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
737b758c
SF
2126 fromName, PATH_MAX, nls_codepage,
2127 remap);
1da177e4
LT
2128 name_len++; /* trailing null */
2129 name_len *= 2;
2130 pSMB->OldFileName[name_len] = 0x04; /* pad */
2131 /* protocol requires ASCII signature byte on Unicode string */
2132 pSMB->OldFileName[name_len + 1] = 0x00;
50c2f753
SF
2133 name_len2 =
2134 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
737b758c 2135 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
2136 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2137 name_len2 *= 2; /* convert to bytes */
50c2f753 2138 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2139 name_len = strnlen(fromName, PATH_MAX);
2140 name_len++; /* trailing null */
2141 strncpy(pSMB->OldFileName, fromName, name_len);
2142 name_len2 = strnlen(toName, PATH_MAX);
2143 name_len2++; /* trailing null */
2144 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2145 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2146 name_len2++; /* trailing null */
2147 name_len2++; /* signature byte */
2148 }
2149
2150 count = 1 /* 1st signature byte */ + name_len + name_len2;
2151 pSMB->hdr.smb_buf_length += count;
2152 pSMB->ByteCount = cpu_to_le16(count);
2153
2154 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2155 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2156 if (rc) {
2157 cFYI(1, ("Send error in copy = %d with %d files copied",
2158 rc, le16_to_cpu(pSMBr->CopyCount)));
2159 }
0d817bc0 2160 cifs_buf_release(pSMB);
1da177e4
LT
2161
2162 if (rc == -EAGAIN)
2163 goto copyRetry;
2164
2165 return rc;
2166}
2167
2168int
2169CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2170 const char *fromName, const char *toName,
2171 const struct nls_table *nls_codepage)
2172{
2173 TRANSACTION2_SPI_REQ *pSMB = NULL;
2174 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2175 char *data_offset;
2176 int name_len;
2177 int name_len_target;
2178 int rc = 0;
2179 int bytes_returned = 0;
2180 __u16 params, param_offset, offset, byte_count;
2181
2182 cFYI(1, ("In Symlink Unix style"));
2183createSymLinkRetry:
2184 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2185 (void **) &pSMBr);
2186 if (rc)
2187 return rc;
2188
2189 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2190 name_len =
e89dc920 2191 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1da177e4
LT
2192 /* find define for this maxpathcomponent */
2193 , nls_codepage);
2194 name_len++; /* trailing null */
2195 name_len *= 2;
2196
50c2f753 2197 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2198 name_len = strnlen(fromName, PATH_MAX);
2199 name_len++; /* trailing null */
2200 strncpy(pSMB->FileName, fromName, name_len);
2201 }
2202 params = 6 + name_len;
2203 pSMB->MaxSetupCount = 0;
2204 pSMB->Reserved = 0;
2205 pSMB->Flags = 0;
2206 pSMB->Timeout = 0;
2207 pSMB->Reserved2 = 0;
2208 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 2209 InformationLevel) - 4;
1da177e4
LT
2210 offset = param_offset + params;
2211
2212 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2213 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2214 name_len_target =
e89dc920 2215 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1da177e4
LT
2216 /* find define for this maxpathcomponent */
2217 , nls_codepage);
2218 name_len_target++; /* trailing null */
2219 name_len_target *= 2;
50c2f753 2220 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2221 name_len_target = strnlen(toName, PATH_MAX);
2222 name_len_target++; /* trailing null */
2223 strncpy(data_offset, toName, name_len_target);
2224 }
2225
2226 pSMB->MaxParameterCount = cpu_to_le16(2);
2227 /* BB find exact max on data count below from sess */
2228 pSMB->MaxDataCount = cpu_to_le16(1000);
2229 pSMB->SetupCount = 1;
2230 pSMB->Reserved3 = 0;
2231 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2232 byte_count = 3 /* pad */ + params + name_len_target;
2233 pSMB->DataCount = cpu_to_le16(name_len_target);
2234 pSMB->ParameterCount = cpu_to_le16(params);
2235 pSMB->TotalDataCount = pSMB->DataCount;
2236 pSMB->TotalParameterCount = pSMB->ParameterCount;
2237 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2238 pSMB->DataOffset = cpu_to_le16(offset);
2239 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2240 pSMB->Reserved4 = 0;
2241 pSMB->hdr.smb_buf_length += byte_count;
2242 pSMB->ByteCount = cpu_to_le16(byte_count);
2243 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2244 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2245 cifs_stats_inc(&tcon->num_symlinks);
ad7a2926 2246 if (rc)
2d785a50 2247 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
1da177e4 2248
0d817bc0 2249 cifs_buf_release(pSMB);
1da177e4
LT
2250
2251 if (rc == -EAGAIN)
2252 goto createSymLinkRetry;
2253
2254 return rc;
2255}
2256
2257int
2258CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2259 const char *fromName, const char *toName,
737b758c 2260 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2261{
2262 TRANSACTION2_SPI_REQ *pSMB = NULL;
2263 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2264 char *data_offset;
2265 int name_len;
2266 int name_len_target;
2267 int rc = 0;
2268 int bytes_returned = 0;
2269 __u16 params, param_offset, offset, byte_count;
2270
2271 cFYI(1, ("In Create Hard link Unix style"));
2272createHardLinkRetry:
2273 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2274 (void **) &pSMBr);
2275 if (rc)
2276 return rc;
2277
2278 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
b1a45695 2279 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
737b758c 2280 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2281 name_len++; /* trailing null */
2282 name_len *= 2;
2283
50c2f753 2284 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2285 name_len = strnlen(toName, PATH_MAX);
2286 name_len++; /* trailing null */
2287 strncpy(pSMB->FileName, toName, name_len);
2288 }
2289 params = 6 + name_len;
2290 pSMB->MaxSetupCount = 0;
2291 pSMB->Reserved = 0;
2292 pSMB->Flags = 0;
2293 pSMB->Timeout = 0;
2294 pSMB->Reserved2 = 0;
2295 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 2296 InformationLevel) - 4;
1da177e4
LT
2297 offset = param_offset + params;
2298
2299 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2300 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2301 name_len_target =
b1a45695 2302 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
737b758c 2303 nls_codepage, remap);
1da177e4
LT
2304 name_len_target++; /* trailing null */
2305 name_len_target *= 2;
50c2f753 2306 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2307 name_len_target = strnlen(fromName, PATH_MAX);
2308 name_len_target++; /* trailing null */
2309 strncpy(data_offset, fromName, name_len_target);
2310 }
2311
2312 pSMB->MaxParameterCount = cpu_to_le16(2);
2313 /* BB find exact max on data count below from sess*/
2314 pSMB->MaxDataCount = cpu_to_le16(1000);
2315 pSMB->SetupCount = 1;
2316 pSMB->Reserved3 = 0;
2317 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2318 byte_count = 3 /* pad */ + params + name_len_target;
2319 pSMB->ParameterCount = cpu_to_le16(params);
2320 pSMB->TotalParameterCount = pSMB->ParameterCount;
2321 pSMB->DataCount = cpu_to_le16(name_len_target);
2322 pSMB->TotalDataCount = pSMB->DataCount;
2323 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2324 pSMB->DataOffset = cpu_to_le16(offset);
2325 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2326 pSMB->Reserved4 = 0;
2327 pSMB->hdr.smb_buf_length += byte_count;
2328 pSMB->ByteCount = cpu_to_le16(byte_count);
2329 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2330 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2331 cifs_stats_inc(&tcon->num_hardlinks);
ad7a2926 2332 if (rc)
1da177e4 2333 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1da177e4
LT
2334
2335 cifs_buf_release(pSMB);
2336 if (rc == -EAGAIN)
2337 goto createHardLinkRetry;
2338
2339 return rc;
2340}
2341
2342int
2343CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2344 const char *fromName, const char *toName,
737b758c 2345 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2346{
2347 int rc = 0;
2348 NT_RENAME_REQ *pSMB = NULL;
2349 RENAME_RSP *pSMBr = NULL;
2350 int bytes_returned;
2351 int name_len, name_len2;
2352 __u16 count;
2353
2354 cFYI(1, ("In CIFSCreateHardLink"));
2355winCreateHardLinkRetry:
2356
2357 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2358 (void **) &pSMBr);
2359 if (rc)
2360 return rc;
2361
2362 pSMB->SearchAttributes =
2363 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2364 ATTR_DIRECTORY);
2365 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2366 pSMB->ClusterCount = 0;
2367
2368 pSMB->BufferFormat = 0x04;
2369
2370 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2371 name_len =
b1a45695 2372 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
737b758c 2373 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2374 name_len++; /* trailing null */
2375 name_len *= 2;
2376 pSMB->OldFileName[name_len] = 0; /* pad */
50c2f753 2377 pSMB->OldFileName[name_len + 1] = 0x04;
1da177e4 2378 name_len2 =
50c2f753 2379 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
737b758c 2380 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
2381 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2382 name_len2 *= 2; /* convert to bytes */
50c2f753 2383 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2384 name_len = strnlen(fromName, PATH_MAX);
2385 name_len++; /* trailing null */
2386 strncpy(pSMB->OldFileName, fromName, name_len);
2387 name_len2 = strnlen(toName, PATH_MAX);
2388 name_len2++; /* trailing null */
2389 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2390 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2391 name_len2++; /* trailing null */
2392 name_len2++; /* signature byte */
2393 }
2394
2395 count = 1 /* string type byte */ + name_len + name_len2;
2396 pSMB->hdr.smb_buf_length += count;
2397 pSMB->ByteCount = cpu_to_le16(count);
2398
2399 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2400 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2401 cifs_stats_inc(&tcon->num_hardlinks);
ad7a2926 2402 if (rc)
1da177e4 2403 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
ad7a2926 2404
1da177e4
LT
2405 cifs_buf_release(pSMB);
2406 if (rc == -EAGAIN)
2407 goto winCreateHardLinkRetry;
2408
2409 return rc;
2410}
2411
2412int
2413CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2414 const unsigned char *searchName,
2415 char *symlinkinfo, const int buflen,
2416 const struct nls_table *nls_codepage)
2417{
2418/* SMB_QUERY_FILE_UNIX_LINK */
2419 TRANSACTION2_QPI_REQ *pSMB = NULL;
2420 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2421 int rc = 0;
2422 int bytes_returned;
2423 int name_len;
2424 __u16 params, byte_count;
2425
2426 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2427
2428querySymLinkRetry:
2429 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2430 (void **) &pSMBr);
2431 if (rc)
2432 return rc;
2433
2434 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2435 name_len =
50c2f753
SF
2436 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2437 PATH_MAX, nls_codepage);
1da177e4
LT
2438 name_len++; /* trailing null */
2439 name_len *= 2;
50c2f753 2440 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2441 name_len = strnlen(searchName, PATH_MAX);
2442 name_len++; /* trailing null */
2443 strncpy(pSMB->FileName, searchName, name_len);
2444 }
2445
2446 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2447 pSMB->TotalDataCount = 0;
2448 pSMB->MaxParameterCount = cpu_to_le16(2);
2449 /* BB find exact max data count below from sess structure BB */
2450 pSMB->MaxDataCount = cpu_to_le16(4000);
2451 pSMB->MaxSetupCount = 0;
2452 pSMB->Reserved = 0;
2453 pSMB->Flags = 0;
2454 pSMB->Timeout = 0;
2455 pSMB->Reserved2 = 0;
2456 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 2457 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
2458 pSMB->DataCount = 0;
2459 pSMB->DataOffset = 0;
2460 pSMB->SetupCount = 1;
2461 pSMB->Reserved3 = 0;
2462 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2463 byte_count = params + 1 /* pad */ ;
2464 pSMB->TotalParameterCount = cpu_to_le16(params);
2465 pSMB->ParameterCount = pSMB->TotalParameterCount;
2466 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2467 pSMB->Reserved4 = 0;
2468 pSMB->hdr.smb_buf_length += byte_count;
2469 pSMB->ByteCount = cpu_to_le16(byte_count);
2470
2471 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2472 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2473 if (rc) {
2474 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2475 } else {
2476 /* decode response */
2477
2478 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2479 if (rc || (pSMBr->ByteCount < 2))
2480 /* BB also check enough total bytes returned */
2481 rc = -EIO; /* bad smb */
2482 else {
2483 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2484 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2485
2486 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2487 name_len = UniStrnlen((wchar_t *) ((char *)
50c2f753
SF
2488 &pSMBr->hdr.Protocol + data_offset),
2489 min_t(const int, buflen, count) / 2);
737b758c 2490 /* BB FIXME investigate remapping reserved chars here */
1da177e4 2491 cifs_strfromUCS_le(symlinkinfo,
50c2f753
SF
2492 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2493 + data_offset),
1da177e4
LT
2494 name_len, nls_codepage);
2495 } else {
2496 strncpy(symlinkinfo,
50c2f753 2497 (char *) &pSMBr->hdr.Protocol +
1da177e4
LT
2498 data_offset,
2499 min_t(const int, buflen, count));
2500 }
2501 symlinkinfo[buflen] = 0;
2502 /* just in case so calling code does not go off the end of buffer */
2503 }
2504 }
2505 cifs_buf_release(pSMB);
2506 if (rc == -EAGAIN)
2507 goto querySymLinkRetry;
2508 return rc;
2509}
2510
c9489779 2511#ifdef CONFIG_CIFS_EXPERIMENTAL
0a4b92c0
SF
2512/* Initialize NT TRANSACT SMB into small smb request buffer.
2513 This assumes that all NT TRANSACTS that we init here have
2514 total parm and data under about 400 bytes (to fit in small cifs
2515 buffer size), which is the case so far, it easily fits. NB:
2516 Setup words themselves and ByteCount
2517 MaxSetupCount (size of returned setup area) and
2518 MaxParameterCount (returned parms size) must be set by caller */
50c2f753 2519static int
b9c7a2bb 2520smb_init_nttransact(const __u16 sub_command, const int setup_count,
0a4b92c0 2521 const int parm_len, struct cifsTconInfo *tcon,
50c2f753 2522 void **ret_buf)
0a4b92c0
SF
2523{
2524 int rc;
2525 __u32 temp_offset;
50c2f753 2526 struct smb_com_ntransact_req *pSMB;
0a4b92c0
SF
2527
2528 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2529 (void **)&pSMB);
2530 if (rc)
2531 return rc;
2532 *ret_buf = (void *)pSMB;
2533 pSMB->Reserved = 0;
2534 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2535 pSMB->TotalDataCount = 0;
2536 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2537 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2538 pSMB->ParameterCount = pSMB->TotalParameterCount;
2539 pSMB->DataCount = pSMB->TotalDataCount;
2540 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2541 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2542 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2543 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2544 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2545 pSMB->SubCommand = cpu_to_le16(sub_command);
2546 return 0;
2547}
2548
2549static int
50c2f753 2550validate_ntransact(char *buf, char **ppparm, char **ppdata,
b9c7a2bb 2551 __u32 *pparmlen, __u32 *pdatalen)
0a4b92c0 2552{
50c2f753 2553 char *end_of_smb;
0a4b92c0 2554 __u32 data_count, data_offset, parm_count, parm_offset;
50c2f753 2555 struct smb_com_ntransact_rsp *pSMBr;
0a4b92c0 2556
630f3f0c
SF
2557 *pdatalen = 0;
2558 *pparmlen = 0;
2559
790fe579 2560 if (buf == NULL)
0a4b92c0
SF
2561 return -EINVAL;
2562
2563 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2564
2565 /* ByteCount was converted from little endian in SendReceive */
50c2f753 2566 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
0a4b92c0
SF
2567 (char *)&pSMBr->ByteCount;
2568
0a4b92c0
SF
2569 data_offset = le32_to_cpu(pSMBr->DataOffset);
2570 data_count = le32_to_cpu(pSMBr->DataCount);
50c2f753 2571 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
0a4b92c0
SF
2572 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2573
2574 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2575 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2576
2577 /* should we also check that parm and data areas do not overlap? */
790fe579
SF
2578 if (*ppparm > end_of_smb) {
2579 cFYI(1, ("parms start after end of smb"));
0a4b92c0 2580 return -EINVAL;
790fe579
SF
2581 } else if (parm_count + *ppparm > end_of_smb) {
2582 cFYI(1, ("parm end after end of smb"));
0a4b92c0 2583 return -EINVAL;
790fe579
SF
2584 } else if (*ppdata > end_of_smb) {
2585 cFYI(1, ("data starts after end of smb"));
0a4b92c0 2586 return -EINVAL;
790fe579 2587 } else if (data_count + *ppdata > end_of_smb) {
26f57364 2588 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
50c2f753
SF
2589 *ppdata, data_count, (data_count + *ppdata),
2590 end_of_smb, pSMBr));
0a4b92c0 2591 return -EINVAL;
790fe579
SF
2592 } else if (parm_count + data_count > pSMBr->ByteCount) {
2593 cFYI(1, ("parm count and data count larger than SMB"));
0a4b92c0
SF
2594 return -EINVAL;
2595 }
630f3f0c
SF
2596 *pdatalen = data_count;
2597 *pparmlen = parm_count;
0a4b92c0
SF
2598 return 0;
2599}
c9489779 2600#endif /* CIFS_EXPERIMENTAL */
0a4b92c0 2601
1da177e4
LT
2602int
2603CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2604 const unsigned char *searchName,
50c2f753 2605 char *symlinkinfo, const int buflen, __u16 fid,
1da177e4
LT
2606 const struct nls_table *nls_codepage)
2607{
2608 int rc = 0;
2609 int bytes_returned;
2610 int name_len;
50c2f753
SF
2611 struct smb_com_transaction_ioctl_req *pSMB;
2612 struct smb_com_transaction_ioctl_rsp *pSMBr;
1da177e4
LT
2613
2614 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2615 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2616 (void **) &pSMBr);
2617 if (rc)
2618 return rc;
2619
2620 pSMB->TotalParameterCount = 0 ;
2621 pSMB->TotalDataCount = 0;
2622 pSMB->MaxParameterCount = cpu_to_le32(2);
2623 /* BB find exact data count max from sess structure BB */
0a4b92c0
SF
2624 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2625 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1da177e4
LT
2626 pSMB->MaxSetupCount = 4;
2627 pSMB->Reserved = 0;
2628 pSMB->ParameterOffset = 0;
2629 pSMB->DataCount = 0;
2630 pSMB->DataOffset = 0;
2631 pSMB->SetupCount = 4;
2632 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2633 pSMB->ParameterCount = pSMB->TotalParameterCount;
2634 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2635 pSMB->IsFsctl = 1; /* FSCTL */
2636 pSMB->IsRootFlag = 0;
2637 pSMB->Fid = fid; /* file handle always le */
2638 pSMB->ByteCount = 0;
2639
2640 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2641 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2642 if (rc) {
2643 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2644 } else { /* decode response */
2645 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2646 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2647 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2648 /* BB also check enough total bytes returned */
2649 rc = -EIO; /* bad smb */
2650 else {
790fe579 2651 if (data_count && (data_count < 2048)) {
50c2f753 2652 char *end_of_smb = 2 /* sizeof byte count */ +
0a4b92c0
SF
2653 pSMBr->ByteCount +
2654 (char *)&pSMBr->ByteCount;
1da177e4 2655
50c2f753
SF
2656 struct reparse_data *reparse_buf =
2657 (struct reparse_data *)
2658 ((char *)&pSMBr->hdr.Protocol
2659 + data_offset);
790fe579 2660 if ((char *)reparse_buf >= end_of_smb) {
1da177e4
LT
2661 rc = -EIO;
2662 goto qreparse_out;
2663 }
790fe579 2664 if ((reparse_buf->LinkNamesBuf +
1da177e4
LT
2665 reparse_buf->TargetNameOffset +
2666 reparse_buf->TargetNameLen) >
2667 end_of_smb) {
26f57364 2668 cFYI(1, ("reparse buf beyond SMB"));
1da177e4
LT
2669 rc = -EIO;
2670 goto qreparse_out;
2671 }
50c2f753 2672
1da177e4
LT
2673 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2674 name_len = UniStrnlen((wchar_t *)
50c2f753
SF
2675 (reparse_buf->LinkNamesBuf +
2676 reparse_buf->TargetNameOffset),
2677 min(buflen/2,
2678 reparse_buf->TargetNameLen / 2));
1da177e4 2679 cifs_strfromUCS_le(symlinkinfo,
50c2f753 2680 (__le16 *) (reparse_buf->LinkNamesBuf +
1da177e4
LT
2681 reparse_buf->TargetNameOffset),
2682 name_len, nls_codepage);
2683 } else { /* ASCII names */
50c2f753
SF
2684 strncpy(symlinkinfo,
2685 reparse_buf->LinkNamesBuf +
2686 reparse_buf->TargetNameOffset,
2687 min_t(const int, buflen,
2688 reparse_buf->TargetNameLen));
1da177e4
LT
2689 }
2690 } else {
2691 rc = -EIO;
63135e08
SF
2692 cFYI(1, ("Invalid return data count on "
2693 "get reparse info ioctl"));
1da177e4
LT
2694 }
2695 symlinkinfo[buflen] = 0; /* just in case so the caller
2696 does not go off the end of the buffer */
50c2f753 2697 cFYI(1, ("readlink result - %s", symlinkinfo));
1da177e4
LT
2698 }
2699 }
2700qreparse_out:
4a6d87f1 2701 cifs_buf_release(pSMB);
1da177e4
LT
2702
2703 /* Note: On -EAGAIN error only caller can retry on handle based calls
2704 since file handle passed in no longer valid */
2705
2706 return rc;
2707}
2708
2709#ifdef CONFIG_CIFS_POSIX
2710
2711/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
50c2f753
SF
2712static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2713 struct cifs_posix_ace *cifs_ace)
1da177e4
LT
2714{
2715 /* u8 cifs fields do not need le conversion */
ff7feac9
SF
2716 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2717 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2718 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
1da177e4
LT
2719 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2720
2721 return;
2722}
2723
2724/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
50c2f753
SF
2725static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2726 const int acl_type, const int size_of_data_area)
1da177e4
LT
2727{
2728 int size = 0;
2729 int i;
2730 __u16 count;
50c2f753
SF
2731 struct cifs_posix_ace *pACE;
2732 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2733 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
1da177e4
LT
2734
2735 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2736 return -EOPNOTSUPP;
2737
790fe579 2738 if (acl_type & ACL_TYPE_ACCESS) {
1da177e4
LT
2739 count = le16_to_cpu(cifs_acl->access_entry_count);
2740 pACE = &cifs_acl->ace_array[0];
2741 size = sizeof(struct cifs_posix_acl);
2742 size += sizeof(struct cifs_posix_ace) * count;
2743 /* check if we would go beyond end of SMB */
790fe579 2744 if (size_of_data_area < size) {
50c2f753
SF
2745 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2746 size_of_data_area, size));
1da177e4
LT
2747 return -EINVAL;
2748 }
790fe579 2749 } else if (acl_type & ACL_TYPE_DEFAULT) {
1da177e4
LT
2750 count = le16_to_cpu(cifs_acl->access_entry_count);
2751 size = sizeof(struct cifs_posix_acl);
2752 size += sizeof(struct cifs_posix_ace) * count;
2753/* skip past access ACEs to get to default ACEs */
2754 pACE = &cifs_acl->ace_array[count];
2755 count = le16_to_cpu(cifs_acl->default_entry_count);
2756 size += sizeof(struct cifs_posix_ace) * count;
2757 /* check if we would go beyond end of SMB */
790fe579 2758 if (size_of_data_area < size)
1da177e4
LT
2759 return -EINVAL;
2760 } else {
2761 /* illegal type */
2762 return -EINVAL;
2763 }
2764
2765 size = posix_acl_xattr_size(count);
790fe579 2766 if ((buflen == 0) || (local_acl == NULL)) {
50c2f753 2767 /* used to query ACL EA size */
790fe579 2768 } else if (size > buflen) {
1da177e4
LT
2769 return -ERANGE;
2770 } else /* buffer big enough */ {
ff7feac9 2771 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
50c2f753
SF
2772 for (i = 0; i < count ; i++) {
2773 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2774 pACE++;
1da177e4
LT
2775 }
2776 }
2777 return size;
2778}
2779
50c2f753
SF
2780static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2781 const posix_acl_xattr_entry *local_ace)
1da177e4
LT
2782{
2783 __u16 rc = 0; /* 0 = ACL converted ok */
2784
ff7feac9
SF
2785 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2786 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
1da177e4 2787 /* BB is there a better way to handle the large uid? */
790fe579 2788 if (local_ace->e_id == cpu_to_le32(-1)) {
1da177e4
LT
2789 /* Probably no need to le convert -1 on any arch but can not hurt */
2790 cifs_ace->cifs_uid = cpu_to_le64(-1);
50c2f753 2791 } else
ff7feac9 2792 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
50c2f753 2793 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
1da177e4
LT
2794 return rc;
2795}
2796
2797/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
50c2f753
SF
2798static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2799 const int buflen, const int acl_type)
1da177e4
LT
2800{
2801 __u16 rc = 0;
50c2f753
SF
2802 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2803 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
1da177e4
LT
2804 int count;
2805 int i;
2806
790fe579 2807 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1da177e4
LT
2808 return 0;
2809
2810 count = posix_acl_xattr_count((size_t)buflen);
c18c842b 2811 cFYI(1, ("setting acl with %d entries from buf of length %d and "
63135e08 2812 "version of %d",
ff7feac9 2813 count, buflen, le32_to_cpu(local_acl->a_version)));
790fe579 2814 if (le32_to_cpu(local_acl->a_version) != 2) {
50c2f753 2815 cFYI(1, ("unknown POSIX ACL version %d",
ff7feac9 2816 le32_to_cpu(local_acl->a_version)));
1da177e4
LT
2817 return 0;
2818 }
2819 cifs_acl->version = cpu_to_le16(1);
790fe579 2820 if (acl_type == ACL_TYPE_ACCESS)
ff7feac9 2821 cifs_acl->access_entry_count = cpu_to_le16(count);
790fe579 2822 else if (acl_type == ACL_TYPE_DEFAULT)
ff7feac9 2823 cifs_acl->default_entry_count = cpu_to_le16(count);
1da177e4 2824 else {
50c2f753 2825 cFYI(1, ("unknown ACL type %d", acl_type));
1da177e4
LT
2826 return 0;
2827 }
50c2f753 2828 for (i = 0; i < count; i++) {
1da177e4
LT
2829 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2830 &local_acl->a_entries[i]);
790fe579 2831 if (rc != 0) {
1da177e4
LT
2832 /* ACE not converted */
2833 break;
2834 }
2835 }
790fe579 2836 if (rc == 0) {
1da177e4
LT
2837 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2838 rc += sizeof(struct cifs_posix_acl);
2839 /* BB add check to make sure ACL does not overflow SMB */
2840 }
2841 return rc;
2842}
2843
2844int
2845CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
50c2f753
SF
2846 const unsigned char *searchName,
2847 char *acl_inf, const int buflen, const int acl_type,
2848 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2849{
2850/* SMB_QUERY_POSIX_ACL */
2851 TRANSACTION2_QPI_REQ *pSMB = NULL;
2852 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2853 int rc = 0;
2854 int bytes_returned;
2855 int name_len;
2856 __u16 params, byte_count;
50c2f753 2857
1da177e4
LT
2858 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2859
2860queryAclRetry:
2861 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2862 (void **) &pSMBr);
2863 if (rc)
2864 return rc;
50c2f753 2865
1da177e4
LT
2866 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2867 name_len =
50c2f753 2868 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 2869 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2870 name_len++; /* trailing null */
2871 name_len *= 2;
2872 pSMB->FileName[name_len] = 0;
2873 pSMB->FileName[name_len+1] = 0;
50c2f753 2874 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2875 name_len = strnlen(searchName, PATH_MAX);
2876 name_len++; /* trailing null */
2877 strncpy(pSMB->FileName, searchName, name_len);
2878 }
2879
2880 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2881 pSMB->TotalDataCount = 0;
2882 pSMB->MaxParameterCount = cpu_to_le16(2);
50c2f753 2883 /* BB find exact max data count below from sess structure BB */
1da177e4
LT
2884 pSMB->MaxDataCount = cpu_to_le16(4000);
2885 pSMB->MaxSetupCount = 0;
2886 pSMB->Reserved = 0;
2887 pSMB->Flags = 0;
2888 pSMB->Timeout = 0;
2889 pSMB->Reserved2 = 0;
2890 pSMB->ParameterOffset = cpu_to_le16(
50c2f753
SF
2891 offsetof(struct smb_com_transaction2_qpi_req,
2892 InformationLevel) - 4);
1da177e4
LT
2893 pSMB->DataCount = 0;
2894 pSMB->DataOffset = 0;
2895 pSMB->SetupCount = 1;
2896 pSMB->Reserved3 = 0;
2897 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2898 byte_count = params + 1 /* pad */ ;
2899 pSMB->TotalParameterCount = cpu_to_le16(params);
2900 pSMB->ParameterCount = pSMB->TotalParameterCount;
2901 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2902 pSMB->Reserved4 = 0;
2903 pSMB->hdr.smb_buf_length += byte_count;
2904 pSMB->ByteCount = cpu_to_le16(byte_count);
2905
2906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
0a4b92c0 2908 cifs_stats_inc(&tcon->num_acl_get);
1da177e4
LT
2909 if (rc) {
2910 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2911 } else {
2912 /* decode response */
50c2f753 2913
1da177e4
LT
2914 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2915 if (rc || (pSMBr->ByteCount < 2))
2916 /* BB also check enough total bytes returned */
2917 rc = -EIO; /* bad smb */
2918 else {
2919 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2920 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2921 rc = cifs_copy_posix_acl(acl_inf,
2922 (char *)&pSMBr->hdr.Protocol+data_offset,
50c2f753 2923 buflen, acl_type, count);
1da177e4
LT
2924 }
2925 }
2926 cifs_buf_release(pSMB);
2927 if (rc == -EAGAIN)
2928 goto queryAclRetry;
2929 return rc;
2930}
2931
2932int
2933CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
50c2f753
SF
2934 const unsigned char *fileName,
2935 const char *local_acl, const int buflen,
2936 const int acl_type,
2937 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2938{
2939 struct smb_com_transaction2_spi_req *pSMB = NULL;
2940 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2941 char *parm_data;
2942 int name_len;
2943 int rc = 0;
2944 int bytes_returned = 0;
2945 __u16 params, byte_count, data_count, param_offset, offset;
2946
2947 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2948setAclRetry:
2949 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
50c2f753 2950 (void **) &pSMBr);
1da177e4
LT
2951 if (rc)
2952 return rc;
2953 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2954 name_len =
50c2f753 2955 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 2956 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2957 name_len++; /* trailing null */
2958 name_len *= 2;
50c2f753 2959 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2960 name_len = strnlen(fileName, PATH_MAX);
2961 name_len++; /* trailing null */
2962 strncpy(pSMB->FileName, fileName, name_len);
2963 }
2964 params = 6 + name_len;
2965 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
2966 /* BB find max SMB size from sess */
2967 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
2968 pSMB->MaxSetupCount = 0;
2969 pSMB->Reserved = 0;
2970 pSMB->Flags = 0;
2971 pSMB->Timeout = 0;
2972 pSMB->Reserved2 = 0;
2973 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 2974 InformationLevel) - 4;
1da177e4
LT
2975 offset = param_offset + params;
2976 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2977 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2978
2979 /* convert to on the wire format for POSIX ACL */
50c2f753 2980 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
1da177e4 2981
790fe579 2982 if (data_count == 0) {
1da177e4
LT
2983 rc = -EOPNOTSUPP;
2984 goto setACLerrorExit;
2985 }
2986 pSMB->DataOffset = cpu_to_le16(offset);
2987 pSMB->SetupCount = 1;
2988 pSMB->Reserved3 = 0;
2989 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2990 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2991 byte_count = 3 /* pad */ + params + data_count;
2992 pSMB->DataCount = cpu_to_le16(data_count);
2993 pSMB->TotalDataCount = pSMB->DataCount;
2994 pSMB->ParameterCount = cpu_to_le16(params);
2995 pSMB->TotalParameterCount = pSMB->ParameterCount;
2996 pSMB->Reserved4 = 0;
2997 pSMB->hdr.smb_buf_length += byte_count;
2998 pSMB->ByteCount = cpu_to_le16(byte_count);
2999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
50c2f753 3000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 3001 if (rc)
1da177e4 3002 cFYI(1, ("Set POSIX ACL returned %d", rc));
1da177e4
LT
3003
3004setACLerrorExit:
3005 cifs_buf_release(pSMB);
3006 if (rc == -EAGAIN)
3007 goto setAclRetry;
3008 return rc;
3009}
3010
f654bac2
SF
3011/* BB fix tabs in this function FIXME BB */
3012int
3013CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
ad7a2926 3014 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
f654bac2 3015{
50c2f753
SF
3016 int rc = 0;
3017 struct smb_t2_qfi_req *pSMB = NULL;
3018 struct smb_t2_qfi_rsp *pSMBr = NULL;
3019 int bytes_returned;
3020 __u16 params, byte_count;
f654bac2 3021
790fe579
SF
3022 cFYI(1, ("In GetExtAttr"));
3023 if (tcon == NULL)
3024 return -ENODEV;
f654bac2
SF
3025
3026GetExtAttrRetry:
790fe579
SF
3027 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3028 (void **) &pSMBr);
3029 if (rc)
3030 return rc;
f654bac2 3031
ad7a2926 3032 params = 2 /* level */ + 2 /* fid */;
790fe579
SF
3033 pSMB->t2.TotalDataCount = 0;
3034 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3035 /* BB find exact max data count below from sess structure BB */
3036 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3037 pSMB->t2.MaxSetupCount = 0;
3038 pSMB->t2.Reserved = 0;
3039 pSMB->t2.Flags = 0;
3040 pSMB->t2.Timeout = 0;
3041 pSMB->t2.Reserved2 = 0;
3042 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3043 Fid) - 4);
3044 pSMB->t2.DataCount = 0;
3045 pSMB->t2.DataOffset = 0;
3046 pSMB->t2.SetupCount = 1;
3047 pSMB->t2.Reserved3 = 0;
3048 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3049 byte_count = params + 1 /* pad */ ;
3050 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3051 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3052 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3053 pSMB->Pad = 0;
f654bac2 3054 pSMB->Fid = netfid;
790fe579
SF
3055 pSMB->hdr.smb_buf_length += byte_count;
3056 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3057
3058 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3059 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3060 if (rc) {
3061 cFYI(1, ("error %d in GetExtAttr", rc));
3062 } else {
3063 /* decode response */
3064 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3065 if (rc || (pSMBr->ByteCount < 2))
3066 /* BB also check enough total bytes returned */
3067 /* If rc should we check for EOPNOSUPP and
3068 disable the srvino flag? or in caller? */
3069 rc = -EIO; /* bad smb */
3070 else {
3071 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3072 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3073 struct file_chattr_info *pfinfo;
3074 /* BB Do we need a cast or hash here ? */
3075 if (count != 16) {
3076 cFYI(1, ("Illegal size ret in GetExtAttr"));
3077 rc = -EIO;
3078 goto GetExtAttrOut;
3079 }
3080 pfinfo = (struct file_chattr_info *)
3081 (data_offset + (char *) &pSMBr->hdr.Protocol);
3082 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
f654bac2 3083 *pMask = le64_to_cpu(pfinfo->mask);
790fe579
SF
3084 }
3085 }
f654bac2 3086GetExtAttrOut:
790fe579
SF
3087 cifs_buf_release(pSMB);
3088 if (rc == -EAGAIN)
3089 goto GetExtAttrRetry;
3090 return rc;
f654bac2
SF
3091}
3092
f654bac2 3093#endif /* CONFIG_POSIX */
1da177e4 3094
297647c2 3095#ifdef CONFIG_CIFS_EXPERIMENTAL
0a4b92c0
SF
3096/* Get Security Descriptor (by handle) from remote server for a file or dir */
3097int
3098CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
630f3f0c 3099 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
0a4b92c0
SF
3100{
3101 int rc = 0;
3102 int buf_type = 0;
ad7a2926 3103 QUERY_SEC_DESC_REQ *pSMB;
0a4b92c0
SF
3104 struct kvec iov[1];
3105
3106 cFYI(1, ("GetCifsACL"));
3107
630f3f0c
SF
3108 *pbuflen = 0;
3109 *acl_inf = NULL;
3110
b9c7a2bb 3111 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
0a4b92c0
SF
3112 8 /* parm len */, tcon, (void **) &pSMB);
3113 if (rc)
3114 return rc;
3115
3116 pSMB->MaxParameterCount = cpu_to_le32(4);
3117 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3118 pSMB->MaxSetupCount = 0;
3119 pSMB->Fid = fid; /* file handle always le */
3120 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3121 CIFS_ACL_DACL);
3122 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3123 pSMB->hdr.smb_buf_length += 11;
3124 iov[0].iov_base = (char *)pSMB;
3125 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3126
a761ac57 3127 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
133672ef 3128 CIFS_STD_OP);
0a4b92c0
SF
3129 cifs_stats_inc(&tcon->num_acl_get);
3130 if (rc) {
3131 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3132 } else { /* decode response */
ad7a2926 3133 __le32 *parm;
630f3f0c
SF
3134 __u32 parm_len;
3135 __u32 acl_len;
50c2f753 3136 struct smb_com_ntransact_rsp *pSMBr;
630f3f0c 3137 char *pdata;
0a4b92c0
SF
3138
3139/* validate_nttransact */
50c2f753 3140 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
630f3f0c 3141 &pdata, &parm_len, pbuflen);
790fe579 3142 if (rc)
0a4b92c0
SF
3143 goto qsec_out;
3144 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3145
630f3f0c 3146 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
0a4b92c0
SF
3147
3148 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3149 rc = -EIO; /* bad smb */
630f3f0c 3150 *pbuflen = 0;
0a4b92c0
SF
3151 goto qsec_out;
3152 }
3153
3154/* BB check that data area is minimum length and as big as acl_len */
3155
af6f4612 3156 acl_len = le32_to_cpu(*parm);
630f3f0c
SF
3157 if (acl_len != *pbuflen) {
3158 cERROR(1, ("acl length %d does not match %d",
3159 acl_len, *pbuflen));
3160 if (*pbuflen > acl_len)
3161 *pbuflen = acl_len;
3162 }
0a4b92c0 3163
630f3f0c
SF
3164 /* check if buffer is big enough for the acl
3165 header followed by the smallest SID */
3166 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3167 (*pbuflen >= 64 * 1024)) {
3168 cERROR(1, ("bad acl length %d", *pbuflen));
3169 rc = -EINVAL;
3170 *pbuflen = 0;
3171 } else {
3172 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3173 if (*acl_inf == NULL) {
3174 *pbuflen = 0;
3175 rc = -ENOMEM;
3176 }
3177 memcpy(*acl_inf, pdata, *pbuflen);
3178 }
0a4b92c0
SF
3179 }
3180qsec_out:
790fe579 3181 if (buf_type == CIFS_SMALL_BUFFER)
0a4b92c0 3182 cifs_small_buf_release(iov[0].iov_base);
790fe579 3183 else if (buf_type == CIFS_LARGE_BUFFER)
0a4b92c0 3184 cifs_buf_release(iov[0].iov_base);
4b8f930f 3185/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
0a4b92c0
SF
3186 return rc;
3187}
97837582
SF
3188
3189int
3190CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3191 struct cifs_ntsd *pntsd, __u32 acllen)
3192{
3193 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3194 int rc = 0;
3195 int bytes_returned = 0;
3196 SET_SEC_DESC_REQ *pSMB = NULL;
3197 NTRANSACT_RSP *pSMBr = NULL;
3198
3199setCifsAclRetry:
3200 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3201 (void **) &pSMBr);
3202 if (rc)
3203 return (rc);
3204
3205 pSMB->MaxSetupCount = 0;
3206 pSMB->Reserved = 0;
3207
3208 param_count = 8;
3209 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3210 data_count = acllen;
3211 data_offset = param_offset + param_count;
3212 byte_count = 3 /* pad */ + param_count;
3213
3214 pSMB->DataCount = cpu_to_le32(data_count);
3215 pSMB->TotalDataCount = pSMB->DataCount;
3216 pSMB->MaxParameterCount = cpu_to_le32(4);
3217 pSMB->MaxDataCount = cpu_to_le32(16384);
3218 pSMB->ParameterCount = cpu_to_le32(param_count);
3219 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3220 pSMB->TotalParameterCount = pSMB->ParameterCount;
3221 pSMB->DataOffset = cpu_to_le32(data_offset);
3222 pSMB->SetupCount = 0;
3223 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3224 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3225
3226 pSMB->Fid = fid; /* file handle always le */
3227 pSMB->Reserved2 = 0;
3228 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3229
3230 if (pntsd && acllen) {
3231 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3232 (char *) pntsd,
3233 acllen);
3234 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3235
3236 } else
3237 pSMB->hdr.smb_buf_length += byte_count;
3238
3239 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3240 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3241
3242 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3243 if (rc)
3244 cFYI(1, ("Set CIFS ACL returned %d", rc));
3245 cifs_buf_release(pSMB);
3246
3247 if (rc == -EAGAIN)
3248 goto setCifsAclRetry;
3249
3250 return (rc);
3251}
3252
297647c2 3253#endif /* CONFIG_CIFS_EXPERIMENTAL */
0a4b92c0 3254
6b8edfe0
SF
3255/* Legacy Query Path Information call for lookup to old servers such
3256 as Win9x/WinME */
3257int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
50c2f753
SF
3258 const unsigned char *searchName,
3259 FILE_ALL_INFO *pFinfo,
3260 const struct nls_table *nls_codepage, int remap)
6b8edfe0 3261{
ad7a2926
SF
3262 QUERY_INFORMATION_REQ *pSMB;
3263 QUERY_INFORMATION_RSP *pSMBr;
6b8edfe0
SF
3264 int rc = 0;
3265 int bytes_returned;
3266 int name_len;
3267
50c2f753 3268 cFYI(1, ("In SMBQPath path %s", searchName));
6b8edfe0
SF
3269QInfRetry:
3270 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
50c2f753 3271 (void **) &pSMBr);
6b8edfe0
SF
3272 if (rc)
3273 return rc;
3274
3275 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3276 name_len =
50c2f753
SF
3277 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3278 PATH_MAX, nls_codepage, remap);
6b8edfe0
SF
3279 name_len++; /* trailing null */
3280 name_len *= 2;
50c2f753 3281 } else {
6b8edfe0
SF
3282 name_len = strnlen(searchName, PATH_MAX);
3283 name_len++; /* trailing null */
3284 strncpy(pSMB->FileName, searchName, name_len);
3285 }
3286 pSMB->BufferFormat = 0x04;
50c2f753 3287 name_len++; /* account for buffer type byte */
6b8edfe0
SF
3288 pSMB->hdr.smb_buf_length += (__u16) name_len;
3289 pSMB->ByteCount = cpu_to_le16(name_len);
3290
3291 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
50c2f753 3292 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6b8edfe0
SF
3293 if (rc) {
3294 cFYI(1, ("Send error in QueryInfo = %d", rc));
ad7a2926 3295 } else if (pFinfo) {
1bd5bbcb
SF
3296 struct timespec ts;
3297 __u32 time = le32_to_cpu(pSMBr->last_write_time);
ad7a2926
SF
3298
3299 /* decode response */
1bd5bbcb 3300 /* BB FIXME - add time zone adjustment BB */
6b8edfe0 3301 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
1bd5bbcb
SF
3302 ts.tv_nsec = 0;
3303 ts.tv_sec = time;
3304 /* decode time fields */
733f99ac 3305 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
1bd5bbcb
SF
3306 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3307 pFinfo->LastAccessTime = 0;
70ca734a
SF
3308 pFinfo->AllocationSize =
3309 cpu_to_le64(le32_to_cpu(pSMBr->size));
3310 pFinfo->EndOfFile = pFinfo->AllocationSize;
3311 pFinfo->Attributes =
3312 cpu_to_le32(le16_to_cpu(pSMBr->attr));
6b8edfe0
SF
3313 } else
3314 rc = -EIO; /* bad buffer passed in */
3315
3316 cifs_buf_release(pSMB);
3317
3318 if (rc == -EAGAIN)
3319 goto QInfRetry;
3320
3321 return rc;
3322}
3323
3324
3325
3326
1da177e4
LT
3327int
3328CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3329 const unsigned char *searchName,
ad7a2926 3330 FILE_ALL_INFO *pFindData,
acf1a1b1 3331 int legacy /* old style infolevel */,
737b758c 3332 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3333{
3334/* level 263 SMB_QUERY_FILE_ALL_INFO */
3335 TRANSACTION2_QPI_REQ *pSMB = NULL;
3336 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3337 int rc = 0;
3338 int bytes_returned;
3339 int name_len;
3340 __u16 params, byte_count;
3341
3342/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3343QPathInfoRetry:
3344 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3345 (void **) &pSMBr);
3346 if (rc)
3347 return rc;
3348
3349 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3350 name_len =
50c2f753 3351 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 3352 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3353 name_len++; /* trailing null */
3354 name_len *= 2;
50c2f753 3355 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3356 name_len = strnlen(searchName, PATH_MAX);
3357 name_len++; /* trailing null */
3358 strncpy(pSMB->FileName, searchName, name_len);
3359 }
3360
50c2f753 3361 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
3362 pSMB->TotalDataCount = 0;
3363 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
3364 /* BB find exact max SMB PDU from sess structure BB */
3365 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
3366 pSMB->MaxSetupCount = 0;
3367 pSMB->Reserved = 0;
3368 pSMB->Flags = 0;
3369 pSMB->Timeout = 0;
3370 pSMB->Reserved2 = 0;
3371 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 3372 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
3373 pSMB->DataCount = 0;
3374 pSMB->DataOffset = 0;
3375 pSMB->SetupCount = 1;
3376 pSMB->Reserved3 = 0;
3377 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3378 byte_count = params + 1 /* pad */ ;
3379 pSMB->TotalParameterCount = cpu_to_le16(params);
3380 pSMB->ParameterCount = pSMB->TotalParameterCount;
790fe579 3381 if (legacy)
acf1a1b1
SF
3382 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3383 else
3384 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
1da177e4
LT
3385 pSMB->Reserved4 = 0;
3386 pSMB->hdr.smb_buf_length += byte_count;
3387 pSMB->ByteCount = cpu_to_le16(byte_count);
3388
3389 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3390 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3391 if (rc) {
3392 cFYI(1, ("Send error in QPathInfo = %d", rc));
3393 } else { /* decode response */
3394 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3395
acf1a1b1
SF
3396 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3397 rc = -EIO;
50c2f753 3398 else if (!legacy && (pSMBr->ByteCount < 40))
1da177e4 3399 rc = -EIO; /* bad smb */
790fe579 3400 else if (legacy && (pSMBr->ByteCount < 24))
50c2f753
SF
3401 rc = -EIO; /* 24 or 26 expected but we do not read
3402 last field */
3403 else if (pFindData) {
acf1a1b1 3404 int size;
1da177e4 3405 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
ad7a2926
SF
3406
3407 /* On legacy responses we do not read the last field,
3408 EAsize, fortunately since it varies by subdialect and
3409 also note it differs on Set vs. Get, ie two bytes or 4
3410 bytes depending but we don't care here */
3411 if (legacy)
acf1a1b1
SF
3412 size = sizeof(FILE_INFO_STANDARD);
3413 else
3414 size = sizeof(FILE_ALL_INFO);
1da177e4
LT
3415 memcpy((char *) pFindData,
3416 (char *) &pSMBr->hdr.Protocol +
acf1a1b1 3417 data_offset, size);
1da177e4
LT
3418 } else
3419 rc = -ENOMEM;
3420 }
3421 cifs_buf_release(pSMB);
3422 if (rc == -EAGAIN)
3423 goto QPathInfoRetry;
3424
3425 return rc;
3426}
3427
3428int
3429CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3430 const unsigned char *searchName,
582d21e5 3431 FILE_UNIX_BASIC_INFO *pFindData,
737b758c 3432 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3433{
3434/* SMB_QUERY_FILE_UNIX_BASIC */
3435 TRANSACTION2_QPI_REQ *pSMB = NULL;
3436 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3437 int rc = 0;
3438 int bytes_returned = 0;
3439 int name_len;
3440 __u16 params, byte_count;
3441
3442 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3443UnixQPathInfoRetry:
3444 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3445 (void **) &pSMBr);
3446 if (rc)
3447 return rc;
3448
3449 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3450 name_len =
b1a45695 3451 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 3452 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3453 name_len++; /* trailing null */
3454 name_len *= 2;
50c2f753 3455 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3456 name_len = strnlen(searchName, PATH_MAX);
3457 name_len++; /* trailing null */
3458 strncpy(pSMB->FileName, searchName, name_len);
3459 }
3460
50c2f753 3461 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
3462 pSMB->TotalDataCount = 0;
3463 pSMB->MaxParameterCount = cpu_to_le16(2);
3464 /* BB find exact max SMB PDU from sess structure BB */
50c2f753 3465 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
3466 pSMB->MaxSetupCount = 0;
3467 pSMB->Reserved = 0;
3468 pSMB->Flags = 0;
3469 pSMB->Timeout = 0;
3470 pSMB->Reserved2 = 0;
3471 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 3472 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
3473 pSMB->DataCount = 0;
3474 pSMB->DataOffset = 0;
3475 pSMB->SetupCount = 1;
3476 pSMB->Reserved3 = 0;
3477 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3478 byte_count = params + 1 /* pad */ ;
3479 pSMB->TotalParameterCount = cpu_to_le16(params);
3480 pSMB->ParameterCount = pSMB->TotalParameterCount;
3481 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3482 pSMB->Reserved4 = 0;
3483 pSMB->hdr.smb_buf_length += byte_count;
3484 pSMB->ByteCount = cpu_to_le16(byte_count);
3485
3486 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3487 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3488 if (rc) {
3489 cFYI(1, ("Send error in QPathInfo = %d", rc));
3490 } else { /* decode response */
3491 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3492
3493 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
1e71f25d
SF
3494 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3495 "Unix Extensions can be disabled on mount "
3496 "by specifying the nosfu mount option."));
1da177e4
LT
3497 rc = -EIO; /* bad smb */
3498 } else {
3499 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3500 memcpy((char *) pFindData,
3501 (char *) &pSMBr->hdr.Protocol +
3502 data_offset,
630f3f0c 3503 sizeof(FILE_UNIX_BASIC_INFO));
1da177e4
LT
3504 }
3505 }
3506 cifs_buf_release(pSMB);
3507 if (rc == -EAGAIN)
3508 goto UnixQPathInfoRetry;
3509
3510 return rc;
3511}
3512
1da177e4
LT
3513/* xid, tcon, searchName and codepage are input parms, rest are returned */
3514int
3515CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
50c2f753 3516 const char *searchName,
1da177e4 3517 const struct nls_table *nls_codepage,
50c2f753
SF
3518 __u16 *pnetfid,
3519 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
1da177e4
LT
3520{
3521/* level 257 SMB_ */
3522 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3523 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
ad7a2926 3524 T2_FFIRST_RSP_PARMS *parms;
1da177e4
LT
3525 int rc = 0;
3526 int bytes_returned = 0;
3527 int name_len;
3528 __u16 params, byte_count;
3529
50c2f753 3530 cFYI(1, ("In FindFirst for %s", searchName));
1da177e4
LT
3531
3532findFirstRetry:
3533 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3534 (void **) &pSMBr);
3535 if (rc)
3536 return rc;
3537
3538 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3539 name_len =
50c2f753 3540 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c
SF
3541 PATH_MAX, nls_codepage, remap);
3542 /* We can not add the asterik earlier in case
3543 it got remapped to 0xF03A as if it were part of the
3544 directory name instead of a wildcard */
1da177e4 3545 name_len *= 2;
ac67055e 3546 pSMB->FileName[name_len] = dirsep;
737b758c
SF
3547 pSMB->FileName[name_len+1] = 0;
3548 pSMB->FileName[name_len+2] = '*';
3549 pSMB->FileName[name_len+3] = 0;
3550 name_len += 4; /* now the trailing null */
1da177e4
LT
3551 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3552 pSMB->FileName[name_len+1] = 0;
737b758c 3553 name_len += 2;
1da177e4
LT
3554 } else { /* BB add check for overrun of SMB buf BB */
3555 name_len = strnlen(searchName, PATH_MAX);
1da177e4 3556/* BB fix here and in unicode clause above ie
790fe579 3557 if (name_len > buffersize-header)
1da177e4
LT
3558 free buffer exit; BB */
3559 strncpy(pSMB->FileName, searchName, name_len);
ac67055e 3560 pSMB->FileName[name_len] = dirsep;
68575476
SF
3561 pSMB->FileName[name_len+1] = '*';
3562 pSMB->FileName[name_len+2] = 0;
3563 name_len += 3;
1da177e4
LT
3564 }
3565
3566 params = 12 + name_len /* includes null */ ;
3567 pSMB->TotalDataCount = 0; /* no EAs */
3568 pSMB->MaxParameterCount = cpu_to_le16(10);
3569 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3570 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3571 pSMB->MaxSetupCount = 0;
3572 pSMB->Reserved = 0;
3573 pSMB->Flags = 0;
3574 pSMB->Timeout = 0;
3575 pSMB->Reserved2 = 0;
3576 byte_count = params + 1 /* pad */ ;
3577 pSMB->TotalParameterCount = cpu_to_le16(params);
3578 pSMB->ParameterCount = pSMB->TotalParameterCount;
3579 pSMB->ParameterOffset = cpu_to_le16(
88274815
SF
3580 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3581 - 4);
1da177e4
LT
3582 pSMB->DataCount = 0;
3583 pSMB->DataOffset = 0;
3584 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3585 pSMB->Reserved3 = 0;
3586 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3587 pSMB->SearchAttributes =
3588 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3589 ATTR_DIRECTORY);
50c2f753
SF
3590 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3591 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
1da177e4
LT
3592 CIFS_SEARCH_RETURN_RESUME);
3593 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3594
3595 /* BB what should we set StorageType to? Does it matter? BB */
3596 pSMB->SearchStorageType = 0;
3597 pSMB->hdr.smb_buf_length += byte_count;
3598 pSMB->ByteCount = cpu_to_le16(byte_count);
3599
3600 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3601 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 3602 cifs_stats_inc(&tcon->num_ffirst);
1da177e4 3603
88274815
SF
3604 if (rc) {/* BB add logic to retry regular search if Unix search
3605 rejected unexpectedly by server */
1da177e4
LT
3606 /* BB Add code to handle unsupported level rc */
3607 cFYI(1, ("Error in FindFirst = %d", rc));
1982c344 3608
88274815 3609 cifs_buf_release(pSMB);
1da177e4
LT
3610
3611 /* BB eventually could optimize out free and realloc of buf */
3612 /* for this case */
3613 if (rc == -EAGAIN)
3614 goto findFirstRetry;
3615 } else { /* decode response */
3616 /* BB remember to free buffer if error BB */
3617 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
790fe579 3618 if (rc == 0) {
b77d753c
SF
3619 unsigned int lnoff;
3620
1da177e4 3621 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 3622 psrch_inf->unicode = true;
1da177e4 3623 else
4b18f2a9 3624 psrch_inf->unicode = false;
1da177e4
LT
3625
3626 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
d47d7c1a 3627 psrch_inf->smallBuf = 0;
50c2f753
SF
3628 psrch_inf->srch_entries_start =
3629 (char *) &pSMBr->hdr.Protocol +
1da177e4 3630 le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
3631 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3632 le16_to_cpu(pSMBr->t2.ParameterOffset));
3633
790fe579 3634 if (parms->EndofSearch)
4b18f2a9 3635 psrch_inf->endOfSearch = true;
1da177e4 3636 else
4b18f2a9 3637 psrch_inf->endOfSearch = false;
1da177e4 3638
50c2f753
SF
3639 psrch_inf->entries_in_buffer =
3640 le16_to_cpu(parms->SearchCount);
60808233 3641 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
1da177e4 3642 psrch_inf->entries_in_buffer;
b77d753c
SF
3643 lnoff = le16_to_cpu(parms->LastNameOffset);
3644 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3645 lnoff) {
3646 cERROR(1, ("ignoring corrupt resume name"));
3647 psrch_inf->last_entry = NULL;
3648 return rc;
3649 }
3650
0752f152 3651 psrch_inf->last_entry = psrch_inf->srch_entries_start +
b77d753c
SF
3652 lnoff;
3653
1da177e4
LT
3654 *pnetfid = parms->SearchHandle;
3655 } else {
3656 cifs_buf_release(pSMB);
3657 }
3658 }
3659
3660 return rc;
3661}
3662
3663int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
50c2f753 3664 __u16 searchHandle, struct cifs_search_info *psrch_inf)
1da177e4
LT
3665{
3666 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3667 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
ad7a2926 3668 T2_FNEXT_RSP_PARMS *parms;
1da177e4
LT
3669 char *response_data;
3670 int rc = 0;
3671 int bytes_returned, name_len;
3672 __u16 params, byte_count;
3673
3674 cFYI(1, ("In FindNext"));
3675
4b18f2a9 3676 if (psrch_inf->endOfSearch)
1da177e4
LT
3677 return -ENOENT;
3678
3679 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3680 (void **) &pSMBr);
3681 if (rc)
3682 return rc;
3683
50c2f753 3684 params = 14; /* includes 2 bytes of null string, converted to LE below*/
1da177e4
LT
3685 byte_count = 0;
3686 pSMB->TotalDataCount = 0; /* no EAs */
3687 pSMB->MaxParameterCount = cpu_to_le16(8);
3688 pSMB->MaxDataCount =
50c2f753
SF
3689 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3690 0xFFFFFF00);
1da177e4
LT
3691 pSMB->MaxSetupCount = 0;
3692 pSMB->Reserved = 0;
3693 pSMB->Flags = 0;
3694 pSMB->Timeout = 0;
3695 pSMB->Reserved2 = 0;
3696 pSMB->ParameterOffset = cpu_to_le16(
3697 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3698 pSMB->DataCount = 0;
3699 pSMB->DataOffset = 0;
3700 pSMB->SetupCount = 1;
3701 pSMB->Reserved3 = 0;
3702 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3703 pSMB->SearchHandle = searchHandle; /* always kept as le */
3704 pSMB->SearchCount =
630f3f0c 3705 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
1da177e4
LT
3706 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3707 pSMB->ResumeKey = psrch_inf->resume_key;
3708 pSMB->SearchFlags =
3709 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3710
3711 name_len = psrch_inf->resume_name_len;
3712 params += name_len;
790fe579 3713 if (name_len < PATH_MAX) {
1da177e4
LT
3714 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3715 byte_count += name_len;
ef6724e3
SF
3716 /* 14 byte parm len above enough for 2 byte null terminator */
3717 pSMB->ResumeFileName[name_len] = 0;
3718 pSMB->ResumeFileName[name_len+1] = 0;
1da177e4
LT
3719 } else {
3720 rc = -EINVAL;
3721 goto FNext2_err_exit;
3722 }
3723 byte_count = params + 1 /* pad */ ;
3724 pSMB->TotalParameterCount = cpu_to_le16(params);
3725 pSMB->ParameterCount = pSMB->TotalParameterCount;
3726 pSMB->hdr.smb_buf_length += byte_count;
3727 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 3728
1da177e4
LT
3729 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3730 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 3731 cifs_stats_inc(&tcon->num_fnext);
1da177e4
LT
3732 if (rc) {
3733 if (rc == -EBADF) {
4b18f2a9 3734 psrch_inf->endOfSearch = true;
6353450a 3735 cifs_buf_release(pSMB);
50c2f753 3736 rc = 0; /* search probably was closed at end of search*/
1da177e4
LT
3737 } else
3738 cFYI(1, ("FindNext returned = %d", rc));
3739 } else { /* decode response */
3740 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
50c2f753 3741
790fe579 3742 if (rc == 0) {
b77d753c
SF
3743 unsigned int lnoff;
3744
1da177e4
LT
3745 /* BB fixme add lock for file (srch_info) struct here */
3746 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 3747 psrch_inf->unicode = true;
1da177e4 3748 else
4b18f2a9 3749 psrch_inf->unicode = false;
1da177e4
LT
3750 response_data = (char *) &pSMBr->hdr.Protocol +
3751 le16_to_cpu(pSMBr->t2.ParameterOffset);
3752 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3753 response_data = (char *)&pSMBr->hdr.Protocol +
3754 le16_to_cpu(pSMBr->t2.DataOffset);
790fe579 3755 if (psrch_inf->smallBuf)
d47d7c1a
SF
3756 cifs_small_buf_release(
3757 psrch_inf->ntwrk_buf_start);
3758 else
3759 cifs_buf_release(psrch_inf->ntwrk_buf_start);
1da177e4
LT
3760 psrch_inf->srch_entries_start = response_data;
3761 psrch_inf->ntwrk_buf_start = (char *)pSMB;
d47d7c1a 3762 psrch_inf->smallBuf = 0;
790fe579 3763 if (parms->EndofSearch)
4b18f2a9 3764 psrch_inf->endOfSearch = true;
1da177e4 3765 else
4b18f2a9 3766 psrch_inf->endOfSearch = false;
50c2f753
SF
3767 psrch_inf->entries_in_buffer =
3768 le16_to_cpu(parms->SearchCount);
1da177e4
LT
3769 psrch_inf->index_of_last_entry +=
3770 psrch_inf->entries_in_buffer;
b77d753c
SF
3771 lnoff = le16_to_cpu(parms->LastNameOffset);
3772 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3773 lnoff) {
3774 cERROR(1, ("ignoring corrupt resume name"));
3775 psrch_inf->last_entry = NULL;
3776 return rc;
3777 } else
3778 psrch_inf->last_entry =
3779 psrch_inf->srch_entries_start + lnoff;
3780
50c2f753
SF
3781/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3782 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
1da177e4
LT
3783
3784 /* BB fixme add unlock here */
3785 }
3786
3787 }
3788
3789 /* BB On error, should we leave previous search buf (and count and
3790 last entry fields) intact or free the previous one? */
3791
3792 /* Note: On -EAGAIN error only caller can retry on handle based calls
3793 since file handle passed in no longer valid */
3794FNext2_err_exit:
3795 if (rc != 0)
3796 cifs_buf_release(pSMB);
1da177e4
LT
3797 return rc;
3798}
3799
3800int
50c2f753
SF
3801CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3802 const __u16 searchHandle)
1da177e4
LT
3803{
3804 int rc = 0;
3805 FINDCLOSE_REQ *pSMB = NULL;
1da177e4
LT
3806
3807 cFYI(1, ("In CIFSSMBFindClose"));
3808 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3809
3810 /* no sense returning error if session restarted
3811 as file handle has been closed */
790fe579 3812 if (rc == -EAGAIN)
1da177e4
LT
3813 return 0;
3814 if (rc)
3815 return rc;
3816
1da177e4
LT
3817 pSMB->FileID = searchHandle;
3818 pSMB->ByteCount = 0;
133672ef 3819 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
ad7a2926 3820 if (rc)
1da177e4 3821 cERROR(1, ("Send error in FindClose = %d", rc));
ad7a2926 3822
a4544347 3823 cifs_stats_inc(&tcon->num_fclose);
1da177e4
LT
3824
3825 /* Since session is dead, search handle closed on server already */
3826 if (rc == -EAGAIN)
3827 rc = 0;
3828
3829 return rc;
3830}
3831
1da177e4
LT
3832int
3833CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
50c2f753 3834 const unsigned char *searchName,
ad7a2926 3835 __u64 *inode_number,
50c2f753 3836 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3837{
3838 int rc = 0;
3839 TRANSACTION2_QPI_REQ *pSMB = NULL;
3840 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3841 int name_len, bytes_returned;
3842 __u16 params, byte_count;
3843
50c2f753 3844 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
790fe579 3845 if (tcon == NULL)
50c2f753 3846 return -ENODEV;
1da177e4
LT
3847
3848GetInodeNumberRetry:
3849 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
50c2f753 3850 (void **) &pSMBr);
1da177e4
LT
3851 if (rc)
3852 return rc;
3853
1da177e4
LT
3854 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3855 name_len =
b1a45695 3856 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
50c2f753 3857 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3858 name_len++; /* trailing null */
3859 name_len *= 2;
50c2f753 3860 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3861 name_len = strnlen(searchName, PATH_MAX);
3862 name_len++; /* trailing null */
3863 strncpy(pSMB->FileName, searchName, name_len);
3864 }
3865
3866 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3867 pSMB->TotalDataCount = 0;
3868 pSMB->MaxParameterCount = cpu_to_le16(2);
3869 /* BB find exact max data count below from sess structure BB */
3870 pSMB->MaxDataCount = cpu_to_le16(4000);
3871 pSMB->MaxSetupCount = 0;
3872 pSMB->Reserved = 0;
3873 pSMB->Flags = 0;
3874 pSMB->Timeout = 0;
3875 pSMB->Reserved2 = 0;
3876 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 3877 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
3878 pSMB->DataCount = 0;
3879 pSMB->DataOffset = 0;
3880 pSMB->SetupCount = 1;
3881 pSMB->Reserved3 = 0;
3882 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3883 byte_count = params + 1 /* pad */ ;
3884 pSMB->TotalParameterCount = cpu_to_le16(params);
3885 pSMB->ParameterCount = pSMB->TotalParameterCount;
3886 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3887 pSMB->Reserved4 = 0;
3888 pSMB->hdr.smb_buf_length += byte_count;
3889 pSMB->ByteCount = cpu_to_le16(byte_count);
3890
3891 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3892 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3893 if (rc) {
3894 cFYI(1, ("error %d in QueryInternalInfo", rc));
3895 } else {
3896 /* decode response */
3897 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3898 if (rc || (pSMBr->ByteCount < 2))
3899 /* BB also check enough total bytes returned */
3900 /* If rc should we check for EOPNOSUPP and
3901 disable the srvino flag? or in caller? */
3902 rc = -EIO; /* bad smb */
50c2f753 3903 else {
1da177e4
LT
3904 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3905 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
50c2f753 3906 struct file_internal_info *pfinfo;
1da177e4 3907 /* BB Do we need a cast or hash here ? */
790fe579 3908 if (count < 8) {
1da177e4
LT
3909 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3910 rc = -EIO;
3911 goto GetInodeNumOut;
3912 }
3913 pfinfo = (struct file_internal_info *)
3914 (data_offset + (char *) &pSMBr->hdr.Protocol);
3915 *inode_number = pfinfo->UniqueId;
3916 }
3917 }
3918GetInodeNumOut:
3919 cifs_buf_release(pSMB);
3920 if (rc == -EAGAIN)
3921 goto GetInodeNumberRetry;
3922 return rc;
3923}
1da177e4 3924
fec4585f
IM
3925/* parses DFS refferal V3 structure
3926 * caller is responsible for freeing target_nodes
3927 * returns:
3928 * on success - 0
3929 * on failure - errno
3930 */
3931static int
a1fe78f1 3932parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
fec4585f
IM
3933 unsigned int *num_of_nodes,
3934 struct dfs_info3_param **target_nodes,
3935 const struct nls_table *nls_codepage)
3936{
3937 int i, rc = 0;
3938 char *data_end;
3939 bool is_unicode;
3940 struct dfs_referral_level_3 *ref;
3941
5ca33c6a
HH
3942 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3943 is_unicode = true;
3944 else
3945 is_unicode = false;
fec4585f
IM
3946 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3947
3948 if (*num_of_nodes < 1) {
3949 cERROR(1, ("num_referrals: must be at least > 0,"
3950 "but we get num_referrals = %d\n", *num_of_nodes));
3951 rc = -EINVAL;
a1fe78f1 3952 goto parse_DFS_referrals_exit;
fec4585f
IM
3953 }
3954
3955 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
1d92cfd5 3956 if (ref->VersionNumber != cpu_to_le16(3)) {
fec4585f 3957 cERROR(1, ("Referrals of V%d version are not supported,"
1d92cfd5 3958 "should be V3", le16_to_cpu(ref->VersionNumber)));
fec4585f 3959 rc = -EINVAL;
a1fe78f1 3960 goto parse_DFS_referrals_exit;
fec4585f
IM
3961 }
3962
3963 /* get the upper boundary of the resp buffer */
3964 data_end = (char *)(&(pSMBr->PathConsumed)) +
3965 le16_to_cpu(pSMBr->t2.DataCount);
3966
3967 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3968 *num_of_nodes,
3969 le16_to_cpu(pSMBr->DFSFlags)));
3970
3971 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3972 *num_of_nodes, GFP_KERNEL);
3973 if (*target_nodes == NULL) {
3974 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3975 rc = -ENOMEM;
a1fe78f1 3976 goto parse_DFS_referrals_exit;
fec4585f
IM
3977 }
3978
3979 /* collect neccessary data from referrals */
3980 for (i = 0; i < *num_of_nodes; i++) {
3981 char *temp;
3982 int max_len;
3983 struct dfs_info3_param *node = (*target_nodes)+i;
3984
3985 node->flags = le16_to_cpu(pSMBr->DFSFlags);
3986 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3987 node->server_type = le16_to_cpu(ref->ServerType);
3988 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3989
3990 /* copy DfsPath */
3991 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3992 max_len = data_end - temp;
3993 rc = cifs_strncpy_to_host(&(node->path_name), temp,
3994 max_len, is_unicode, nls_codepage);
3995 if (rc)
a1fe78f1 3996 goto parse_DFS_referrals_exit;
fec4585f
IM
3997
3998 /* copy link target UNC */
3999 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4000 max_len = data_end - temp;
4001 rc = cifs_strncpy_to_host(&(node->node_name), temp,
4002 max_len, is_unicode, nls_codepage);
4003 if (rc)
a1fe78f1 4004 goto parse_DFS_referrals_exit;
fec4585f 4005
1d92cfd5 4006 ref += le16_to_cpu(ref->Size);
fec4585f
IM
4007 }
4008
a1fe78f1 4009parse_DFS_referrals_exit:
fec4585f
IM
4010 if (rc) {
4011 free_dfs_info_array(*target_nodes, *num_of_nodes);
4012 *target_nodes = NULL;
4013 *num_of_nodes = 0;
4014 }
4015 return rc;
4016}
4017
1da177e4
LT
4018int
4019CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4020 const unsigned char *searchName,
c2cf07d5
SF
4021 struct dfs_info3_param **target_nodes,
4022 unsigned int *num_of_nodes,
737b758c 4023 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4024{
4025/* TRANS2_GET_DFS_REFERRAL */
4026 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4027 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
1da177e4
LT
4028 int rc = 0;
4029 int bytes_returned;
4030 int name_len;
1da177e4 4031 __u16 params, byte_count;
c2cf07d5
SF
4032 *num_of_nodes = 0;
4033 *target_nodes = NULL;
1da177e4
LT
4034
4035 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4036 if (ses == NULL)
4037 return -ENODEV;
4038getDFSRetry:
4039 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4040 (void **) &pSMBr);
4041 if (rc)
4042 return rc;
50c2f753
SF
4043
4044 /* server pointer checked in called function,
1982c344
SF
4045 but should never be null here anyway */
4046 pSMB->hdr.Mid = GetNextMid(ses->server);
1da177e4
LT
4047 pSMB->hdr.Tid = ses->ipc_tid;
4048 pSMB->hdr.Uid = ses->Suid;
26f57364 4049 if (ses->capabilities & CAP_STATUS32)
1da177e4 4050 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
26f57364 4051 if (ses->capabilities & CAP_DFS)
1da177e4 4052 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
1da177e4
LT
4053
4054 if (ses->capabilities & CAP_UNICODE) {
4055 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4056 name_len =
b1a45695 4057 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
737b758c 4058 searchName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
4059 name_len++; /* trailing null */
4060 name_len *= 2;
50c2f753 4061 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4062 name_len = strnlen(searchName, PATH_MAX);
4063 name_len++; /* trailing null */
4064 strncpy(pSMB->RequestFileName, searchName, name_len);
4065 }
4066
790fe579
SF
4067 if (ses->server) {
4068 if (ses->server->secMode &
1a4e15a0
SF
4069 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4070 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4071 }
4072
50c2f753 4073 pSMB->hdr.Uid = ses->Suid;
1a4e15a0 4074
1da177e4
LT
4075 params = 2 /* level */ + name_len /*includes null */ ;
4076 pSMB->TotalDataCount = 0;
4077 pSMB->DataCount = 0;
4078 pSMB->DataOffset = 0;
4079 pSMB->MaxParameterCount = 0;
582d21e5
SF
4080 /* BB find exact max SMB PDU from sess structure BB */
4081 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
4082 pSMB->MaxSetupCount = 0;
4083 pSMB->Reserved = 0;
4084 pSMB->Flags = 0;
4085 pSMB->Timeout = 0;
4086 pSMB->Reserved2 = 0;
4087 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4088 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
1da177e4
LT
4089 pSMB->SetupCount = 1;
4090 pSMB->Reserved3 = 0;
4091 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4092 byte_count = params + 3 /* pad */ ;
4093 pSMB->ParameterCount = cpu_to_le16(params);
4094 pSMB->TotalParameterCount = pSMB->ParameterCount;
4095 pSMB->MaxReferralLevel = cpu_to_le16(3);
4096 pSMB->hdr.smb_buf_length += byte_count;
4097 pSMB->ByteCount = cpu_to_le16(byte_count);
4098
4099 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4100 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4101 if (rc) {
4102 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
c2cf07d5
SF
4103 goto GetDFSRefExit;
4104 }
4105 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4106
c2cf07d5 4107 /* BB Also check if enough total bytes returned? */
fec4585f 4108 if (rc || (pSMBr->ByteCount < 17)) {
c2cf07d5 4109 rc = -EIO; /* bad smb */
fec4585f
IM
4110 goto GetDFSRefExit;
4111 }
c2cf07d5 4112
fec4585f
IM
4113 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4114 pSMBr->ByteCount,
4115 le16_to_cpu(pSMBr->t2.DataOffset)));
1da177e4 4116
fec4585f 4117 /* parse returned result into more usable form */
a1fe78f1 4118 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
fec4585f 4119 target_nodes, nls_codepage);
c2cf07d5 4120
1da177e4 4121GetDFSRefExit:
0d817bc0 4122 cifs_buf_release(pSMB);
1da177e4
LT
4123
4124 if (rc == -EAGAIN)
4125 goto getDFSRetry;
4126
4127 return rc;
4128}
4129
20962438
SF
4130/* Query File System Info such as free space to old servers such as Win 9x */
4131int
4132SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4133{
4134/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4135 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4136 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4137 FILE_SYSTEM_ALLOC_INFO *response_data;
4138 int rc = 0;
4139 int bytes_returned = 0;
4140 __u16 params, byte_count;
4141
4142 cFYI(1, ("OldQFSInfo"));
4143oldQFSInfoRetry:
4144 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4145 (void **) &pSMBr);
4146 if (rc)
4147 return rc;
20962438
SF
4148
4149 params = 2; /* level */
4150 pSMB->TotalDataCount = 0;
4151 pSMB->MaxParameterCount = cpu_to_le16(2);
4152 pSMB->MaxDataCount = cpu_to_le16(1000);
4153 pSMB->MaxSetupCount = 0;
4154 pSMB->Reserved = 0;
4155 pSMB->Flags = 0;
4156 pSMB->Timeout = 0;
4157 pSMB->Reserved2 = 0;
4158 byte_count = params + 1 /* pad */ ;
4159 pSMB->TotalParameterCount = cpu_to_le16(params);
4160 pSMB->ParameterCount = pSMB->TotalParameterCount;
4161 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4162 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4163 pSMB->DataCount = 0;
4164 pSMB->DataOffset = 0;
4165 pSMB->SetupCount = 1;
4166 pSMB->Reserved3 = 0;
4167 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4168 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4169 pSMB->hdr.smb_buf_length += byte_count;
4170 pSMB->ByteCount = cpu_to_le16(byte_count);
4171
4172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4174 if (rc) {
4175 cFYI(1, ("Send error in QFSInfo = %d", rc));
4176 } else { /* decode response */
4177 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4178
4179 if (rc || (pSMBr->ByteCount < 18))
4180 rc = -EIO; /* bad smb */
4181 else {
4182 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
50c2f753 4183 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
20962438
SF
4184 pSMBr->ByteCount, data_offset));
4185
50c2f753 4186 response_data = (FILE_SYSTEM_ALLOC_INFO *)
20962438
SF
4187 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4188 FSData->f_bsize =
4189 le16_to_cpu(response_data->BytesPerSector) *
4190 le32_to_cpu(response_data->
4191 SectorsPerAllocationUnit);
4192 FSData->f_blocks =
50c2f753 4193 le32_to_cpu(response_data->TotalAllocationUnits);
20962438
SF
4194 FSData->f_bfree = FSData->f_bavail =
4195 le32_to_cpu(response_data->FreeAllocationUnits);
4196 cFYI(1,
4197 ("Blocks: %lld Free: %lld Block size %ld",
4198 (unsigned long long)FSData->f_blocks,
4199 (unsigned long long)FSData->f_bfree,
4200 FSData->f_bsize));
4201 }
4202 }
4203 cifs_buf_release(pSMB);
4204
4205 if (rc == -EAGAIN)
4206 goto oldQFSInfoRetry;
4207
4208 return rc;
4209}
4210
1da177e4 4211int
737b758c 4212CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
1da177e4
LT
4213{
4214/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4215 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4216 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4217 FILE_SYSTEM_INFO *response_data;
4218 int rc = 0;
4219 int bytes_returned = 0;
4220 __u16 params, byte_count;
4221
4222 cFYI(1, ("In QFSInfo"));
4223QFSInfoRetry:
4224 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4225 (void **) &pSMBr);
4226 if (rc)
4227 return rc;
4228
4229 params = 2; /* level */
4230 pSMB->TotalDataCount = 0;
4231 pSMB->MaxParameterCount = cpu_to_le16(2);
20962438 4232 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4233 pSMB->MaxSetupCount = 0;
4234 pSMB->Reserved = 0;
4235 pSMB->Flags = 0;
4236 pSMB->Timeout = 0;
4237 pSMB->Reserved2 = 0;
4238 byte_count = params + 1 /* pad */ ;
4239 pSMB->TotalParameterCount = cpu_to_le16(params);
4240 pSMB->ParameterCount = pSMB->TotalParameterCount;
4241 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4242 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4243 pSMB->DataCount = 0;
4244 pSMB->DataOffset = 0;
4245 pSMB->SetupCount = 1;
4246 pSMB->Reserved3 = 0;
4247 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4248 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4249 pSMB->hdr.smb_buf_length += byte_count;
4250 pSMB->ByteCount = cpu_to_le16(byte_count);
4251
4252 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4253 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4254 if (rc) {
20962438 4255 cFYI(1, ("Send error in QFSInfo = %d", rc));
1da177e4 4256 } else { /* decode response */
50c2f753 4257 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4258
20962438 4259 if (rc || (pSMBr->ByteCount < 24))
1da177e4
LT
4260 rc = -EIO; /* bad smb */
4261 else {
4262 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
4263
4264 response_data =
4265 (FILE_SYSTEM_INFO
4266 *) (((char *) &pSMBr->hdr.Protocol) +
4267 data_offset);
4268 FSData->f_bsize =
4269 le32_to_cpu(response_data->BytesPerSector) *
4270 le32_to_cpu(response_data->
4271 SectorsPerAllocationUnit);
4272 FSData->f_blocks =
4273 le64_to_cpu(response_data->TotalAllocationUnits);
4274 FSData->f_bfree = FSData->f_bavail =
4275 le64_to_cpu(response_data->FreeAllocationUnits);
4276 cFYI(1,
4277 ("Blocks: %lld Free: %lld Block size %ld",
4278 (unsigned long long)FSData->f_blocks,
4279 (unsigned long long)FSData->f_bfree,
4280 FSData->f_bsize));
4281 }
4282 }
4283 cifs_buf_release(pSMB);
4284
4285 if (rc == -EAGAIN)
4286 goto QFSInfoRetry;
4287
4288 return rc;
4289}
4290
4291int
737b758c 4292CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
4293{
4294/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4295 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4296 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4297 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4298 int rc = 0;
4299 int bytes_returned = 0;
4300 __u16 params, byte_count;
4301
4302 cFYI(1, ("In QFSAttributeInfo"));
4303QFSAttributeRetry:
4304 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4305 (void **) &pSMBr);
4306 if (rc)
4307 return rc;
4308
4309 params = 2; /* level */
4310 pSMB->TotalDataCount = 0;
4311 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4312 /* BB find exact max SMB PDU from sess structure BB */
4313 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4314 pSMB->MaxSetupCount = 0;
4315 pSMB->Reserved = 0;
4316 pSMB->Flags = 0;
4317 pSMB->Timeout = 0;
4318 pSMB->Reserved2 = 0;
4319 byte_count = params + 1 /* pad */ ;
4320 pSMB->TotalParameterCount = cpu_to_le16(params);
4321 pSMB->ParameterCount = pSMB->TotalParameterCount;
4322 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4323 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4324 pSMB->DataCount = 0;
4325 pSMB->DataOffset = 0;
4326 pSMB->SetupCount = 1;
4327 pSMB->Reserved3 = 0;
4328 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4329 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4330 pSMB->hdr.smb_buf_length += byte_count;
4331 pSMB->ByteCount = cpu_to_le16(byte_count);
4332
4333 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4334 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4335 if (rc) {
4336 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4337 } else { /* decode response */
4338 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4339
50c2f753
SF
4340 if (rc || (pSMBr->ByteCount < 13)) {
4341 /* BB also check if enough bytes returned */
1da177e4
LT
4342 rc = -EIO; /* bad smb */
4343 } else {
4344 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4345 response_data =
4346 (FILE_SYSTEM_ATTRIBUTE_INFO
4347 *) (((char *) &pSMBr->hdr.Protocol) +
4348 data_offset);
4349 memcpy(&tcon->fsAttrInfo, response_data,
26f57364 4350 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
1da177e4
LT
4351 }
4352 }
4353 cifs_buf_release(pSMB);
4354
4355 if (rc == -EAGAIN)
4356 goto QFSAttributeRetry;
4357
4358 return rc;
4359}
4360
4361int
737b758c 4362CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
4363{
4364/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4365 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4366 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4367 FILE_SYSTEM_DEVICE_INFO *response_data;
4368 int rc = 0;
4369 int bytes_returned = 0;
4370 __u16 params, byte_count;
4371
4372 cFYI(1, ("In QFSDeviceInfo"));
4373QFSDeviceRetry:
4374 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4375 (void **) &pSMBr);
4376 if (rc)
4377 return rc;
4378
4379 params = 2; /* level */
4380 pSMB->TotalDataCount = 0;
4381 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4382 /* BB find exact max SMB PDU from sess structure BB */
4383 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4384 pSMB->MaxSetupCount = 0;
4385 pSMB->Reserved = 0;
4386 pSMB->Flags = 0;
4387 pSMB->Timeout = 0;
4388 pSMB->Reserved2 = 0;
4389 byte_count = params + 1 /* pad */ ;
4390 pSMB->TotalParameterCount = cpu_to_le16(params);
4391 pSMB->ParameterCount = pSMB->TotalParameterCount;
4392 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4393 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4394
4395 pSMB->DataCount = 0;
4396 pSMB->DataOffset = 0;
4397 pSMB->SetupCount = 1;
4398 pSMB->Reserved3 = 0;
4399 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4400 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4401 pSMB->hdr.smb_buf_length += byte_count;
4402 pSMB->ByteCount = cpu_to_le16(byte_count);
4403
4404 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4405 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4406 if (rc) {
4407 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4408 } else { /* decode response */
4409 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4410
630f3f0c 4411 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
1da177e4
LT
4412 rc = -EIO; /* bad smb */
4413 else {
4414 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4415 response_data =
737b758c
SF
4416 (FILE_SYSTEM_DEVICE_INFO *)
4417 (((char *) &pSMBr->hdr.Protocol) +
1da177e4
LT
4418 data_offset);
4419 memcpy(&tcon->fsDevInfo, response_data,
26f57364 4420 sizeof(FILE_SYSTEM_DEVICE_INFO));
1da177e4
LT
4421 }
4422 }
4423 cifs_buf_release(pSMB);
4424
4425 if (rc == -EAGAIN)
4426 goto QFSDeviceRetry;
4427
4428 return rc;
4429}
4430
4431int
737b758c 4432CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
4433{
4434/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4435 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4436 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4437 FILE_SYSTEM_UNIX_INFO *response_data;
4438 int rc = 0;
4439 int bytes_returned = 0;
4440 __u16 params, byte_count;
4441
4442 cFYI(1, ("In QFSUnixInfo"));
4443QFSUnixRetry:
4444 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4445 (void **) &pSMBr);
4446 if (rc)
4447 return rc;
4448
4449 params = 2; /* level */
4450 pSMB->TotalDataCount = 0;
4451 pSMB->DataCount = 0;
4452 pSMB->DataOffset = 0;
4453 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4454 /* BB find exact max SMB PDU from sess structure BB */
4455 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
4456 pSMB->MaxSetupCount = 0;
4457 pSMB->Reserved = 0;
4458 pSMB->Flags = 0;
4459 pSMB->Timeout = 0;
4460 pSMB->Reserved2 = 0;
4461 byte_count = params + 1 /* pad */ ;
4462 pSMB->ParameterCount = cpu_to_le16(params);
4463 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
4464 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4465 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4466 pSMB->SetupCount = 1;
4467 pSMB->Reserved3 = 0;
4468 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4469 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4470 pSMB->hdr.smb_buf_length += byte_count;
4471 pSMB->ByteCount = cpu_to_le16(byte_count);
4472
4473 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4474 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4475 if (rc) {
4476 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4477 } else { /* decode response */
4478 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4479
4480 if (rc || (pSMBr->ByteCount < 13)) {
4481 rc = -EIO; /* bad smb */
4482 } else {
4483 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4484 response_data =
4485 (FILE_SYSTEM_UNIX_INFO
4486 *) (((char *) &pSMBr->hdr.Protocol) +
4487 data_offset);
4488 memcpy(&tcon->fsUnixInfo, response_data,
26f57364 4489 sizeof(FILE_SYSTEM_UNIX_INFO));
1da177e4
LT
4490 }
4491 }
4492 cifs_buf_release(pSMB);
4493
4494 if (rc == -EAGAIN)
4495 goto QFSUnixRetry;
4496
4497
4498 return rc;
4499}
4500
ac67055e 4501int
45abc6ee 4502CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
ac67055e
JA
4503{
4504/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4505 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4506 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4507 int rc = 0;
4508 int bytes_returned = 0;
4509 __u16 params, param_offset, offset, byte_count;
4510
4511 cFYI(1, ("In SETFSUnixInfo"));
4512SETFSUnixRetry:
f26282c9 4513 /* BB switch to small buf init to save memory */
ac67055e
JA
4514 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4515 (void **) &pSMBr);
4516 if (rc)
4517 return rc;
4518
4519 params = 4; /* 2 bytes zero followed by info level. */
4520 pSMB->MaxSetupCount = 0;
4521 pSMB->Reserved = 0;
4522 pSMB->Flags = 0;
4523 pSMB->Timeout = 0;
4524 pSMB->Reserved2 = 0;
50c2f753
SF
4525 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4526 - 4;
ac67055e
JA
4527 offset = param_offset + params;
4528
4529 pSMB->MaxParameterCount = cpu_to_le16(4);
582d21e5
SF
4530 /* BB find exact max SMB PDU from sess structure BB */
4531 pSMB->MaxDataCount = cpu_to_le16(100);
ac67055e
JA
4532 pSMB->SetupCount = 1;
4533 pSMB->Reserved3 = 0;
4534 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4535 byte_count = 1 /* pad */ + params + 12;
4536
4537 pSMB->DataCount = cpu_to_le16(12);
4538 pSMB->ParameterCount = cpu_to_le16(params);
4539 pSMB->TotalDataCount = pSMB->DataCount;
4540 pSMB->TotalParameterCount = pSMB->ParameterCount;
4541 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4542 pSMB->DataOffset = cpu_to_le16(offset);
4543
4544 /* Params. */
4545 pSMB->FileNum = 0;
4546 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4547
4548 /* Data. */
4549 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4550 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4551 pSMB->ClientUnixCap = cpu_to_le64(cap);
4552
4553 pSMB->hdr.smb_buf_length += byte_count;
4554 pSMB->ByteCount = cpu_to_le16(byte_count);
4555
4556 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4557 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4558 if (rc) {
4559 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4560 } else { /* decode response */
4561 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
ad7a2926 4562 if (rc)
ac67055e 4563 rc = -EIO; /* bad smb */
ac67055e
JA
4564 }
4565 cifs_buf_release(pSMB);
4566
4567 if (rc == -EAGAIN)
4568 goto SETFSUnixRetry;
4569
4570 return rc;
4571}
4572
4573
1da177e4
LT
4574
4575int
4576CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
737b758c 4577 struct kstatfs *FSData)
1da177e4
LT
4578{
4579/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4580 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4581 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4582 FILE_SYSTEM_POSIX_INFO *response_data;
4583 int rc = 0;
4584 int bytes_returned = 0;
4585 __u16 params, byte_count;
4586
4587 cFYI(1, ("In QFSPosixInfo"));
4588QFSPosixRetry:
4589 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4590 (void **) &pSMBr);
4591 if (rc)
4592 return rc;
4593
4594 params = 2; /* level */
4595 pSMB->TotalDataCount = 0;
4596 pSMB->DataCount = 0;
4597 pSMB->DataOffset = 0;
4598 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4599 /* BB find exact max SMB PDU from sess structure BB */
4600 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
4601 pSMB->MaxSetupCount = 0;
4602 pSMB->Reserved = 0;
4603 pSMB->Flags = 0;
4604 pSMB->Timeout = 0;
4605 pSMB->Reserved2 = 0;
4606 byte_count = params + 1 /* pad */ ;
4607 pSMB->ParameterCount = cpu_to_le16(params);
4608 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
4609 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4610 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4611 pSMB->SetupCount = 1;
4612 pSMB->Reserved3 = 0;
4613 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4614 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4615 pSMB->hdr.smb_buf_length += byte_count;
4616 pSMB->ByteCount = cpu_to_le16(byte_count);
4617
4618 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4619 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4620 if (rc) {
4621 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4622 } else { /* decode response */
4623 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4624
4625 if (rc || (pSMBr->ByteCount < 13)) {
4626 rc = -EIO; /* bad smb */
4627 } else {
4628 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4629 response_data =
4630 (FILE_SYSTEM_POSIX_INFO
4631 *) (((char *) &pSMBr->hdr.Protocol) +
4632 data_offset);
4633 FSData->f_bsize =
4634 le32_to_cpu(response_data->BlockSize);
4635 FSData->f_blocks =
4636 le64_to_cpu(response_data->TotalBlocks);
4637 FSData->f_bfree =
4638 le64_to_cpu(response_data->BlocksAvail);
790fe579 4639 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
1da177e4
LT
4640 FSData->f_bavail = FSData->f_bfree;
4641 } else {
4642 FSData->f_bavail =
50c2f753 4643 le64_to_cpu(response_data->UserBlocksAvail);
1da177e4 4644 }
790fe579 4645 if (response_data->TotalFileNodes != cpu_to_le64(-1))
1da177e4 4646 FSData->f_files =
50c2f753 4647 le64_to_cpu(response_data->TotalFileNodes);
790fe579 4648 if (response_data->FreeFileNodes != cpu_to_le64(-1))
1da177e4 4649 FSData->f_ffree =
50c2f753 4650 le64_to_cpu(response_data->FreeFileNodes);
1da177e4
LT
4651 }
4652 }
4653 cifs_buf_release(pSMB);
4654
4655 if (rc == -EAGAIN)
4656 goto QFSPosixRetry;
4657
4658 return rc;
4659}
4660
4661
50c2f753
SF
4662/* We can not use write of zero bytes trick to
4663 set file size due to need for large file support. Also note that
4664 this SetPathInfo is preferred to SetFileInfo based method in next
1da177e4
LT
4665 routine which is only needed to work around a sharing violation bug
4666 in Samba which this routine can run into */
4667
4668int
4669CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4b18f2a9 4670 __u64 size, bool SetAllocation,
737b758c 4671 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4672{
4673 struct smb_com_transaction2_spi_req *pSMB = NULL;
4674 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4675 struct file_end_of_file_info *parm_data;
4676 int name_len;
4677 int rc = 0;
4678 int bytes_returned = 0;
4679 __u16 params, byte_count, data_count, param_offset, offset;
4680
4681 cFYI(1, ("In SetEOF"));
4682SetEOFRetry:
4683 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4684 (void **) &pSMBr);
4685 if (rc)
4686 return rc;
4687
4688 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4689 name_len =
b1a45695 4690 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 4691 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4692 name_len++; /* trailing null */
4693 name_len *= 2;
3e87d803 4694 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4695 name_len = strnlen(fileName, PATH_MAX);
4696 name_len++; /* trailing null */
4697 strncpy(pSMB->FileName, fileName, name_len);
4698 }
4699 params = 6 + name_len;
26f57364 4700 data_count = sizeof(struct file_end_of_file_info);
1da177e4 4701 pSMB->MaxParameterCount = cpu_to_le16(2);
3e87d803 4702 pSMB->MaxDataCount = cpu_to_le16(4100);
1da177e4
LT
4703 pSMB->MaxSetupCount = 0;
4704 pSMB->Reserved = 0;
4705 pSMB->Flags = 0;
4706 pSMB->Timeout = 0;
4707 pSMB->Reserved2 = 0;
4708 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 4709 InformationLevel) - 4;
1da177e4 4710 offset = param_offset + params;
790fe579 4711 if (SetAllocation) {
50c2f753
SF
4712 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4713 pSMB->InformationLevel =
4714 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4715 else
4716 pSMB->InformationLevel =
4717 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4718 } else /* Set File Size */ {
1da177e4
LT
4719 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4720 pSMB->InformationLevel =
50c2f753 4721 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
4722 else
4723 pSMB->InformationLevel =
50c2f753 4724 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
4725 }
4726
4727 parm_data =
4728 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4729 offset);
4730 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4731 pSMB->DataOffset = cpu_to_le16(offset);
4732 pSMB->SetupCount = 1;
4733 pSMB->Reserved3 = 0;
4734 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4735 byte_count = 3 /* pad */ + params + data_count;
4736 pSMB->DataCount = cpu_to_le16(data_count);
4737 pSMB->TotalDataCount = pSMB->DataCount;
4738 pSMB->ParameterCount = cpu_to_le16(params);
4739 pSMB->TotalParameterCount = pSMB->ParameterCount;
4740 pSMB->Reserved4 = 0;
4741 pSMB->hdr.smb_buf_length += byte_count;
4742 parm_data->FileSize = cpu_to_le64(size);
4743 pSMB->ByteCount = cpu_to_le16(byte_count);
4744 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4745 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 4746 if (rc)
1da177e4 4747 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
1da177e4
LT
4748
4749 cifs_buf_release(pSMB);
4750
4751 if (rc == -EAGAIN)
4752 goto SetEOFRetry;
4753
4754 return rc;
4755}
4756
4757int
50c2f753 4758CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4b18f2a9 4759 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
1da177e4
LT
4760{
4761 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
4762 char *data_offset;
4763 struct file_end_of_file_info *parm_data;
4764 int rc = 0;
1da177e4
LT
4765 __u16 params, param_offset, offset, byte_count, count;
4766
4767 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4768 (long long)size));
cd63499c
SF
4769 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4770
1da177e4
LT
4771 if (rc)
4772 return rc;
4773
4774 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4775 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
50c2f753 4776
1da177e4
LT
4777 params = 6;
4778 pSMB->MaxSetupCount = 0;
4779 pSMB->Reserved = 0;
4780 pSMB->Flags = 0;
4781 pSMB->Timeout = 0;
4782 pSMB->Reserved2 = 0;
4783 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4784 offset = param_offset + params;
4785
50c2f753 4786 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1da177e4
LT
4787
4788 count = sizeof(struct file_end_of_file_info);
4789 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4790 /* BB find exact max SMB PDU from sess structure BB */
4791 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4792 pSMB->SetupCount = 1;
4793 pSMB->Reserved3 = 0;
4794 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4795 byte_count = 3 /* pad */ + params + count;
4796 pSMB->DataCount = cpu_to_le16(count);
4797 pSMB->ParameterCount = cpu_to_le16(params);
4798 pSMB->TotalDataCount = pSMB->DataCount;
4799 pSMB->TotalParameterCount = pSMB->ParameterCount;
4800 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4801 parm_data =
50c2f753
SF
4802 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4803 + offset);
1da177e4
LT
4804 pSMB->DataOffset = cpu_to_le16(offset);
4805 parm_data->FileSize = cpu_to_le64(size);
4806 pSMB->Fid = fid;
790fe579 4807 if (SetAllocation) {
1da177e4
LT
4808 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4809 pSMB->InformationLevel =
4810 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4811 else
4812 pSMB->InformationLevel =
4813 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
50c2f753 4814 } else /* Set File Size */ {
1da177e4
LT
4815 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4816 pSMB->InformationLevel =
50c2f753 4817 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
4818 else
4819 pSMB->InformationLevel =
50c2f753 4820 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
4821 }
4822 pSMB->Reserved4 = 0;
4823 pSMB->hdr.smb_buf_length += byte_count;
4824 pSMB->ByteCount = cpu_to_le16(byte_count);
133672ef 4825 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1da177e4
LT
4826 if (rc) {
4827 cFYI(1,
4828 ("Send error in SetFileInfo (SetFileSize) = %d",
4829 rc));
4830 }
4831
50c2f753 4832 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
4833 since file handle passed in no longer valid */
4834
4835 return rc;
4836}
4837
50c2f753 4838/* Some legacy servers such as NT4 require that the file times be set on
1da177e4
LT
4839 an open handle, rather than by pathname - this is awkward due to
4840 potential access conflicts on the open, but it is unavoidable for these
4841 old servers since the only other choice is to go from 100 nanosecond DCE
4842 time and resort to the original setpathinfo level which takes the ancient
4843 DOS time format with 2 second granularity */
4844int
2dd2dfa0
JL
4845CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4846 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
1da177e4
LT
4847{
4848 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
4849 char *data_offset;
4850 int rc = 0;
1da177e4
LT
4851 __u16 params, param_offset, offset, byte_count, count;
4852
4853 cFYI(1, ("Set Times (via SetFileInfo)"));
cd63499c
SF
4854 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4855
1da177e4
LT
4856 if (rc)
4857 return rc;
4858
2dd2dfa0
JL
4859 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4860 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
50c2f753 4861
1da177e4
LT
4862 params = 6;
4863 pSMB->MaxSetupCount = 0;
4864 pSMB->Reserved = 0;
4865 pSMB->Flags = 0;
4866 pSMB->Timeout = 0;
4867 pSMB->Reserved2 = 0;
4868 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4869 offset = param_offset + params;
4870
50c2f753 4871 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1da177e4 4872
26f57364 4873 count = sizeof(FILE_BASIC_INFO);
1da177e4 4874 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4875 /* BB find max SMB PDU from sess */
4876 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4877 pSMB->SetupCount = 1;
4878 pSMB->Reserved3 = 0;
4879 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4880 byte_count = 3 /* pad */ + params + count;
4881 pSMB->DataCount = cpu_to_le16(count);
4882 pSMB->ParameterCount = cpu_to_le16(params);
4883 pSMB->TotalDataCount = pSMB->DataCount;
4884 pSMB->TotalParameterCount = pSMB->ParameterCount;
4885 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4886 pSMB->DataOffset = cpu_to_le16(offset);
4887 pSMB->Fid = fid;
4888 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4889 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4890 else
4891 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4892 pSMB->Reserved4 = 0;
4893 pSMB->hdr.smb_buf_length += byte_count;
4894 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 4895 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
133672ef 4896 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
ad7a2926 4897 if (rc)
50c2f753 4898 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
1da177e4 4899
50c2f753 4900 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
4901 since file handle passed in no longer valid */
4902
4903 return rc;
4904}
4905
6d22f098
JL
4906int
4907CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4908 bool delete_file, __u16 fid, __u32 pid_of_opener)
4909{
4910 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4911 char *data_offset;
4912 int rc = 0;
4913 __u16 params, param_offset, offset, byte_count, count;
4914
4915 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4916 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4917
4918 if (rc)
4919 return rc;
4920
4921 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4922 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4923
4924 params = 6;
4925 pSMB->MaxSetupCount = 0;
4926 pSMB->Reserved = 0;
4927 pSMB->Flags = 0;
4928 pSMB->Timeout = 0;
4929 pSMB->Reserved2 = 0;
4930 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4931 offset = param_offset + params;
4932
4933 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4934
4935 count = 1;
4936 pSMB->MaxParameterCount = cpu_to_le16(2);
4937 /* BB find max SMB PDU from sess */
4938 pSMB->MaxDataCount = cpu_to_le16(1000);
4939 pSMB->SetupCount = 1;
4940 pSMB->Reserved3 = 0;
4941 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4942 byte_count = 3 /* pad */ + params + count;
4943 pSMB->DataCount = cpu_to_le16(count);
4944 pSMB->ParameterCount = cpu_to_le16(params);
4945 pSMB->TotalDataCount = pSMB->DataCount;
4946 pSMB->TotalParameterCount = pSMB->ParameterCount;
4947 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4948 pSMB->DataOffset = cpu_to_le16(offset);
4949 pSMB->Fid = fid;
4950 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4951 pSMB->Reserved4 = 0;
4952 pSMB->hdr.smb_buf_length += byte_count;
4953 pSMB->ByteCount = cpu_to_le16(byte_count);
4954 *data_offset = delete_file ? 1 : 0;
4955 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4956 if (rc)
4957 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4958
4959 return rc;
4960}
1da177e4
LT
4961
4962int
6fc000e5
JL
4963CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4964 const char *fileName, const FILE_BASIC_INFO *data,
4965 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4966{
4967 TRANSACTION2_SPI_REQ *pSMB = NULL;
4968 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4969 int name_len;
4970 int rc = 0;
4971 int bytes_returned = 0;
4972 char *data_offset;
4973 __u16 params, param_offset, offset, byte_count, count;
4974
4975 cFYI(1, ("In SetTimes"));
4976
4977SetTimesRetry:
4978 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4979 (void **) &pSMBr);
4980 if (rc)
4981 return rc;
4982
4983 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4984 name_len =
b1a45695 4985 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 4986 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4987 name_len++; /* trailing null */
4988 name_len *= 2;
50c2f753 4989 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4990 name_len = strnlen(fileName, PATH_MAX);
4991 name_len++; /* trailing null */
4992 strncpy(pSMB->FileName, fileName, name_len);
4993 }
4994
4995 params = 6 + name_len;
26f57364 4996 count = sizeof(FILE_BASIC_INFO);
1da177e4 4997 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4998 /* BB find max SMB PDU from sess structure BB */
4999 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5000 pSMB->MaxSetupCount = 0;
5001 pSMB->Reserved = 0;
5002 pSMB->Flags = 0;
5003 pSMB->Timeout = 0;
5004 pSMB->Reserved2 = 0;
5005 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5006 InformationLevel) - 4;
1da177e4
LT
5007 offset = param_offset + params;
5008 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5009 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5010 pSMB->DataOffset = cpu_to_le16(offset);
5011 pSMB->SetupCount = 1;
5012 pSMB->Reserved3 = 0;
5013 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5014 byte_count = 3 /* pad */ + params + count;
5015
5016 pSMB->DataCount = cpu_to_le16(count);
5017 pSMB->ParameterCount = cpu_to_le16(params);
5018 pSMB->TotalDataCount = pSMB->DataCount;
5019 pSMB->TotalParameterCount = pSMB->ParameterCount;
5020 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5021 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5022 else
5023 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5024 pSMB->Reserved4 = 0;
5025 pSMB->hdr.smb_buf_length += byte_count;
26f57364 5026 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
1da177e4
LT
5027 pSMB->ByteCount = cpu_to_le16(byte_count);
5028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5030 if (rc)
1da177e4 5031 cFYI(1, ("SetPathInfo (times) returned %d", rc));
1da177e4
LT
5032
5033 cifs_buf_release(pSMB);
5034
5035 if (rc == -EAGAIN)
5036 goto SetTimesRetry;
5037
5038 return rc;
5039}
5040
5041/* Can not be used to set time stamps yet (due to old DOS time format) */
5042/* Can be used to set attributes */
5043#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5044 handling it anyway and NT4 was what we thought it would be needed for
5045 Do not delete it until we prove whether needed for Win9x though */
5046int
5047CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5048 __u16 dos_attrs, const struct nls_table *nls_codepage)
5049{
5050 SETATTR_REQ *pSMB = NULL;
5051 SETATTR_RSP *pSMBr = NULL;
5052 int rc = 0;
5053 int bytes_returned;
5054 int name_len;
5055
5056 cFYI(1, ("In SetAttrLegacy"));
5057
5058SetAttrLgcyRetry:
5059 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5060 (void **) &pSMBr);
5061 if (rc)
5062 return rc;
5063
5064 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5065 name_len =
50c2f753 5066 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
1da177e4
LT
5067 PATH_MAX, nls_codepage);
5068 name_len++; /* trailing null */
5069 name_len *= 2;
50c2f753 5070 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5071 name_len = strnlen(fileName, PATH_MAX);
5072 name_len++; /* trailing null */
5073 strncpy(pSMB->fileName, fileName, name_len);
5074 }
5075 pSMB->attr = cpu_to_le16(dos_attrs);
5076 pSMB->BufferFormat = 0x04;
5077 pSMB->hdr.smb_buf_length += name_len + 1;
5078 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5079 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5080 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5081 if (rc)
1da177e4 5082 cFYI(1, ("Error in LegacySetAttr = %d", rc));
1da177e4
LT
5083
5084 cifs_buf_release(pSMB);
5085
5086 if (rc == -EAGAIN)
5087 goto SetAttrLgcyRetry;
5088
5089 return rc;
5090}
5091#endif /* temporarily unneeded SetAttr legacy function */
5092
5093int
4e1e7fb9 5094CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
063ea279 5095 const struct cifs_unix_set_info_args *args,
4e1e7fb9 5096 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5097{
5098 TRANSACTION2_SPI_REQ *pSMB = NULL;
5099 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5100 int name_len;
5101 int rc = 0;
5102 int bytes_returned = 0;
5103 FILE_UNIX_BASIC_INFO *data_offset;
5104 __u16 params, param_offset, offset, count, byte_count;
4e1e7fb9 5105 __u64 mode = args->mode;
1da177e4
LT
5106
5107 cFYI(1, ("In SetUID/GID/Mode"));
5108setPermsRetry:
5109 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5110 (void **) &pSMBr);
5111 if (rc)
5112 return rc;
5113
5114 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5115 name_len =
50c2f753 5116 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 5117 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5118 name_len++; /* trailing null */
5119 name_len *= 2;
3e87d803 5120 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5121 name_len = strnlen(fileName, PATH_MAX);
5122 name_len++; /* trailing null */
5123 strncpy(pSMB->FileName, fileName, name_len);
5124 }
5125
5126 params = 6 + name_len;
26f57364 5127 count = sizeof(FILE_UNIX_BASIC_INFO);
1da177e4 5128 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5129 /* BB find max SMB PDU from sess structure BB */
5130 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5131 pSMB->MaxSetupCount = 0;
5132 pSMB->Reserved = 0;
5133 pSMB->Flags = 0;
5134 pSMB->Timeout = 0;
5135 pSMB->Reserved2 = 0;
5136 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5137 InformationLevel) - 4;
1da177e4
LT
5138 offset = param_offset + params;
5139 data_offset =
5140 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5141 offset);
5142 memset(data_offset, 0, count);
5143 pSMB->DataOffset = cpu_to_le16(offset);
5144 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5145 pSMB->SetupCount = 1;
5146 pSMB->Reserved3 = 0;
5147 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5148 byte_count = 3 /* pad */ + params + count;
5149 pSMB->ParameterCount = cpu_to_le16(params);
5150 pSMB->DataCount = cpu_to_le16(count);
5151 pSMB->TotalParameterCount = pSMB->ParameterCount;
5152 pSMB->TotalDataCount = pSMB->DataCount;
5153 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5154 pSMB->Reserved4 = 0;
5155 pSMB->hdr.smb_buf_length += byte_count;
c7af1857
SF
5156 /* Samba server ignores set of file size to zero due to bugs in some
5157 older clients, but we should be precise - we use SetFileSize to
5158 set file size and do not want to truncate file size to zero
5159 accidently as happened on one Samba server beta by putting
50c2f753 5160 zero instead of -1 here */
4e1e7fb9
JL
5161 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5162 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5163 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5164 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5165 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5166 data_offset->Uid = cpu_to_le64(args->uid);
5167 data_offset->Gid = cpu_to_le64(args->gid);
1da177e4 5168 /* better to leave device as zero when it is */
4e1e7fb9
JL
5169 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5170 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
1da177e4 5171 data_offset->Permissions = cpu_to_le64(mode);
50c2f753 5172
790fe579 5173 if (S_ISREG(mode))
1da177e4 5174 data_offset->Type = cpu_to_le32(UNIX_FILE);
790fe579 5175 else if (S_ISDIR(mode))
1da177e4 5176 data_offset->Type = cpu_to_le32(UNIX_DIR);
790fe579 5177 else if (S_ISLNK(mode))
1da177e4 5178 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
790fe579 5179 else if (S_ISCHR(mode))
1da177e4 5180 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
790fe579 5181 else if (S_ISBLK(mode))
1da177e4 5182 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
790fe579 5183 else if (S_ISFIFO(mode))
1da177e4 5184 data_offset->Type = cpu_to_le32(UNIX_FIFO);
790fe579 5185 else if (S_ISSOCK(mode))
1da177e4
LT
5186 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5187
5188
5189 pSMB->ByteCount = cpu_to_le16(byte_count);
5190 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5191 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5192 if (rc)
1da177e4 5193 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
1da177e4 5194
0d817bc0 5195 cifs_buf_release(pSMB);
1da177e4
LT
5196 if (rc == -EAGAIN)
5197 goto setPermsRetry;
5198 return rc;
5199}
5200
50c2f753 5201int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
167a251a 5202 const int notify_subdirs, const __u16 netfid,
50c2f753 5203 __u32 filter, struct file *pfile, int multishot,
167a251a 5204 const struct nls_table *nls_codepage)
1da177e4
LT
5205{
5206 int rc = 0;
50c2f753
SF
5207 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5208 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
abb15b8a 5209 struct dir_notify_req *dnotify_req;
1da177e4
LT
5210 int bytes_returned;
5211
50c2f753 5212 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
1da177e4 5213 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
50c2f753 5214 (void **) &pSMBr);
1da177e4
LT
5215 if (rc)
5216 return rc;
5217
5218 pSMB->TotalParameterCount = 0 ;
5219 pSMB->TotalDataCount = 0;
5220 pSMB->MaxParameterCount = cpu_to_le32(2);
5221 /* BB find exact data count max from sess structure BB */
5222 pSMB->MaxDataCount = 0; /* same in little endian or be */
0a4b92c0
SF
5223/* BB VERIFY verify which is correct for above BB */
5224 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5225 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5226
1da177e4
LT
5227 pSMB->MaxSetupCount = 4;
5228 pSMB->Reserved = 0;
5229 pSMB->ParameterOffset = 0;
5230 pSMB->DataCount = 0;
5231 pSMB->DataOffset = 0;
5232 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5233 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5234 pSMB->ParameterCount = pSMB->TotalParameterCount;
790fe579 5235 if (notify_subdirs)
1da177e4
LT
5236 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5237 pSMB->Reserved2 = 0;
5238 pSMB->CompletionFilter = cpu_to_le32(filter);
5239 pSMB->Fid = netfid; /* file handle always le */
5240 pSMB->ByteCount = 0;
5241
5242 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
133672ef
SF
5243 (struct smb_hdr *)pSMBr, &bytes_returned,
5244 CIFS_ASYNC_OP);
1da177e4
LT
5245 if (rc) {
5246 cFYI(1, ("Error in Notify = %d", rc));
ff5dbd9e
SF
5247 } else {
5248 /* Add file to outstanding requests */
50c2f753 5249 /* BB change to kmem cache alloc */
5cbded58 5250 dnotify_req = kmalloc(
47c786e7
SF
5251 sizeof(struct dir_notify_req),
5252 GFP_KERNEL);
790fe579 5253 if (dnotify_req) {
47c786e7
SF
5254 dnotify_req->Pid = pSMB->hdr.Pid;
5255 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5256 dnotify_req->Mid = pSMB->hdr.Mid;
5257 dnotify_req->Tid = pSMB->hdr.Tid;
5258 dnotify_req->Uid = pSMB->hdr.Uid;
5259 dnotify_req->netfid = netfid;
5260 dnotify_req->pfile = pfile;
5261 dnotify_req->filter = filter;
5262 dnotify_req->multishot = multishot;
5263 spin_lock(&GlobalMid_Lock);
50c2f753 5264 list_add_tail(&dnotify_req->lhead,
47c786e7
SF
5265 &GlobalDnotifyReqList);
5266 spin_unlock(&GlobalMid_Lock);
50c2f753 5267 } else
47c786e7 5268 rc = -ENOMEM;
1da177e4
LT
5269 }
5270 cifs_buf_release(pSMB);
50c2f753 5271 return rc;
1da177e4
LT
5272}
5273#ifdef CONFIG_CIFS_XATTR
5274ssize_t
5275CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5276 const unsigned char *searchName,
50c2f753 5277 char *EAData, size_t buf_size,
737b758c 5278 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5279{
5280 /* BB assumes one setup word */
5281 TRANSACTION2_QPI_REQ *pSMB = NULL;
5282 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5283 int rc = 0;
5284 int bytes_returned;
5285 int name_len;
50c2f753
SF
5286 struct fea *temp_fea;
5287 char *temp_ptr;
1da177e4
LT
5288 __u16 params, byte_count;
5289
5290 cFYI(1, ("In Query All EAs path %s", searchName));
5291QAllEAsRetry:
5292 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5293 (void **) &pSMBr);
5294 if (rc)
5295 return rc;
5296
5297 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5298 name_len =
50c2f753 5299 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 5300 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5301 name_len++; /* trailing null */
5302 name_len *= 2;
5303 } else { /* BB improve the check for buffer overruns BB */
5304 name_len = strnlen(searchName, PATH_MAX);
5305 name_len++; /* trailing null */
5306 strncpy(pSMB->FileName, searchName, name_len);
5307 }
5308
50c2f753 5309 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
5310 pSMB->TotalDataCount = 0;
5311 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5312 /* BB find exact max SMB PDU from sess structure BB */
5313 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
5314 pSMB->MaxSetupCount = 0;
5315 pSMB->Reserved = 0;
5316 pSMB->Flags = 0;
5317 pSMB->Timeout = 0;
5318 pSMB->Reserved2 = 0;
5319 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 5320 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
5321 pSMB->DataCount = 0;
5322 pSMB->DataOffset = 0;
5323 pSMB->SetupCount = 1;
5324 pSMB->Reserved3 = 0;
5325 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5326 byte_count = params + 1 /* pad */ ;
5327 pSMB->TotalParameterCount = cpu_to_le16(params);
5328 pSMB->ParameterCount = pSMB->TotalParameterCount;
5329 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5330 pSMB->Reserved4 = 0;
5331 pSMB->hdr.smb_buf_length += byte_count;
5332 pSMB->ByteCount = cpu_to_le16(byte_count);
5333
5334 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5335 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5336 if (rc) {
5337 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5338 } else { /* decode response */
5339 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5340
5341 /* BB also check enough total bytes returned */
5342 /* BB we need to improve the validity checking
5343 of these trans2 responses */
50c2f753 5344 if (rc || (pSMBr->ByteCount < 4))
1da177e4
LT
5345 rc = -EIO; /* bad smb */
5346 /* else if (pFindData){
5347 memcpy((char *) pFindData,
5348 (char *) &pSMBr->hdr.Protocol +
5349 data_offset, kl);
5350 }*/ else {
5351 /* check that length of list is not more than bcc */
5352 /* check that each entry does not go beyond length
5353 of list */
5354 /* check that each element of each entry does not
5355 go beyond end of list */
5356 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
50c2f753 5357 struct fealist *ea_response_data;
1da177e4
LT
5358 rc = 0;
5359 /* validate_trans2_offsets() */
790fe579 5360 /* BB check if start of smb + data_offset > &bcc+ bcc */
1da177e4
LT
5361 ea_response_data = (struct fealist *)
5362 (((char *) &pSMBr->hdr.Protocol) +
5363 data_offset);
5364 name_len = le32_to_cpu(ea_response_data->list_len);
50c2f753 5365 cFYI(1, ("ea length %d", name_len));
790fe579 5366 if (name_len <= 8) {
1da177e4 5367 /* returned EA size zeroed at top of function */
50c2f753 5368 cFYI(1, ("empty EA list returned from server"));
1da177e4
LT
5369 } else {
5370 /* account for ea list len */
5371 name_len -= 4;
5372 temp_fea = ea_response_data->list;
5373 temp_ptr = (char *)temp_fea;
50c2f753 5374 while (name_len > 0) {
1da177e4
LT
5375 __u16 value_len;
5376 name_len -= 4;
5377 temp_ptr += 4;
5378 rc += temp_fea->name_len;
5379 /* account for prefix user. and trailing null */
790fe579
SF
5380 rc = rc + 5 + 1;
5381 if (rc < (int)buf_size) {
50c2f753
SF
5382 memcpy(EAData, "user.", 5);
5383 EAData += 5;
5384 memcpy(EAData, temp_ptr,
5385 temp_fea->name_len);
5386 EAData += temp_fea->name_len;
1da177e4
LT
5387 /* null terminate name */
5388 *EAData = 0;
5389 EAData = EAData + 1;
790fe579 5390 } else if (buf_size == 0) {
1da177e4
LT
5391 /* skip copy - calc size only */
5392 } else {
5393 /* stop before overrun buffer */
5394 rc = -ERANGE;
5395 break;
5396 }
5397 name_len -= temp_fea->name_len;
5398 temp_ptr += temp_fea->name_len;
5399 /* account for trailing null */
5400 name_len--;
5401 temp_ptr++;
50c2f753
SF
5402 value_len =
5403 le16_to_cpu(temp_fea->value_len);
1da177e4
LT
5404 name_len -= value_len;
5405 temp_ptr += value_len;
50c2f753
SF
5406 /* BB check that temp_ptr is still
5407 within the SMB BB*/
5408
5409 /* no trailing null to account for
5410 in value len */
1da177e4
LT
5411 /* go on to next EA */
5412 temp_fea = (struct fea *)temp_ptr;
5413 }
5414 }
5415 }
5416 }
0d817bc0 5417 cifs_buf_release(pSMB);
1da177e4
LT
5418 if (rc == -EAGAIN)
5419 goto QAllEAsRetry;
5420
5421 return (ssize_t)rc;
5422}
5423
50c2f753
SF
5424ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5425 const unsigned char *searchName, const unsigned char *ea_name,
5426 unsigned char *ea_value, size_t buf_size,
737b758c 5427 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5428{
5429 TRANSACTION2_QPI_REQ *pSMB = NULL;
5430 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5431 int rc = 0;
5432 int bytes_returned;
5433 int name_len;
50c2f753
SF
5434 struct fea *temp_fea;
5435 char *temp_ptr;
1da177e4
LT
5436 __u16 params, byte_count;
5437
5438 cFYI(1, ("In Query EA path %s", searchName));
5439QEARetry:
5440 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5441 (void **) &pSMBr);
5442 if (rc)
5443 return rc;
5444
5445 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5446 name_len =
50c2f753 5447 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 5448 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5449 name_len++; /* trailing null */
5450 name_len *= 2;
5451 } else { /* BB improve the check for buffer overruns BB */
5452 name_len = strnlen(searchName, PATH_MAX);
5453 name_len++; /* trailing null */
5454 strncpy(pSMB->FileName, searchName, name_len);
5455 }
5456
50c2f753 5457 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
5458 pSMB->TotalDataCount = 0;
5459 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5460 /* BB find exact max SMB PDU from sess structure BB */
5461 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
5462 pSMB->MaxSetupCount = 0;
5463 pSMB->Reserved = 0;
5464 pSMB->Flags = 0;
5465 pSMB->Timeout = 0;
5466 pSMB->Reserved2 = 0;
5467 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 5468 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
5469 pSMB->DataCount = 0;
5470 pSMB->DataOffset = 0;
5471 pSMB->SetupCount = 1;
5472 pSMB->Reserved3 = 0;
5473 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5474 byte_count = params + 1 /* pad */ ;
5475 pSMB->TotalParameterCount = cpu_to_le16(params);
5476 pSMB->ParameterCount = pSMB->TotalParameterCount;
5477 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5478 pSMB->Reserved4 = 0;
5479 pSMB->hdr.smb_buf_length += byte_count;
5480 pSMB->ByteCount = cpu_to_le16(byte_count);
5481
5482 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5483 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5484 if (rc) {
5485 cFYI(1, ("Send error in Query EA = %d", rc));
5486 } else { /* decode response */
5487 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5488
5489 /* BB also check enough total bytes returned */
5490 /* BB we need to improve the validity checking
5491 of these trans2 responses */
50c2f753 5492 if (rc || (pSMBr->ByteCount < 4))
1da177e4
LT
5493 rc = -EIO; /* bad smb */
5494 /* else if (pFindData){
5495 memcpy((char *) pFindData,
5496 (char *) &pSMBr->hdr.Protocol +
5497 data_offset, kl);
5498 }*/ else {
5499 /* check that length of list is not more than bcc */
5500 /* check that each entry does not go beyond length
5501 of list */
5502 /* check that each element of each entry does not
5503 go beyond end of list */
5504 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
50c2f753 5505 struct fealist *ea_response_data;
1da177e4
LT
5506 rc = -ENODATA;
5507 /* validate_trans2_offsets() */
790fe579 5508 /* BB check if start of smb + data_offset > &bcc+ bcc*/
1da177e4
LT
5509 ea_response_data = (struct fealist *)
5510 (((char *) &pSMBr->hdr.Protocol) +
5511 data_offset);
5512 name_len = le32_to_cpu(ea_response_data->list_len);
50c2f753 5513 cFYI(1, ("ea length %d", name_len));
790fe579 5514 if (name_len <= 8) {
1da177e4 5515 /* returned EA size zeroed at top of function */
50c2f753 5516 cFYI(1, ("empty EA list returned from server"));
1da177e4
LT
5517 } else {
5518 /* account for ea list len */
5519 name_len -= 4;
5520 temp_fea = ea_response_data->list;
5521 temp_ptr = (char *)temp_fea;
5522 /* loop through checking if we have a matching
5523 name and then return the associated value */
50c2f753 5524 while (name_len > 0) {
1da177e4
LT
5525 __u16 value_len;
5526 name_len -= 4;
5527 temp_ptr += 4;
50c2f753
SF
5528 value_len =
5529 le16_to_cpu(temp_fea->value_len);
5530 /* BB validate that value_len falls within SMB,
5531 even though maximum for name_len is 255 */
790fe579 5532 if (memcmp(temp_fea->name, ea_name,
1da177e4
LT
5533 temp_fea->name_len) == 0) {
5534 /* found a match */
5535 rc = value_len;
5536 /* account for prefix user. and trailing null */
790fe579 5537 if (rc <= (int)buf_size) {
1da177e4
LT
5538 memcpy(ea_value,
5539 temp_fea->name+temp_fea->name_len+1,
5540 rc);
50c2f753
SF
5541 /* ea values, unlike ea
5542 names, are not null
5543 terminated */
790fe579 5544 } else if (buf_size == 0) {
1da177e4
LT
5545 /* skip copy - calc size only */
5546 } else {
50c2f753 5547 /* stop before overrun buffer */
1da177e4
LT
5548 rc = -ERANGE;
5549 }
5550 break;
5551 }
5552 name_len -= temp_fea->name_len;
5553 temp_ptr += temp_fea->name_len;
5554 /* account for trailing null */
5555 name_len--;
5556 temp_ptr++;
5557 name_len -= value_len;
5558 temp_ptr += value_len;
50c2f753
SF
5559 /* No trailing null to account for in
5560 value_len. Go on to next EA */
1da177e4
LT
5561 temp_fea = (struct fea *)temp_ptr;
5562 }
50c2f753 5563 }
1da177e4
LT
5564 }
5565 }
0d817bc0 5566 cifs_buf_release(pSMB);
1da177e4
LT
5567 if (rc == -EAGAIN)
5568 goto QEARetry;
5569
5570 return (ssize_t)rc;
5571}
5572
5573int
5574CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
50c2f753
SF
5575 const char *ea_name, const void *ea_value,
5576 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5577 int remap)
1da177e4
LT
5578{
5579 struct smb_com_transaction2_spi_req *pSMB = NULL;
5580 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5581 struct fealist *parm_data;
5582 int name_len;
5583 int rc = 0;
5584 int bytes_returned = 0;
5585 __u16 params, param_offset, byte_count, offset, count;
5586
5587 cFYI(1, ("In SetEA"));
5588SetEARetry:
5589 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5590 (void **) &pSMBr);
5591 if (rc)
5592 return rc;
5593
5594 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5595 name_len =
50c2f753 5596 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 5597 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5598 name_len++; /* trailing null */
5599 name_len *= 2;
50c2f753 5600 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5601 name_len = strnlen(fileName, PATH_MAX);
5602 name_len++; /* trailing null */
5603 strncpy(pSMB->FileName, fileName, name_len);
5604 }
5605
5606 params = 6 + name_len;
5607
5608 /* done calculating parms using name_len of file name,
5609 now use name_len to calculate length of ea name
5610 we are going to create in the inode xattrs */
790fe579 5611 if (ea_name == NULL)
1da177e4
LT
5612 name_len = 0;
5613 else
50c2f753 5614 name_len = strnlen(ea_name, 255);
1da177e4 5615
dae5dbdb 5616 count = sizeof(*parm_data) + ea_value_len + name_len;
1da177e4 5617 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5618 /* BB find max SMB PDU from sess */
5619 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5620 pSMB->MaxSetupCount = 0;
5621 pSMB->Reserved = 0;
5622 pSMB->Flags = 0;
5623 pSMB->Timeout = 0;
5624 pSMB->Reserved2 = 0;
5625 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5626 InformationLevel) - 4;
1da177e4
LT
5627 offset = param_offset + params;
5628 pSMB->InformationLevel =
5629 cpu_to_le16(SMB_SET_FILE_EA);
5630
5631 parm_data =
5632 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5633 offset);
5634 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5635 pSMB->DataOffset = cpu_to_le16(offset);
5636 pSMB->SetupCount = 1;
5637 pSMB->Reserved3 = 0;
5638 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5639 byte_count = 3 /* pad */ + params + count;
5640 pSMB->DataCount = cpu_to_le16(count);
5641 parm_data->list_len = cpu_to_le32(count);
5642 parm_data->list[0].EA_flags = 0;
5643 /* we checked above that name len is less than 255 */
53b3531b 5644 parm_data->list[0].name_len = (__u8)name_len;
1da177e4 5645 /* EA names are always ASCII */
790fe579 5646 if (ea_name)
50c2f753 5647 strncpy(parm_data->list[0].name, ea_name, name_len);
1da177e4
LT
5648 parm_data->list[0].name[name_len] = 0;
5649 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5650 /* caller ensures that ea_value_len is less than 64K but
5651 we need to ensure that it fits within the smb */
5652
50c2f753
SF
5653 /*BB add length check to see if it would fit in
5654 negotiated SMB buffer size BB */
790fe579
SF
5655 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5656 if (ea_value_len)
50c2f753
SF
5657 memcpy(parm_data->list[0].name+name_len+1,
5658 ea_value, ea_value_len);
1da177e4
LT
5659
5660 pSMB->TotalDataCount = pSMB->DataCount;
5661 pSMB->ParameterCount = cpu_to_le16(params);
5662 pSMB->TotalParameterCount = pSMB->ParameterCount;
5663 pSMB->Reserved4 = 0;
5664 pSMB->hdr.smb_buf_length += byte_count;
5665 pSMB->ByteCount = cpu_to_le16(byte_count);
5666 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5667 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5668 if (rc)
1da177e4 5669 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
1da177e4
LT
5670
5671 cifs_buf_release(pSMB);
5672
5673 if (rc == -EAGAIN)
5674 goto SetEARetry;
5675
5676 return rc;
5677}
5678
5679#endif