quota: fix possible infinite loop in quota code
[deliverable/linux.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);
26f57364 131 if (open_file)
4b18f2a9 132 open_file->invalidHandle = true;
1da177e4
LT
133 }
134 write_unlock(&GlobalSMBSeslock);
09d1db5c
SF
135 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
136 to this tcon */
1da177e4
LT
137}
138
ad7a2926
SF
139/* Allocate and return pointer to an SMB request buffer, and set basic
140 SMB information in the SMB header. If the return code is zero, this
141 function must have filled in request_buf pointer */
1da177e4
LT
142static int
143small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
ad7a2926 144 void **request_buf)
1da177e4
LT
145{
146 int rc = 0;
147
148 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
149 check for tcp and smb session status done differently
150 for those three - in the calling routine */
790fe579
SF
151 if (tcon) {
152 if (tcon->tidStatus == CifsExiting) {
6ab16d24
SF
153 /* only tree disconnect, open, and write,
154 (and ulogoff which does not have tcon)
155 are allowed as we start force umount */
790fe579 156 if ((smb_command != SMB_COM_WRITE_ANDX) &&
50c2f753 157 (smb_command != SMB_COM_OPEN_ANDX) &&
6ab16d24 158 (smb_command != SMB_COM_TREE_DISCONNECT)) {
790fe579 159 cFYI(1, ("can not send cmd %d while umounting",
6ab16d24
SF
160 smb_command));
161 return -ENODEV;
162 }
163 }
790fe579 164 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
50c2f753 165 (tcon->ses->server)) {
1da177e4 166 struct nls_table *nls_codepage;
50c2f753 167 /* Give Demultiplex thread up to 10 seconds to
09d1db5c
SF
168 reconnect, should be greater than cifs socket
169 timeout which is 7 seconds */
c18c842b 170 while (tcon->ses->server->tcpStatus ==
63135e08 171 CifsNeedReconnect) {
1da177e4 172 wait_event_interruptible_timeout(tcon->ses->server->response_q,
c18c842b 173 (tcon->ses->server->tcpStatus ==
63135e08
SF
174 CifsGood), 10 * HZ);
175 if (tcon->ses->server->tcpStatus ==
176 CifsNeedReconnect) {
1da177e4 177 /* on "soft" mounts we wait once */
4b18f2a9 178 if (!tcon->retry ||
1da177e4 179 (tcon->ses->status == CifsExiting)) {
50c2f753
SF
180 cFYI(1, ("gave up waiting on "
181 "reconnect in smb_init"));
1da177e4 182 return -EHOSTDOWN;
09d1db5c
SF
183 } /* else "hard" mount - keep retrying
184 until process is killed or server
185 comes back on-line */
1da177e4
LT
186 } else /* TCP session is reestablished now */
187 break;
1da177e4 188 }
50c2f753 189
1da177e4
LT
190 nls_codepage = load_nls_default();
191 /* need to prevent multiple threads trying to
192 simultaneously reconnect the same SMB session */
193 down(&tcon->ses->sesSem);
790fe579 194 if (tcon->ses->status == CifsNeedReconnect)
50c2f753 195 rc = cifs_setup_session(0, tcon->ses,
09d1db5c 196 nls_codepage);
790fe579 197 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
1da177e4 198 mark_open_files_invalid(tcon);
50c2f753 199 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
8af18971 200 tcon, nls_codepage);
1da177e4 201 up(&tcon->ses->sesSem);
3e84469d
SF
202 /* BB FIXME add code to check if wsize needs
203 update due to negotiated smb buffer size
204 shrinking */
35028d71 205 if (rc == 0) {
1da177e4 206 atomic_inc(&tconInfoReconnectCount);
35028d71
SF
207 /* tell server Unix caps we support */
208 if (tcon->ses->capabilities & CAP_UNIX)
209 reset_cifs_unix_caps(
210 0 /* no xid */,
211 tcon,
212 NULL /* we do not know sb */,
213 NULL /* no vol info */);
214 }
1da177e4
LT
215
216 cFYI(1, ("reconnect tcon rc = %d", rc));
50c2f753
SF
217 /* Removed call to reopen open files here.
218 It is safer (and faster) to reopen files
09d1db5c 219 one at a time as needed in read and write */
1da177e4 220
50c2f753 221 /* Check if handle based operation so we
09d1db5c
SF
222 know whether we can continue or not without
223 returning to caller to reset file handle */
50c2f753 224 switch (smb_command) {
1da177e4
LT
225 case SMB_COM_READ_ANDX:
226 case SMB_COM_WRITE_ANDX:
227 case SMB_COM_CLOSE:
228 case SMB_COM_FIND_CLOSE2:
229 case SMB_COM_LOCKING_ANDX: {
230 unload_nls(nls_codepage);
231 return -EAGAIN;
232 }
233 }
234 } else {
235 up(&tcon->ses->sesSem);
236 }
237 unload_nls(nls_codepage);
238
239 } else {
240 return -EIO;
241 }
242 }
790fe579 243 if (rc)
1da177e4
LT
244 return rc;
245
246 *request_buf = cifs_small_buf_get();
247 if (*request_buf == NULL) {
248 /* BB should we add a retry in here if not a writepage? */
249 return -ENOMEM;
250 }
251
63135e08 252 header_assemble((struct smb_hdr *) *request_buf, smb_command,
c18c842b 253 tcon, wct);
1da177e4 254
790fe579
SF
255 if (tcon != NULL)
256 cifs_stats_inc(&tcon->num_smbs_sent);
a4544347 257
1da177e4 258 return rc;
5815449d
SF
259}
260
12b3b8ff 261int
50c2f753 262small_smb_init_no_tc(const int smb_command, const int wct,
5815449d 263 struct cifsSesInfo *ses, void **request_buf)
12b3b8ff
SF
264{
265 int rc;
50c2f753 266 struct smb_hdr *buffer;
12b3b8ff 267
5815449d 268 rc = small_smb_init(smb_command, wct, NULL, request_buf);
790fe579 269 if (rc)
12b3b8ff
SF
270 return rc;
271
04fdabe1 272 buffer = (struct smb_hdr *)*request_buf;
12b3b8ff
SF
273 buffer->Mid = GetNextMid(ses->server);
274 if (ses->capabilities & CAP_UNICODE)
275 buffer->Flags2 |= SMBFLG2_UNICODE;
04fdabe1 276 if (ses->capabilities & CAP_STATUS32)
12b3b8ff
SF
277 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
278
279 /* uid, tid can stay at zero as set in header assemble */
280
50c2f753 281 /* BB add support for turning on the signing when
12b3b8ff
SF
282 this function is used after 1st of session setup requests */
283
284 return rc;
285}
1da177e4
LT
286
287/* If the return code is zero, this function must fill in request_buf pointer */
288static int
289smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
290 void **request_buf /* returned */ ,
291 void **response_buf /* returned */ )
292{
293 int rc = 0;
294
295 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
296 check for tcp and smb session status done differently
297 for those three - in the calling routine */
790fe579
SF
298 if (tcon) {
299 if (tcon->tidStatus == CifsExiting) {
6ab16d24
SF
300 /* only tree disconnect, open, and write,
301 (and ulogoff which does not have tcon)
302 are allowed as we start force umount */
790fe579 303 if ((smb_command != SMB_COM_WRITE_ANDX) &&
6ab16d24
SF
304 (smb_command != SMB_COM_OPEN_ANDX) &&
305 (smb_command != SMB_COM_TREE_DISCONNECT)) {
790fe579 306 cFYI(1, ("can not send cmd %d while umounting",
6ab16d24
SF
307 smb_command));
308 return -ENODEV;
309 }
310 }
311
790fe579 312 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
50c2f753 313 (tcon->ses->server)) {
1da177e4 314 struct nls_table *nls_codepage;
09d1db5c
SF
315 /* Give Demultiplex thread up to 10 seconds to
316 reconnect, should be greater than cifs socket
317 timeout which is 7 seconds */
63135e08
SF
318 while (tcon->ses->server->tcpStatus ==
319 CifsNeedReconnect) {
1da177e4 320 wait_event_interruptible_timeout(tcon->ses->server->response_q,
63135e08
SF
321 (tcon->ses->server->tcpStatus ==
322 CifsGood), 10 * HZ);
790fe579 323 if (tcon->ses->server->tcpStatus ==
09d1db5c 324 CifsNeedReconnect) {
1da177e4 325 /* on "soft" mounts we wait once */
4b18f2a9 326 if (!tcon->retry ||
1da177e4 327 (tcon->ses->status == CifsExiting)) {
50c2f753
SF
328 cFYI(1, ("gave up waiting on "
329 "reconnect in smb_init"));
1da177e4 330 return -EHOSTDOWN;
09d1db5c
SF
331 } /* else "hard" mount - keep retrying
332 until process is killed or server
333 comes on-line */
1da177e4
LT
334 } else /* TCP session is reestablished now */
335 break;
1da177e4 336 }
1da177e4
LT
337 nls_codepage = load_nls_default();
338 /* need to prevent multiple threads trying to
339 simultaneously reconnect the same SMB session */
340 down(&tcon->ses->sesSem);
790fe579 341 if (tcon->ses->status == CifsNeedReconnect)
50c2f753 342 rc = cifs_setup_session(0, tcon->ses,
09d1db5c 343 nls_codepage);
790fe579 344 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
1da177e4 345 mark_open_files_invalid(tcon);
09d1db5c
SF
346 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
347 tcon, nls_codepage);
1da177e4 348 up(&tcon->ses->sesSem);
3e84469d
SF
349 /* BB FIXME add code to check if wsize needs
350 update due to negotiated smb buffer size
351 shrinking */
35028d71 352 if (rc == 0) {
1da177e4 353 atomic_inc(&tconInfoReconnectCount);
35028d71
SF
354 /* tell server Unix caps we support */
355 if (tcon->ses->capabilities & CAP_UNIX)
356 reset_cifs_unix_caps(
357 0 /* no xid */,
358 tcon,
359 NULL /* do not know sb */,
360 NULL /* no vol info */);
361 }
1da177e4
LT
362
363 cFYI(1, ("reconnect tcon rc = %d", rc));
50c2f753
SF
364 /* Removed call to reopen open files here.
365 It is safer (and faster) to reopen files
09d1db5c 366 one at a time as needed in read and write */
1da177e4 367
50c2f753 368 /* Check if handle based operation so we
09d1db5c
SF
369 know whether we can continue or not without
370 returning to caller to reset file handle */
50c2f753 371 switch (smb_command) {
1da177e4
LT
372 case SMB_COM_READ_ANDX:
373 case SMB_COM_WRITE_ANDX:
374 case SMB_COM_CLOSE:
375 case SMB_COM_FIND_CLOSE2:
376 case SMB_COM_LOCKING_ANDX: {
377 unload_nls(nls_codepage);
378 return -EAGAIN;
379 }
380 }
381 } else {
382 up(&tcon->ses->sesSem);
383 }
384 unload_nls(nls_codepage);
385
386 } else {
387 return -EIO;
388 }
389 }
790fe579 390 if (rc)
1da177e4
LT
391 return rc;
392
393 *request_buf = cifs_buf_get();
394 if (*request_buf == NULL) {
395 /* BB should we add a retry in here if not a writepage? */
396 return -ENOMEM;
397 }
398 /* Although the original thought was we needed the response buf for */
399 /* potential retries of smb operations it turns out we can determine */
400 /* from the mid flags when the request buffer can be resent without */
401 /* having to use a second distinct buffer for the response */
790fe579 402 if (response_buf)
50c2f753 403 *response_buf = *request_buf;
1da177e4
LT
404
405 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
ad7a2926 406 wct);
1da177e4 407
790fe579
SF
408 if (tcon != NULL)
409 cifs_stats_inc(&tcon->num_smbs_sent);
a4544347 410
1da177e4
LT
411 return rc;
412}
413
50c2f753 414static int validate_t2(struct smb_t2_rsp *pSMB)
1da177e4
LT
415{
416 int rc = -EINVAL;
417 int total_size;
50c2f753 418 char *pBCC;
1da177e4
LT
419
420 /* check for plausible wct, bcc and t2 data and parm sizes */
421 /* check for parm and data offset going beyond end of smb */
790fe579
SF
422 if (pSMB->hdr.WordCount >= 10) {
423 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
1da177e4
LT
424 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
425 /* check that bcc is at least as big as parms + data */
426 /* check that bcc is less than negotiated smb buffer */
427 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
790fe579 428 if (total_size < 512) {
c18c842b 429 total_size +=
63135e08 430 le16_to_cpu(pSMB->t2_rsp.DataCount);
1da177e4 431 /* BCC le converted in SendReceive */
50c2f753 432 pBCC = (pSMB->hdr.WordCount * 2) +
09d1db5c 433 sizeof(struct smb_hdr) +
1da177e4 434 (char *)pSMB;
790fe579 435 if ((total_size <= (*(u16 *)pBCC)) &&
50c2f753 436 (total_size <
1da177e4
LT
437 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
438 return 0;
439 }
1da177e4
LT
440 }
441 }
442 }
50c2f753 443 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
1da177e4
LT
444 sizeof(struct smb_t2_rsp) + 16);
445 return rc;
446}
447int
448CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
449{
450 NEGOTIATE_REQ *pSMB;
451 NEGOTIATE_RSP *pSMBr;
452 int rc = 0;
453 int bytes_returned;
3979877e 454 int i;
50c2f753 455 struct TCP_Server_Info *server;
1da177e4 456 u16 count;
750d1151 457 unsigned int secFlags;
733f99ac 458 u16 dialect;
1da177e4 459
790fe579 460 if (ses->server)
1da177e4
LT
461 server = ses->server;
462 else {
463 rc = -EIO;
464 return rc;
465 }
466 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
467 (void **) &pSMB, (void **) &pSMBr);
468 if (rc)
469 return rc;
750d1151
SF
470
471 /* if any of auth flags (ie not sign or seal) are overriden use them */
790fe579 472 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
762e5ab7 473 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
750d1151
SF
474 else /* if override flags set only sign/seal OR them with global auth */
475 secFlags = extended_security | ses->overrideSecFlg;
476
762e5ab7 477 cFYI(1, ("secFlags 0x%x", secFlags));
f40c5628 478
1982c344 479 pSMB->hdr.Mid = GetNextMid(server);
100c1ddc 480 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
a013689d 481
100c1ddc 482 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
254e55ed 483 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
a013689d
SF
484 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
485 cFYI(1, ("Kerberos only mechanism, enable extended security"));
486 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
487 }
50c2f753 488
3979877e 489 count = 0;
50c2f753 490 for (i = 0; i < CIFS_NUM_PROT; i++) {
3979877e
SF
491 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
492 count += strlen(protocols[i].name) + 1;
493 /* null at end of source and target buffers anyway */
494 }
1da177e4
LT
495 pSMB->hdr.smb_buf_length += count;
496 pSMB->ByteCount = cpu_to_le16(count);
497
498 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
499 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
50c2f753 500 if (rc != 0)
254e55ed
SF
501 goto neg_err_exit;
502
733f99ac 503 dialect = le16_to_cpu(pSMBr->DialectIndex);
790fe579 504 cFYI(1, ("Dialect: %d", dialect));
254e55ed 505 /* Check wct = 1 error case */
790fe579 506 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
254e55ed 507 /* core returns wct = 1, but we do not ask for core - otherwise
50c2f753 508 small wct just comes when dialect index is -1 indicating we
254e55ed
SF
509 could not negotiate a common dialect */
510 rc = -EOPNOTSUPP;
511 goto neg_err_exit;
50c2f753 512#ifdef CONFIG_CIFS_WEAK_PW_HASH
790fe579 513 } else if ((pSMBr->hdr.WordCount == 13)
733f99ac
AV
514 && ((dialect == LANMAN_PROT)
515 || (dialect == LANMAN2_PROT))) {
b815f1e5 516 __s16 tmp;
50c2f753 517 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
254e55ed 518
790fe579 519 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
750d1151 520 (secFlags & CIFSSEC_MAY_PLNTXT))
254e55ed
SF
521 server->secType = LANMAN;
522 else {
523 cERROR(1, ("mount failed weak security disabled"
524 " in /proc/fs/cifs/SecurityFlags"));
3979877e
SF
525 rc = -EOPNOTSUPP;
526 goto neg_err_exit;
50c2f753 527 }
254e55ed
SF
528 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
529 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
530 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
3979877e 531 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
254e55ed
SF
532 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
533 /* even though we do not use raw we might as well set this
534 accurately, in case we ever find a need for it */
790fe579 535 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
254e55ed
SF
536 server->maxRw = 0xFF00;
537 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
538 } else {
539 server->maxRw = 0;/* we do not need to use raw anyway */
540 server->capabilities = CAP_MPX_MODE;
541 }
b815f1e5 542 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
1a70d652 543 if (tmp == -1) {
25ee4a98
SF
544 /* OS/2 often does not set timezone therefore
545 * we must use server time to calc time zone.
b815f1e5
SF
546 * Could deviate slightly from the right zone.
547 * Smallest defined timezone difference is 15 minutes
548 * (i.e. Nepal). Rounding up/down is done to match
549 * this requirement.
25ee4a98 550 */
b815f1e5 551 int val, seconds, remain, result;
25ee4a98
SF
552 struct timespec ts, utc;
553 utc = CURRENT_TIME;
554 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
555 le16_to_cpu(rsp->SrvTime.Time));
50c2f753
SF
556 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
557 (int)ts.tv_sec, (int)utc.tv_sec,
25ee4a98 558 (int)(utc.tv_sec - ts.tv_sec)));
b815f1e5 559 val = (int)(utc.tv_sec - ts.tv_sec);
8594c15a 560 seconds = abs(val);
947a5067 561 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
b815f1e5 562 remain = seconds % MIN_TZ_ADJ;
790fe579 563 if (remain >= (MIN_TZ_ADJ / 2))
b815f1e5 564 result += MIN_TZ_ADJ;
790fe579 565 if (val < 0)
ad7a2926 566 result = -result;
b815f1e5 567 server->timeAdj = result;
25ee4a98 568 } else {
b815f1e5
SF
569 server->timeAdj = (int)tmp;
570 server->timeAdj *= 60; /* also in seconds */
25ee4a98 571 }
790fe579 572 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
25ee4a98 573
3979877e 574
254e55ed 575 /* BB get server time for time conversions and add
50c2f753 576 code to use it and timezone since this is not UTC */
3979877e 577
50c2f753 578 if (rsp->EncryptionKeyLength ==
25ee4a98 579 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
254e55ed
SF
580 memcpy(server->cryptKey, rsp->EncryptionKey,
581 CIFS_CRYPTO_KEY_SIZE);
582 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
583 rc = -EIO; /* need cryptkey unless plain text */
584 goto neg_err_exit;
585 }
3979877e 586
790fe579 587 cFYI(1, ("LANMAN negotiated"));
254e55ed
SF
588 /* we will not end up setting signing flags - as no signing
589 was in LANMAN and server did not return the flags on */
590 goto signing_check;
7c7b25bc 591#else /* weak security disabled */
790fe579 592 } else if (pSMBr->hdr.WordCount == 13) {
50c2f753 593 cERROR(1, ("mount failed, cifs module not built "
254e55ed 594 "with CIFS_WEAK_PW_HASH support"));
7c7b25bc
SF
595 rc = -EOPNOTSUPP;
596#endif /* WEAK_PW_HASH */
254e55ed 597 goto neg_err_exit;
790fe579 598 } else if (pSMBr->hdr.WordCount != 17) {
254e55ed
SF
599 /* unknown wct */
600 rc = -EOPNOTSUPP;
601 goto neg_err_exit;
602 }
603 /* else wct == 17 NTLM */
604 server->secMode = pSMBr->SecurityMode;
790fe579
SF
605 if ((server->secMode & SECMODE_USER) == 0)
606 cFYI(1, ("share mode security"));
bdc4bf6e 607
790fe579 608 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
bdc4bf6e 609#ifdef CONFIG_CIFS_WEAK_PW_HASH
750d1151 610 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
bdc4bf6e 611#endif /* CIFS_WEAK_PW_HASH */
50c2f753 612 cERROR(1, ("Server requests plain text password"
254e55ed 613 " but client support disabled"));
9312f675 614
790fe579 615 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
254e55ed 616 server->secType = NTLMv2;
790fe579 617 else if (secFlags & CIFSSEC_MAY_NTLM)
254e55ed 618 server->secType = NTLM;
790fe579 619 else if (secFlags & CIFSSEC_MAY_NTLMV2)
f40c5628 620 server->secType = NTLMv2;
a013689d
SF
621 else if (secFlags & CIFSSEC_MAY_KRB5)
622 server->secType = Kerberos;
623 else if (secFlags & CIFSSEC_MAY_LANMAN)
624 server->secType = LANMAN;
625/* #ifdef CONFIG_CIFS_EXPERIMENTAL
626 else if (secFlags & CIFSSEC_MAY_PLNTXT)
627 server->secType = ??
628#endif */
629 else {
630 rc = -EOPNOTSUPP;
631 cERROR(1, ("Invalid security type"));
632 goto neg_err_exit;
633 }
634 /* else ... any others ...? */
254e55ed
SF
635
636 /* one byte, so no need to convert this or EncryptionKeyLen from
637 little endian */
638 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
639 /* probably no need to store and check maxvcs */
640 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
1da177e4 641 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
254e55ed 642 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
90c81e0b 643 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
254e55ed
SF
644 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
645 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
b815f1e5
SF
646 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
647 server->timeAdj *= 60;
254e55ed
SF
648 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
649 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
650 CIFS_CRYPTO_KEY_SIZE);
651 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
652 && (pSMBr->EncryptionKeyLength == 0)) {
653 /* decode security blob */
654 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
655 rc = -EIO; /* no crypt key only if plain text pwd */
656 goto neg_err_exit;
657 }
1da177e4 658
254e55ed
SF
659 /* BB might be helpful to save off the domain of server here */
660
50c2f753 661 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
254e55ed
SF
662 (server->capabilities & CAP_EXTENDED_SECURITY)) {
663 count = pSMBr->ByteCount;
e187e44e 664 if (count < 16) {
254e55ed 665 rc = -EIO;
e187e44e
JL
666 goto neg_err_exit;
667 }
668
669 if (server->socketUseCount.counter > 1) {
670 if (memcmp(server->server_GUID,
671 pSMBr->u.extended_response.
672 GUID, 16) != 0) {
673 cFYI(1, ("server UID changed"));
254e55ed 674 memcpy(server->server_GUID,
e187e44e
JL
675 pSMBr->u.extended_response.GUID,
676 16);
677 }
678 } else
679 memcpy(server->server_GUID,
680 pSMBr->u.extended_response.GUID, 16);
681
682 if (count == 16) {
683 server->secType = RawNTLMSSP;
254e55ed
SF
684 } else {
685 rc = decode_negTokenInit(pSMBr->u.extended_response.
686 SecurityBlob,
687 count - 16,
688 &server->secType);
790fe579 689 if (rc == 1) {
e545937a 690 rc = 0;
254e55ed
SF
691 } else {
692 rc = -EINVAL;
1da177e4 693 }
1da177e4 694 }
254e55ed
SF
695 } else
696 server->capabilities &= ~CAP_EXTENDED_SECURITY;
697
6344a423 698#ifdef CONFIG_CIFS_WEAK_PW_HASH
254e55ed 699signing_check:
6344a423 700#endif
762e5ab7
SF
701 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
702 /* MUST_SIGN already includes the MAY_SIGN FLAG
703 so if this is zero it means that signing is disabled */
704 cFYI(1, ("Signing disabled"));
abb63d6c 705 if (server->secMode & SECMODE_SIGN_REQUIRED) {
762e5ab7 706 cERROR(1, ("Server requires "
7111d214
JL
707 "packet signing to be enabled in "
708 "/proc/fs/cifs/SecurityFlags."));
abb63d6c
SF
709 rc = -EOPNOTSUPP;
710 }
50c2f753 711 server->secMode &=
254e55ed 712 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
762e5ab7
SF
713 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
714 /* signing required */
38c10a1d 715 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
762e5ab7
SF
716 if ((server->secMode &
717 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
718 cERROR(1,
719 ("signing required but server lacks support"));
38c10a1d 720 rc = -EOPNOTSUPP;
762e5ab7
SF
721 } else
722 server->secMode |= SECMODE_SIGN_REQUIRED;
723 } else {
724 /* signing optional ie CIFSSEC_MAY_SIGN */
790fe579 725 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
50c2f753 726 server->secMode &=
254e55ed 727 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
1da177e4 728 }
50c2f753
SF
729
730neg_err_exit:
4a6d87f1 731 cifs_buf_release(pSMB);
254e55ed 732
790fe579 733 cFYI(1, ("negprot rc %d", rc));
1da177e4
LT
734 return rc;
735}
736
737int
738CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
739{
740 struct smb_hdr *smb_buffer;
1da177e4 741 int rc = 0;
1da177e4
LT
742
743 cFYI(1, ("In tree disconnect"));
744 /*
745 * If last user of the connection and
746 * connection alive - disconnect it
747 * If this is the last connection on the server session disconnect it
50c2f753 748 * (and inside session disconnect we should check if tcp socket needs
1da177e4
LT
749 * to be freed and kernel thread woken up).
750 */
751 if (tcon)
752 down(&tcon->tconSem);
753 else
754 return -EIO;
755
756 atomic_dec(&tcon->useCount);
757 if (atomic_read(&tcon->useCount) > 0) {
758 up(&tcon->tconSem);
759 return -EBUSY;
760 }
761
50c2f753 762 /* No need to return error on this operation if tid invalidated and
1da177e4 763 closed on server already e.g. due to tcp session crashing */
790fe579 764 if (tcon->tidStatus == CifsNeedReconnect) {
1da177e4 765 up(&tcon->tconSem);
50c2f753 766 return 0;
1da177e4
LT
767 }
768
790fe579 769 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
1da177e4
LT
770 up(&tcon->tconSem);
771 return -EIO;
772 }
50c2f753 773 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
09d1db5c 774 (void **)&smb_buffer);
1da177e4
LT
775 if (rc) {
776 up(&tcon->tconSem);
777 return rc;
cd63499c 778 }
133672ef
SF
779
780 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
1da177e4 781 if (rc)
966ca923 782 cFYI(1, ("Tree disconnect failed %d", rc));
1da177e4 783
1da177e4
LT
784 up(&tcon->tconSem);
785
50c2f753 786 /* No need to return error on this operation if tid invalidated and
1da177e4
LT
787 closed on server already e.g. due to tcp session crashing */
788 if (rc == -EAGAIN)
789 rc = 0;
790
791 return rc;
792}
793
794int
795CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
796{
1da177e4
LT
797 LOGOFF_ANDX_REQ *pSMB;
798 int rc = 0;
1da177e4
LT
799
800 cFYI(1, ("In SMBLogoff for session disconnect"));
801 if (ses)
802 down(&ses->sesSem);
803 else
804 return -EIO;
805
806 atomic_dec(&ses->inUse);
807 if (atomic_read(&ses->inUse) > 0) {
808 up(&ses->sesSem);
809 return -EBUSY;
810 }
811 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
812 if (rc) {
813 up(&ses->sesSem);
814 return rc;
815 }
816
790fe579 817 if (ses->server) {
1982c344
SF
818 pSMB->hdr.Mid = GetNextMid(ses->server);
819
790fe579 820 if (ses->server->secMode &
1da177e4
LT
821 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
822 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
823 }
824
825 pSMB->hdr.Uid = ses->Suid;
826
827 pSMB->AndXCommand = 0xFF;
133672ef 828 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
1da177e4
LT
829 if (ses->server) {
830 atomic_dec(&ses->server->socketUseCount);
831 if (atomic_read(&ses->server->socketUseCount) == 0) {
832 spin_lock(&GlobalMid_Lock);
833 ses->server->tcpStatus = CifsExiting;
834 spin_unlock(&GlobalMid_Lock);
835 rc = -ESHUTDOWN;
836 }
837 }
a59c6586 838 up(&ses->sesSem);
1da177e4
LT
839
840 /* if session dead then we do not need to do ulogoff,
50c2f753 841 since server closed smb session, no sense reporting
1da177e4
LT
842 error */
843 if (rc == -EAGAIN)
844 rc = 0;
845 return rc;
846}
847
2d785a50
SF
848int
849CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
850 __u16 type, const struct nls_table *nls_codepage, int remap)
851{
852 TRANSACTION2_SPI_REQ *pSMB = NULL;
853 TRANSACTION2_SPI_RSP *pSMBr = NULL;
854 struct unlink_psx_rq *pRqD;
855 int name_len;
856 int rc = 0;
857 int bytes_returned = 0;
858 __u16 params, param_offset, offset, byte_count;
859
860 cFYI(1, ("In POSIX delete"));
861PsxDelete:
862 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
863 (void **) &pSMBr);
864 if (rc)
865 return rc;
866
867 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
868 name_len =
869 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
870 PATH_MAX, nls_codepage, remap);
871 name_len++; /* trailing null */
872 name_len *= 2;
873 } else { /* BB add path length overrun check */
874 name_len = strnlen(fileName, PATH_MAX);
875 name_len++; /* trailing null */
876 strncpy(pSMB->FileName, fileName, name_len);
877 }
878
879 params = 6 + name_len;
880 pSMB->MaxParameterCount = cpu_to_le16(2);
881 pSMB->MaxDataCount = 0; /* BB double check this with jra */
882 pSMB->MaxSetupCount = 0;
883 pSMB->Reserved = 0;
884 pSMB->Flags = 0;
885 pSMB->Timeout = 0;
886 pSMB->Reserved2 = 0;
887 param_offset = offsetof(struct smb_com_transaction2_spi_req,
888 InformationLevel) - 4;
889 offset = param_offset + params;
890
891 /* Setup pointer to Request Data (inode type) */
892 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
893 pRqD->type = cpu_to_le16(type);
894 pSMB->ParameterOffset = cpu_to_le16(param_offset);
895 pSMB->DataOffset = cpu_to_le16(offset);
896 pSMB->SetupCount = 1;
897 pSMB->Reserved3 = 0;
898 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
899 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
900
901 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
902 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
903 pSMB->ParameterCount = cpu_to_le16(params);
904 pSMB->TotalParameterCount = pSMB->ParameterCount;
905 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
906 pSMB->Reserved4 = 0;
907 pSMB->hdr.smb_buf_length += byte_count;
908 pSMB->ByteCount = cpu_to_le16(byte_count);
909 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
910 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 911 if (rc)
2d785a50 912 cFYI(1, ("Posix delete returned %d", rc));
2d785a50
SF
913 cifs_buf_release(pSMB);
914
915 cifs_stats_inc(&tcon->num_deletes);
916
917 if (rc == -EAGAIN)
918 goto PsxDelete;
919
920 return rc;
921}
922
1da177e4 923int
737b758c
SF
924CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
925 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
926{
927 DELETE_FILE_REQ *pSMB = NULL;
928 DELETE_FILE_RSP *pSMBr = NULL;
929 int rc = 0;
930 int bytes_returned;
931 int name_len;
932
933DelFileRetry:
934 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
935 (void **) &pSMBr);
936 if (rc)
937 return rc;
938
939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
940 name_len =
50c2f753 941 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
737b758c 942 PATH_MAX, nls_codepage, remap);
1da177e4
LT
943 name_len++; /* trailing null */
944 name_len *= 2;
09d1db5c 945 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
946 name_len = strnlen(fileName, PATH_MAX);
947 name_len++; /* trailing null */
948 strncpy(pSMB->fileName, fileName, name_len);
949 }
950 pSMB->SearchAttributes =
951 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
952 pSMB->BufferFormat = 0x04;
953 pSMB->hdr.smb_buf_length += name_len + 1;
954 pSMB->ByteCount = cpu_to_le16(name_len + 1);
955 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
956 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 957 cifs_stats_inc(&tcon->num_deletes);
ad7a2926 958 if (rc)
1da177e4 959 cFYI(1, ("Error in RMFile = %d", rc));
1da177e4
LT
960
961 cifs_buf_release(pSMB);
962 if (rc == -EAGAIN)
963 goto DelFileRetry;
964
965 return rc;
966}
967
968int
50c2f753 969CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
737b758c 970 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
971{
972 DELETE_DIRECTORY_REQ *pSMB = NULL;
973 DELETE_DIRECTORY_RSP *pSMBr = NULL;
974 int rc = 0;
975 int bytes_returned;
976 int name_len;
977
978 cFYI(1, ("In CIFSSMBRmDir"));
979RmDirRetry:
980 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
981 (void **) &pSMBr);
982 if (rc)
983 return rc;
984
985 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
737b758c
SF
986 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
987 PATH_MAX, nls_codepage, remap);
1da177e4
LT
988 name_len++; /* trailing null */
989 name_len *= 2;
09d1db5c 990 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
991 name_len = strnlen(dirName, PATH_MAX);
992 name_len++; /* trailing null */
993 strncpy(pSMB->DirName, dirName, name_len);
994 }
995
996 pSMB->BufferFormat = 0x04;
997 pSMB->hdr.smb_buf_length += name_len + 1;
998 pSMB->ByteCount = cpu_to_le16(name_len + 1);
999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 1001 cifs_stats_inc(&tcon->num_rmdirs);
ad7a2926 1002 if (rc)
1da177e4 1003 cFYI(1, ("Error in RMDir = %d", rc));
1da177e4
LT
1004
1005 cifs_buf_release(pSMB);
1006 if (rc == -EAGAIN)
1007 goto RmDirRetry;
1008 return rc;
1009}
1010
1011int
1012CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
737b758c 1013 const char *name, const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1014{
1015 int rc = 0;
1016 CREATE_DIRECTORY_REQ *pSMB = NULL;
1017 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1018 int bytes_returned;
1019 int name_len;
1020
1021 cFYI(1, ("In CIFSSMBMkDir"));
1022MkDirRetry:
1023 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1024 (void **) &pSMBr);
1025 if (rc)
1026 return rc;
1027
1028 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
50c2f753 1029 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
737b758c 1030 PATH_MAX, nls_codepage, remap);
1da177e4
LT
1031 name_len++; /* trailing null */
1032 name_len *= 2;
09d1db5c 1033 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
1034 name_len = strnlen(name, PATH_MAX);
1035 name_len++; /* trailing null */
1036 strncpy(pSMB->DirName, name, name_len);
1037 }
1038
1039 pSMB->BufferFormat = 0x04;
1040 pSMB->hdr.smb_buf_length += name_len + 1;
1041 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1042 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 1044 cifs_stats_inc(&tcon->num_mkdirs);
ad7a2926 1045 if (rc)
1da177e4 1046 cFYI(1, ("Error in Mkdir = %d", rc));
a5a2b489 1047
1da177e4
LT
1048 cifs_buf_release(pSMB);
1049 if (rc == -EAGAIN)
1050 goto MkDirRetry;
1051 return rc;
1052}
1053
2dd29d31
SF
1054int
1055CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
ad7a2926 1056 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
50c2f753 1057 __u32 *pOplock, const char *name,
2dd29d31
SF
1058 const struct nls_table *nls_codepage, int remap)
1059{
1060 TRANSACTION2_SPI_REQ *pSMB = NULL;
1061 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1062 int name_len;
1063 int rc = 0;
1064 int bytes_returned = 0;
2dd29d31 1065 __u16 params, param_offset, offset, byte_count, count;
ad7a2926
SF
1066 OPEN_PSX_REQ *pdata;
1067 OPEN_PSX_RSP *psx_rsp;
2dd29d31
SF
1068
1069 cFYI(1, ("In POSIX Create"));
1070PsxCreat:
1071 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1072 (void **) &pSMBr);
1073 if (rc)
1074 return rc;
1075
1076 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1077 name_len =
1078 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1079 PATH_MAX, nls_codepage, remap);
1080 name_len++; /* trailing null */
1081 name_len *= 2;
1082 } else { /* BB improve the check for buffer overruns BB */
1083 name_len = strnlen(name, PATH_MAX);
1084 name_len++; /* trailing null */
1085 strncpy(pSMB->FileName, name, name_len);
1086 }
1087
1088 params = 6 + name_len;
1089 count = sizeof(OPEN_PSX_REQ);
1090 pSMB->MaxParameterCount = cpu_to_le16(2);
1091 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1092 pSMB->MaxSetupCount = 0;
1093 pSMB->Reserved = 0;
1094 pSMB->Flags = 0;
1095 pSMB->Timeout = 0;
1096 pSMB->Reserved2 = 0;
1097 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 1098 InformationLevel) - 4;
2dd29d31 1099 offset = param_offset + params;
2dd29d31 1100 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
8f2376ad 1101 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2dd29d31 1102 pdata->Permissions = cpu_to_le64(mode);
50c2f753 1103 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
2dd29d31
SF
1104 pdata->OpenFlags = cpu_to_le32(*pOplock);
1105 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1106 pSMB->DataOffset = cpu_to_le16(offset);
1107 pSMB->SetupCount = 1;
1108 pSMB->Reserved3 = 0;
1109 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1110 byte_count = 3 /* pad */ + params + count;
1111
1112 pSMB->DataCount = cpu_to_le16(count);
1113 pSMB->ParameterCount = cpu_to_le16(params);
1114 pSMB->TotalDataCount = pSMB->DataCount;
1115 pSMB->TotalParameterCount = pSMB->ParameterCount;
1116 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1117 pSMB->Reserved4 = 0;
50c2f753 1118 pSMB->hdr.smb_buf_length += byte_count;
2dd29d31
SF
1119 pSMB->ByteCount = cpu_to_le16(byte_count);
1120 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1121 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1122 if (rc) {
1123 cFYI(1, ("Posix create returned %d", rc));
1124 goto psx_create_err;
1125 }
1126
790fe579 1127 cFYI(1, ("copying inode info"));
2dd29d31
SF
1128 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1129
1130 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1131 rc = -EIO; /* bad smb */
1132 goto psx_create_err;
1133 }
1134
1135 /* copy return information to pRetData */
50c2f753 1136 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
2dd29d31 1137 + le16_to_cpu(pSMBr->t2.DataOffset));
50c2f753 1138
2dd29d31 1139 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
790fe579 1140 if (netfid)
2dd29d31
SF
1141 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1142 /* Let caller know file was created so we can set the mode. */
1143 /* Do we care about the CreateAction in any other cases? */
790fe579 1144 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
2dd29d31
SF
1145 *pOplock |= CIFS_CREATE_ACTION;
1146 /* check to make sure response data is there */
8f2376ad
CG
1147 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1148 pRetData->Type = cpu_to_le32(-1); /* unknown */
90c81e0b 1149 cFYI(DBG2, ("unknown type"));
cbac3cba 1150 } else {
790fe579 1151 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
2dd29d31 1152 + sizeof(FILE_UNIX_BASIC_INFO)) {
50c2f753 1153 cERROR(1, ("Open response data too small"));
8f2376ad 1154 pRetData->Type = cpu_to_le32(-1);
2dd29d31
SF
1155 goto psx_create_err;
1156 }
50c2f753 1157 memcpy((char *) pRetData,
cbac3cba 1158 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
26f57364 1159 sizeof(FILE_UNIX_BASIC_INFO));
2dd29d31 1160 }
2dd29d31
SF
1161
1162psx_create_err:
1163 cifs_buf_release(pSMB);
1164
1165 cifs_stats_inc(&tcon->num_mkdirs);
1166
1167 if (rc == -EAGAIN)
1168 goto PsxCreat;
1169
50c2f753 1170 return rc;
2dd29d31
SF
1171}
1172
a9d02ad4
SF
1173static __u16 convert_disposition(int disposition)
1174{
1175 __u16 ofun = 0;
1176
1177 switch (disposition) {
1178 case FILE_SUPERSEDE:
1179 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1180 break;
1181 case FILE_OPEN:
1182 ofun = SMBOPEN_OAPPEND;
1183 break;
1184 case FILE_CREATE:
1185 ofun = SMBOPEN_OCREATE;
1186 break;
1187 case FILE_OPEN_IF:
1188 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1189 break;
1190 case FILE_OVERWRITE:
1191 ofun = SMBOPEN_OTRUNC;
1192 break;
1193 case FILE_OVERWRITE_IF:
1194 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1195 break;
1196 default:
790fe579 1197 cFYI(1, ("unknown disposition %d", disposition));
a9d02ad4
SF
1198 ofun = SMBOPEN_OAPPEND; /* regular open */
1199 }
1200 return ofun;
1201}
1202
35fc37d5
JL
1203static int
1204access_flags_to_smbopen_mode(const int access_flags)
1205{
1206 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1207
1208 if (masked_flags == GENERIC_READ)
1209 return SMBOPEN_READ;
1210 else if (masked_flags == GENERIC_WRITE)
1211 return SMBOPEN_WRITE;
1212
1213 /* just go for read/write */
1214 return SMBOPEN_READWRITE;
1215}
1216
a9d02ad4
SF
1217int
1218SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1219 const char *fileName, const int openDisposition,
ad7a2926
SF
1220 const int access_flags, const int create_options, __u16 *netfid,
1221 int *pOplock, FILE_ALL_INFO *pfile_info,
a9d02ad4
SF
1222 const struct nls_table *nls_codepage, int remap)
1223{
1224 int rc = -EACCES;
1225 OPENX_REQ *pSMB = NULL;
1226 OPENX_RSP *pSMBr = NULL;
1227 int bytes_returned;
1228 int name_len;
1229 __u16 count;
1230
1231OldOpenRetry:
1232 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1233 (void **) &pSMBr);
1234 if (rc)
1235 return rc;
1236
1237 pSMB->AndXCommand = 0xFF; /* none */
1238
1239 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1240 count = 1; /* account for one byte pad to word boundary */
1241 name_len =
1242 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1243 fileName, PATH_MAX, nls_codepage, remap);
1244 name_len++; /* trailing null */
1245 name_len *= 2;
1246 } else { /* BB improve check for buffer overruns BB */
1247 count = 0; /* no pad */
1248 name_len = strnlen(fileName, PATH_MAX);
1249 name_len++; /* trailing null */
1250 strncpy(pSMB->fileName, fileName, name_len);
1251 }
1252 if (*pOplock & REQ_OPLOCK)
1253 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
26f57364 1254 else if (*pOplock & REQ_BATCHOPLOCK)
a9d02ad4 1255 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
26f57364 1256
a9d02ad4 1257 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
35fc37d5 1258 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
a9d02ad4
SF
1259 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1260 /* set file as system file if special file such
1261 as fifo and server expecting SFU style and
1262 no Unix extensions */
1263
790fe579
SF
1264 if (create_options & CREATE_OPTION_SPECIAL)
1265 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
ad7a2926
SF
1266 else /* BB FIXME BB */
1267 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
a9d02ad4 1268
67750fb9
JL
1269 if (create_options & CREATE_OPTION_READONLY)
1270 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
a9d02ad4
SF
1271
1272 /* BB FIXME BB */
50c2f753
SF
1273/* pSMB->CreateOptions = cpu_to_le32(create_options &
1274 CREATE_OPTIONS_MASK); */
a9d02ad4 1275 /* BB FIXME END BB */
3e87d803
SF
1276
1277 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
70ca734a 1278 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
a9d02ad4
SF
1279 count += name_len;
1280 pSMB->hdr.smb_buf_length += count;
1281
1282 pSMB->ByteCount = cpu_to_le16(count);
1283 /* long_op set to 1 to allow for oplock break timeouts */
1284 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
133672ef 1285 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
a9d02ad4
SF
1286 cifs_stats_inc(&tcon->num_opens);
1287 if (rc) {
1288 cFYI(1, ("Error in Open = %d", rc));
1289 } else {
1290 /* BB verify if wct == 15 */
1291
582d21e5 1292/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
a9d02ad4
SF
1293
1294 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1295 /* Let caller know file was created so we can set the mode. */
1296 /* Do we care about the CreateAction in any other cases? */
1297 /* BB FIXME BB */
790fe579 1298/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
a9d02ad4
SF
1299 *pOplock |= CIFS_CREATE_ACTION; */
1300 /* BB FIXME END */
1301
790fe579 1302 if (pfile_info) {
a9d02ad4
SF
1303 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1304 pfile_info->LastAccessTime = 0; /* BB fixme */
1305 pfile_info->LastWriteTime = 0; /* BB fixme */
1306 pfile_info->ChangeTime = 0; /* BB fixme */
70ca734a 1307 pfile_info->Attributes =
50c2f753 1308 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
a9d02ad4 1309 /* the file_info buf is endian converted by caller */
70ca734a
SF
1310 pfile_info->AllocationSize =
1311 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1312 pfile_info->EndOfFile = pfile_info->AllocationSize;
a9d02ad4
SF
1313 pfile_info->NumberOfLinks = cpu_to_le32(1);
1314 }
1315 }
1316
1317 cifs_buf_release(pSMB);
1318 if (rc == -EAGAIN)
1319 goto OldOpenRetry;
1320 return rc;
1321}
1322
1da177e4
LT
1323int
1324CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1325 const char *fileName, const int openDisposition,
ad7a2926
SF
1326 const int access_flags, const int create_options, __u16 *netfid,
1327 int *pOplock, FILE_ALL_INFO *pfile_info,
737b758c 1328 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1329{
1330 int rc = -EACCES;
1331 OPEN_REQ *pSMB = NULL;
1332 OPEN_RSP *pSMBr = NULL;
1333 int bytes_returned;
1334 int name_len;
1335 __u16 count;
1336
1337openRetry:
1338 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1339 (void **) &pSMBr);
1340 if (rc)
1341 return rc;
1342
1343 pSMB->AndXCommand = 0xFF; /* none */
1344
1345 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1346 count = 1; /* account for one byte pad to word boundary */
1347 name_len =
b1a45695 1348 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
737b758c 1349 fileName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1350 name_len++; /* trailing null */
1351 name_len *= 2;
1352 pSMB->NameLength = cpu_to_le16(name_len);
09d1db5c 1353 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
1354 count = 0; /* no pad */
1355 name_len = strnlen(fileName, PATH_MAX);
1356 name_len++; /* trailing null */
1357 pSMB->NameLength = cpu_to_le16(name_len);
1358 strncpy(pSMB->fileName, fileName, name_len);
1359 }
1360 if (*pOplock & REQ_OPLOCK)
1361 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
26f57364 1362 else if (*pOplock & REQ_BATCHOPLOCK)
1da177e4 1363 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1da177e4
LT
1364 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1365 pSMB->AllocationSize = 0;
eda3c029
SF
1366 /* set file as system file if special file such
1367 as fifo and server expecting SFU style and
1368 no Unix extensions */
790fe579 1369 if (create_options & CREATE_OPTION_SPECIAL)
eda3c029
SF
1370 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1371 else
1372 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
67750fb9 1373
1da177e4
LT
1374 /* XP does not handle ATTR_POSIX_SEMANTICS */
1375 /* but it helps speed up case sensitive checks for other
1376 servers such as Samba */
1377 if (tcon->ses->capabilities & CAP_UNIX)
1378 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1379
67750fb9
JL
1380 if (create_options & CREATE_OPTION_READONLY)
1381 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1382
1da177e4
LT
1383 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1384 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
eda3c029 1385 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
09d1db5c
SF
1386 /* BB Expirement with various impersonation levels and verify */
1387 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1da177e4
LT
1388 pSMB->SecurityFlags =
1389 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1390
1391 count += name_len;
1392 pSMB->hdr.smb_buf_length += count;
1393
1394 pSMB->ByteCount = cpu_to_le16(count);
1395 /* long_op set to 1 to allow for oplock break timeouts */
1396 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
133672ef 1397 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
a4544347 1398 cifs_stats_inc(&tcon->num_opens);
1da177e4
LT
1399 if (rc) {
1400 cFYI(1, ("Error in Open = %d", rc));
1401 } else {
09d1db5c 1402 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1da177e4
LT
1403 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1404 /* Let caller know file was created so we can set the mode. */
1405 /* Do we care about the CreateAction in any other cases? */
790fe579 1406 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
50c2f753 1407 *pOplock |= CIFS_CREATE_ACTION;
790fe579 1408 if (pfile_info) {
50c2f753 1409 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1da177e4
LT
1410 36 /* CreationTime to Attributes */);
1411 /* the file_info buf is endian converted by caller */
1412 pfile_info->AllocationSize = pSMBr->AllocationSize;
1413 pfile_info->EndOfFile = pSMBr->EndOfFile;
1414 pfile_info->NumberOfLinks = cpu_to_le32(1);
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
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
SF
2021int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2022 int netfid, char *target_name,
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);
2076 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
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) {
1da177e4 3619 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 3620 psrch_inf->unicode = true;
1da177e4 3621 else
4b18f2a9 3622 psrch_inf->unicode = false;
1da177e4
LT
3623
3624 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
d47d7c1a 3625 psrch_inf->smallBuf = 0;
50c2f753
SF
3626 psrch_inf->srch_entries_start =
3627 (char *) &pSMBr->hdr.Protocol +
1da177e4 3628 le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
3629 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3630 le16_to_cpu(pSMBr->t2.ParameterOffset));
3631
790fe579 3632 if (parms->EndofSearch)
4b18f2a9 3633 psrch_inf->endOfSearch = true;
1da177e4 3634 else
4b18f2a9 3635 psrch_inf->endOfSearch = false;
1da177e4 3636
50c2f753
SF
3637 psrch_inf->entries_in_buffer =
3638 le16_to_cpu(parms->SearchCount);
60808233 3639 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
1da177e4 3640 psrch_inf->entries_in_buffer;
1da177e4
LT
3641 *pnetfid = parms->SearchHandle;
3642 } else {
3643 cifs_buf_release(pSMB);
3644 }
3645 }
3646
3647 return rc;
3648}
3649
3650int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
50c2f753 3651 __u16 searchHandle, struct cifs_search_info *psrch_inf)
1da177e4
LT
3652{
3653 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3654 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
ad7a2926 3655 T2_FNEXT_RSP_PARMS *parms;
1da177e4
LT
3656 char *response_data;
3657 int rc = 0;
3658 int bytes_returned, name_len;
3659 __u16 params, byte_count;
3660
3661 cFYI(1, ("In FindNext"));
3662
4b18f2a9 3663 if (psrch_inf->endOfSearch)
1da177e4
LT
3664 return -ENOENT;
3665
3666 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3667 (void **) &pSMBr);
3668 if (rc)
3669 return rc;
3670
50c2f753 3671 params = 14; /* includes 2 bytes of null string, converted to LE below*/
1da177e4
LT
3672 byte_count = 0;
3673 pSMB->TotalDataCount = 0; /* no EAs */
3674 pSMB->MaxParameterCount = cpu_to_le16(8);
3675 pSMB->MaxDataCount =
50c2f753
SF
3676 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3677 0xFFFFFF00);
1da177e4
LT
3678 pSMB->MaxSetupCount = 0;
3679 pSMB->Reserved = 0;
3680 pSMB->Flags = 0;
3681 pSMB->Timeout = 0;
3682 pSMB->Reserved2 = 0;
3683 pSMB->ParameterOffset = cpu_to_le16(
3684 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3685 pSMB->DataCount = 0;
3686 pSMB->DataOffset = 0;
3687 pSMB->SetupCount = 1;
3688 pSMB->Reserved3 = 0;
3689 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3690 pSMB->SearchHandle = searchHandle; /* always kept as le */
3691 pSMB->SearchCount =
630f3f0c 3692 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
1da177e4
LT
3693 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3694 pSMB->ResumeKey = psrch_inf->resume_key;
3695 pSMB->SearchFlags =
3696 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3697
3698 name_len = psrch_inf->resume_name_len;
3699 params += name_len;
790fe579 3700 if (name_len < PATH_MAX) {
1da177e4
LT
3701 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3702 byte_count += name_len;
ef6724e3
SF
3703 /* 14 byte parm len above enough for 2 byte null terminator */
3704 pSMB->ResumeFileName[name_len] = 0;
3705 pSMB->ResumeFileName[name_len+1] = 0;
1da177e4
LT
3706 } else {
3707 rc = -EINVAL;
3708 goto FNext2_err_exit;
3709 }
3710 byte_count = params + 1 /* pad */ ;
3711 pSMB->TotalParameterCount = cpu_to_le16(params);
3712 pSMB->ParameterCount = pSMB->TotalParameterCount;
3713 pSMB->hdr.smb_buf_length += byte_count;
3714 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 3715
1da177e4
LT
3716 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3717 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 3718 cifs_stats_inc(&tcon->num_fnext);
1da177e4
LT
3719 if (rc) {
3720 if (rc == -EBADF) {
4b18f2a9 3721 psrch_inf->endOfSearch = true;
6353450a 3722 cifs_buf_release(pSMB);
50c2f753 3723 rc = 0; /* search probably was closed at end of search*/
1da177e4
LT
3724 } else
3725 cFYI(1, ("FindNext returned = %d", rc));
3726 } else { /* decode response */
3727 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
50c2f753 3728
790fe579 3729 if (rc == 0) {
1da177e4
LT
3730 /* BB fixme add lock for file (srch_info) struct here */
3731 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 3732 psrch_inf->unicode = true;
1da177e4 3733 else
4b18f2a9 3734 psrch_inf->unicode = false;
1da177e4
LT
3735 response_data = (char *) &pSMBr->hdr.Protocol +
3736 le16_to_cpu(pSMBr->t2.ParameterOffset);
3737 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3738 response_data = (char *)&pSMBr->hdr.Protocol +
3739 le16_to_cpu(pSMBr->t2.DataOffset);
790fe579 3740 if (psrch_inf->smallBuf)
d47d7c1a
SF
3741 cifs_small_buf_release(
3742 psrch_inf->ntwrk_buf_start);
3743 else
3744 cifs_buf_release(psrch_inf->ntwrk_buf_start);
1da177e4
LT
3745 psrch_inf->srch_entries_start = response_data;
3746 psrch_inf->ntwrk_buf_start = (char *)pSMB;
d47d7c1a 3747 psrch_inf->smallBuf = 0;
790fe579 3748 if (parms->EndofSearch)
4b18f2a9 3749 psrch_inf->endOfSearch = true;
1da177e4 3750 else
4b18f2a9 3751 psrch_inf->endOfSearch = false;
50c2f753
SF
3752 psrch_inf->entries_in_buffer =
3753 le16_to_cpu(parms->SearchCount);
1da177e4
LT
3754 psrch_inf->index_of_last_entry +=
3755 psrch_inf->entries_in_buffer;
50c2f753
SF
3756/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3757 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
1da177e4
LT
3758
3759 /* BB fixme add unlock here */
3760 }
3761
3762 }
3763
3764 /* BB On error, should we leave previous search buf (and count and
3765 last entry fields) intact or free the previous one? */
3766
3767 /* Note: On -EAGAIN error only caller can retry on handle based calls
3768 since file handle passed in no longer valid */
3769FNext2_err_exit:
3770 if (rc != 0)
3771 cifs_buf_release(pSMB);
1da177e4
LT
3772 return rc;
3773}
3774
3775int
50c2f753
SF
3776CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3777 const __u16 searchHandle)
1da177e4
LT
3778{
3779 int rc = 0;
3780 FINDCLOSE_REQ *pSMB = NULL;
1da177e4
LT
3781
3782 cFYI(1, ("In CIFSSMBFindClose"));
3783 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3784
3785 /* no sense returning error if session restarted
3786 as file handle has been closed */
790fe579 3787 if (rc == -EAGAIN)
1da177e4
LT
3788 return 0;
3789 if (rc)
3790 return rc;
3791
1da177e4
LT
3792 pSMB->FileID = searchHandle;
3793 pSMB->ByteCount = 0;
133672ef 3794 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
ad7a2926 3795 if (rc)
1da177e4 3796 cERROR(1, ("Send error in FindClose = %d", rc));
ad7a2926 3797
a4544347 3798 cifs_stats_inc(&tcon->num_fclose);
1da177e4
LT
3799
3800 /* Since session is dead, search handle closed on server already */
3801 if (rc == -EAGAIN)
3802 rc = 0;
3803
3804 return rc;
3805}
3806
1da177e4
LT
3807int
3808CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
50c2f753 3809 const unsigned char *searchName,
ad7a2926 3810 __u64 *inode_number,
50c2f753 3811 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3812{
3813 int rc = 0;
3814 TRANSACTION2_QPI_REQ *pSMB = NULL;
3815 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3816 int name_len, bytes_returned;
3817 __u16 params, byte_count;
3818
50c2f753 3819 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
790fe579 3820 if (tcon == NULL)
50c2f753 3821 return -ENODEV;
1da177e4
LT
3822
3823GetInodeNumberRetry:
3824 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
50c2f753 3825 (void **) &pSMBr);
1da177e4
LT
3826 if (rc)
3827 return rc;
3828
1da177e4
LT
3829 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3830 name_len =
b1a45695 3831 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
50c2f753 3832 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3833 name_len++; /* trailing null */
3834 name_len *= 2;
50c2f753 3835 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3836 name_len = strnlen(searchName, PATH_MAX);
3837 name_len++; /* trailing null */
3838 strncpy(pSMB->FileName, searchName, name_len);
3839 }
3840
3841 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3842 pSMB->TotalDataCount = 0;
3843 pSMB->MaxParameterCount = cpu_to_le16(2);
3844 /* BB find exact max data count below from sess structure BB */
3845 pSMB->MaxDataCount = cpu_to_le16(4000);
3846 pSMB->MaxSetupCount = 0;
3847 pSMB->Reserved = 0;
3848 pSMB->Flags = 0;
3849 pSMB->Timeout = 0;
3850 pSMB->Reserved2 = 0;
3851 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 3852 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
3853 pSMB->DataCount = 0;
3854 pSMB->DataOffset = 0;
3855 pSMB->SetupCount = 1;
3856 pSMB->Reserved3 = 0;
3857 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3858 byte_count = params + 1 /* pad */ ;
3859 pSMB->TotalParameterCount = cpu_to_le16(params);
3860 pSMB->ParameterCount = pSMB->TotalParameterCount;
3861 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3862 pSMB->Reserved4 = 0;
3863 pSMB->hdr.smb_buf_length += byte_count;
3864 pSMB->ByteCount = cpu_to_le16(byte_count);
3865
3866 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3867 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3868 if (rc) {
3869 cFYI(1, ("error %d in QueryInternalInfo", rc));
3870 } else {
3871 /* decode response */
3872 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3873 if (rc || (pSMBr->ByteCount < 2))
3874 /* BB also check enough total bytes returned */
3875 /* If rc should we check for EOPNOSUPP and
3876 disable the srvino flag? or in caller? */
3877 rc = -EIO; /* bad smb */
50c2f753 3878 else {
1da177e4
LT
3879 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3880 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
50c2f753 3881 struct file_internal_info *pfinfo;
1da177e4 3882 /* BB Do we need a cast or hash here ? */
790fe579 3883 if (count < 8) {
1da177e4
LT
3884 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3885 rc = -EIO;
3886 goto GetInodeNumOut;
3887 }
3888 pfinfo = (struct file_internal_info *)
3889 (data_offset + (char *) &pSMBr->hdr.Protocol);
3890 *inode_number = pfinfo->UniqueId;
3891 }
3892 }
3893GetInodeNumOut:
3894 cifs_buf_release(pSMB);
3895 if (rc == -EAGAIN)
3896 goto GetInodeNumberRetry;
3897 return rc;
3898}
1da177e4 3899
fec4585f
IM
3900/* parses DFS refferal V3 structure
3901 * caller is responsible for freeing target_nodes
3902 * returns:
3903 * on success - 0
3904 * on failure - errno
3905 */
3906static int
a1fe78f1 3907parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
fec4585f
IM
3908 unsigned int *num_of_nodes,
3909 struct dfs_info3_param **target_nodes,
3910 const struct nls_table *nls_codepage)
3911{
3912 int i, rc = 0;
3913 char *data_end;
3914 bool is_unicode;
3915 struct dfs_referral_level_3 *ref;
3916
3917 is_unicode = pSMBr->hdr.Flags2 & SMBFLG2_UNICODE;
3918 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3919
3920 if (*num_of_nodes < 1) {
3921 cERROR(1, ("num_referrals: must be at least > 0,"
3922 "but we get num_referrals = %d\n", *num_of_nodes));
3923 rc = -EINVAL;
a1fe78f1 3924 goto parse_DFS_referrals_exit;
fec4585f
IM
3925 }
3926
3927 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
1d92cfd5 3928 if (ref->VersionNumber != cpu_to_le16(3)) {
fec4585f 3929 cERROR(1, ("Referrals of V%d version are not supported,"
1d92cfd5 3930 "should be V3", le16_to_cpu(ref->VersionNumber)));
fec4585f 3931 rc = -EINVAL;
a1fe78f1 3932 goto parse_DFS_referrals_exit;
fec4585f
IM
3933 }
3934
3935 /* get the upper boundary of the resp buffer */
3936 data_end = (char *)(&(pSMBr->PathConsumed)) +
3937 le16_to_cpu(pSMBr->t2.DataCount);
3938
3939 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3940 *num_of_nodes,
3941 le16_to_cpu(pSMBr->DFSFlags)));
3942
3943 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3944 *num_of_nodes, GFP_KERNEL);
3945 if (*target_nodes == NULL) {
3946 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3947 rc = -ENOMEM;
a1fe78f1 3948 goto parse_DFS_referrals_exit;
fec4585f
IM
3949 }
3950
3951 /* collect neccessary data from referrals */
3952 for (i = 0; i < *num_of_nodes; i++) {
3953 char *temp;
3954 int max_len;
3955 struct dfs_info3_param *node = (*target_nodes)+i;
3956
3957 node->flags = le16_to_cpu(pSMBr->DFSFlags);
3958 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3959 node->server_type = le16_to_cpu(ref->ServerType);
3960 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3961
3962 /* copy DfsPath */
3963 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3964 max_len = data_end - temp;
3965 rc = cifs_strncpy_to_host(&(node->path_name), temp,
3966 max_len, is_unicode, nls_codepage);
3967 if (rc)
a1fe78f1 3968 goto parse_DFS_referrals_exit;
fec4585f
IM
3969
3970 /* copy link target UNC */
3971 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3972 max_len = data_end - temp;
3973 rc = cifs_strncpy_to_host(&(node->node_name), temp,
3974 max_len, is_unicode, nls_codepage);
3975 if (rc)
a1fe78f1 3976 goto parse_DFS_referrals_exit;
fec4585f 3977
1d92cfd5 3978 ref += le16_to_cpu(ref->Size);
fec4585f
IM
3979 }
3980
a1fe78f1 3981parse_DFS_referrals_exit:
fec4585f
IM
3982 if (rc) {
3983 free_dfs_info_array(*target_nodes, *num_of_nodes);
3984 *target_nodes = NULL;
3985 *num_of_nodes = 0;
3986 }
3987 return rc;
3988}
3989
1da177e4
LT
3990int
3991CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3992 const unsigned char *searchName,
c2cf07d5
SF
3993 struct dfs_info3_param **target_nodes,
3994 unsigned int *num_of_nodes,
737b758c 3995 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3996{
3997/* TRANS2_GET_DFS_REFERRAL */
3998 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3999 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
1da177e4
LT
4000 int rc = 0;
4001 int bytes_returned;
4002 int name_len;
1da177e4 4003 __u16 params, byte_count;
c2cf07d5
SF
4004 *num_of_nodes = 0;
4005 *target_nodes = NULL;
1da177e4
LT
4006
4007 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4008 if (ses == NULL)
4009 return -ENODEV;
4010getDFSRetry:
4011 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4012 (void **) &pSMBr);
4013 if (rc)
4014 return rc;
50c2f753
SF
4015
4016 /* server pointer checked in called function,
1982c344
SF
4017 but should never be null here anyway */
4018 pSMB->hdr.Mid = GetNextMid(ses->server);
1da177e4
LT
4019 pSMB->hdr.Tid = ses->ipc_tid;
4020 pSMB->hdr.Uid = ses->Suid;
26f57364 4021 if (ses->capabilities & CAP_STATUS32)
1da177e4 4022 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
26f57364 4023 if (ses->capabilities & CAP_DFS)
1da177e4 4024 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
1da177e4
LT
4025
4026 if (ses->capabilities & CAP_UNICODE) {
4027 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4028 name_len =
b1a45695 4029 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
737b758c 4030 searchName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
4031 name_len++; /* trailing null */
4032 name_len *= 2;
50c2f753 4033 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4034 name_len = strnlen(searchName, PATH_MAX);
4035 name_len++; /* trailing null */
4036 strncpy(pSMB->RequestFileName, searchName, name_len);
4037 }
4038
790fe579
SF
4039 if (ses->server) {
4040 if (ses->server->secMode &
1a4e15a0
SF
4041 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4042 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4043 }
4044
50c2f753 4045 pSMB->hdr.Uid = ses->Suid;
1a4e15a0 4046
1da177e4
LT
4047 params = 2 /* level */ + name_len /*includes null */ ;
4048 pSMB->TotalDataCount = 0;
4049 pSMB->DataCount = 0;
4050 pSMB->DataOffset = 0;
4051 pSMB->MaxParameterCount = 0;
582d21e5
SF
4052 /* BB find exact max SMB PDU from sess structure BB */
4053 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
4054 pSMB->MaxSetupCount = 0;
4055 pSMB->Reserved = 0;
4056 pSMB->Flags = 0;
4057 pSMB->Timeout = 0;
4058 pSMB->Reserved2 = 0;
4059 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4060 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
1da177e4
LT
4061 pSMB->SetupCount = 1;
4062 pSMB->Reserved3 = 0;
4063 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4064 byte_count = params + 3 /* pad */ ;
4065 pSMB->ParameterCount = cpu_to_le16(params);
4066 pSMB->TotalParameterCount = pSMB->ParameterCount;
4067 pSMB->MaxReferralLevel = cpu_to_le16(3);
4068 pSMB->hdr.smb_buf_length += byte_count;
4069 pSMB->ByteCount = cpu_to_le16(byte_count);
4070
4071 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4073 if (rc) {
4074 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
c2cf07d5
SF
4075 goto GetDFSRefExit;
4076 }
4077 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4078
c2cf07d5 4079 /* BB Also check if enough total bytes returned? */
fec4585f 4080 if (rc || (pSMBr->ByteCount < 17)) {
c2cf07d5 4081 rc = -EIO; /* bad smb */
fec4585f
IM
4082 goto GetDFSRefExit;
4083 }
c2cf07d5 4084
fec4585f
IM
4085 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4086 pSMBr->ByteCount,
4087 le16_to_cpu(pSMBr->t2.DataOffset)));
1da177e4 4088
fec4585f 4089 /* parse returned result into more usable form */
a1fe78f1 4090 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
fec4585f 4091 target_nodes, nls_codepage);
c2cf07d5 4092
1da177e4 4093GetDFSRefExit:
0d817bc0 4094 cifs_buf_release(pSMB);
1da177e4
LT
4095
4096 if (rc == -EAGAIN)
4097 goto getDFSRetry;
4098
4099 return rc;
4100}
4101
20962438
SF
4102/* Query File System Info such as free space to old servers such as Win 9x */
4103int
4104SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4105{
4106/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4107 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4108 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4109 FILE_SYSTEM_ALLOC_INFO *response_data;
4110 int rc = 0;
4111 int bytes_returned = 0;
4112 __u16 params, byte_count;
4113
4114 cFYI(1, ("OldQFSInfo"));
4115oldQFSInfoRetry:
4116 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4117 (void **) &pSMBr);
4118 if (rc)
4119 return rc;
20962438
SF
4120
4121 params = 2; /* level */
4122 pSMB->TotalDataCount = 0;
4123 pSMB->MaxParameterCount = cpu_to_le16(2);
4124 pSMB->MaxDataCount = cpu_to_le16(1000);
4125 pSMB->MaxSetupCount = 0;
4126 pSMB->Reserved = 0;
4127 pSMB->Flags = 0;
4128 pSMB->Timeout = 0;
4129 pSMB->Reserved2 = 0;
4130 byte_count = params + 1 /* pad */ ;
4131 pSMB->TotalParameterCount = cpu_to_le16(params);
4132 pSMB->ParameterCount = pSMB->TotalParameterCount;
4133 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4134 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4135 pSMB->DataCount = 0;
4136 pSMB->DataOffset = 0;
4137 pSMB->SetupCount = 1;
4138 pSMB->Reserved3 = 0;
4139 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4140 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4141 pSMB->hdr.smb_buf_length += byte_count;
4142 pSMB->ByteCount = cpu_to_le16(byte_count);
4143
4144 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4145 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4146 if (rc) {
4147 cFYI(1, ("Send error in QFSInfo = %d", rc));
4148 } else { /* decode response */
4149 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4150
4151 if (rc || (pSMBr->ByteCount < 18))
4152 rc = -EIO; /* bad smb */
4153 else {
4154 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
50c2f753 4155 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
20962438
SF
4156 pSMBr->ByteCount, data_offset));
4157
50c2f753 4158 response_data = (FILE_SYSTEM_ALLOC_INFO *)
20962438
SF
4159 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4160 FSData->f_bsize =
4161 le16_to_cpu(response_data->BytesPerSector) *
4162 le32_to_cpu(response_data->
4163 SectorsPerAllocationUnit);
4164 FSData->f_blocks =
50c2f753 4165 le32_to_cpu(response_data->TotalAllocationUnits);
20962438
SF
4166 FSData->f_bfree = FSData->f_bavail =
4167 le32_to_cpu(response_data->FreeAllocationUnits);
4168 cFYI(1,
4169 ("Blocks: %lld Free: %lld Block size %ld",
4170 (unsigned long long)FSData->f_blocks,
4171 (unsigned long long)FSData->f_bfree,
4172 FSData->f_bsize));
4173 }
4174 }
4175 cifs_buf_release(pSMB);
4176
4177 if (rc == -EAGAIN)
4178 goto oldQFSInfoRetry;
4179
4180 return rc;
4181}
4182
1da177e4 4183int
737b758c 4184CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
1da177e4
LT
4185{
4186/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4187 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4188 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4189 FILE_SYSTEM_INFO *response_data;
4190 int rc = 0;
4191 int bytes_returned = 0;
4192 __u16 params, byte_count;
4193
4194 cFYI(1, ("In QFSInfo"));
4195QFSInfoRetry:
4196 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4197 (void **) &pSMBr);
4198 if (rc)
4199 return rc;
4200
4201 params = 2; /* level */
4202 pSMB->TotalDataCount = 0;
4203 pSMB->MaxParameterCount = cpu_to_le16(2);
20962438 4204 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4205 pSMB->MaxSetupCount = 0;
4206 pSMB->Reserved = 0;
4207 pSMB->Flags = 0;
4208 pSMB->Timeout = 0;
4209 pSMB->Reserved2 = 0;
4210 byte_count = params + 1 /* pad */ ;
4211 pSMB->TotalParameterCount = cpu_to_le16(params);
4212 pSMB->ParameterCount = pSMB->TotalParameterCount;
4213 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4214 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4215 pSMB->DataCount = 0;
4216 pSMB->DataOffset = 0;
4217 pSMB->SetupCount = 1;
4218 pSMB->Reserved3 = 0;
4219 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4220 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4221 pSMB->hdr.smb_buf_length += byte_count;
4222 pSMB->ByteCount = cpu_to_le16(byte_count);
4223
4224 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4225 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4226 if (rc) {
20962438 4227 cFYI(1, ("Send error in QFSInfo = %d", rc));
1da177e4 4228 } else { /* decode response */
50c2f753 4229 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4230
20962438 4231 if (rc || (pSMBr->ByteCount < 24))
1da177e4
LT
4232 rc = -EIO; /* bad smb */
4233 else {
4234 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
4235
4236 response_data =
4237 (FILE_SYSTEM_INFO
4238 *) (((char *) &pSMBr->hdr.Protocol) +
4239 data_offset);
4240 FSData->f_bsize =
4241 le32_to_cpu(response_data->BytesPerSector) *
4242 le32_to_cpu(response_data->
4243 SectorsPerAllocationUnit);
4244 FSData->f_blocks =
4245 le64_to_cpu(response_data->TotalAllocationUnits);
4246 FSData->f_bfree = FSData->f_bavail =
4247 le64_to_cpu(response_data->FreeAllocationUnits);
4248 cFYI(1,
4249 ("Blocks: %lld Free: %lld Block size %ld",
4250 (unsigned long long)FSData->f_blocks,
4251 (unsigned long long)FSData->f_bfree,
4252 FSData->f_bsize));
4253 }
4254 }
4255 cifs_buf_release(pSMB);
4256
4257 if (rc == -EAGAIN)
4258 goto QFSInfoRetry;
4259
4260 return rc;
4261}
4262
4263int
737b758c 4264CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
4265{
4266/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4267 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4268 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4269 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4270 int rc = 0;
4271 int bytes_returned = 0;
4272 __u16 params, byte_count;
4273
4274 cFYI(1, ("In QFSAttributeInfo"));
4275QFSAttributeRetry:
4276 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4277 (void **) &pSMBr);
4278 if (rc)
4279 return rc;
4280
4281 params = 2; /* level */
4282 pSMB->TotalDataCount = 0;
4283 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4284 /* BB find exact max SMB PDU from sess structure BB */
4285 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4286 pSMB->MaxSetupCount = 0;
4287 pSMB->Reserved = 0;
4288 pSMB->Flags = 0;
4289 pSMB->Timeout = 0;
4290 pSMB->Reserved2 = 0;
4291 byte_count = params + 1 /* pad */ ;
4292 pSMB->TotalParameterCount = cpu_to_le16(params);
4293 pSMB->ParameterCount = pSMB->TotalParameterCount;
4294 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4295 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4296 pSMB->DataCount = 0;
4297 pSMB->DataOffset = 0;
4298 pSMB->SetupCount = 1;
4299 pSMB->Reserved3 = 0;
4300 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4301 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4302 pSMB->hdr.smb_buf_length += byte_count;
4303 pSMB->ByteCount = cpu_to_le16(byte_count);
4304
4305 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4306 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4307 if (rc) {
4308 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4309 } else { /* decode response */
4310 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4311
50c2f753
SF
4312 if (rc || (pSMBr->ByteCount < 13)) {
4313 /* BB also check if enough bytes returned */
1da177e4
LT
4314 rc = -EIO; /* bad smb */
4315 } else {
4316 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4317 response_data =
4318 (FILE_SYSTEM_ATTRIBUTE_INFO
4319 *) (((char *) &pSMBr->hdr.Protocol) +
4320 data_offset);
4321 memcpy(&tcon->fsAttrInfo, response_data,
26f57364 4322 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
1da177e4
LT
4323 }
4324 }
4325 cifs_buf_release(pSMB);
4326
4327 if (rc == -EAGAIN)
4328 goto QFSAttributeRetry;
4329
4330 return rc;
4331}
4332
4333int
737b758c 4334CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
4335{
4336/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4337 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4338 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4339 FILE_SYSTEM_DEVICE_INFO *response_data;
4340 int rc = 0;
4341 int bytes_returned = 0;
4342 __u16 params, byte_count;
4343
4344 cFYI(1, ("In QFSDeviceInfo"));
4345QFSDeviceRetry:
4346 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4347 (void **) &pSMBr);
4348 if (rc)
4349 return rc;
4350
4351 params = 2; /* level */
4352 pSMB->TotalDataCount = 0;
4353 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4354 /* BB find exact max SMB PDU from sess structure BB */
4355 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4356 pSMB->MaxSetupCount = 0;
4357 pSMB->Reserved = 0;
4358 pSMB->Flags = 0;
4359 pSMB->Timeout = 0;
4360 pSMB->Reserved2 = 0;
4361 byte_count = params + 1 /* pad */ ;
4362 pSMB->TotalParameterCount = cpu_to_le16(params);
4363 pSMB->ParameterCount = pSMB->TotalParameterCount;
4364 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4365 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4366
4367 pSMB->DataCount = 0;
4368 pSMB->DataOffset = 0;
4369 pSMB->SetupCount = 1;
4370 pSMB->Reserved3 = 0;
4371 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4372 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4373 pSMB->hdr.smb_buf_length += byte_count;
4374 pSMB->ByteCount = cpu_to_le16(byte_count);
4375
4376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4377 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4378 if (rc) {
4379 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4380 } else { /* decode response */
4381 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4382
630f3f0c 4383 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
1da177e4
LT
4384 rc = -EIO; /* bad smb */
4385 else {
4386 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4387 response_data =
737b758c
SF
4388 (FILE_SYSTEM_DEVICE_INFO *)
4389 (((char *) &pSMBr->hdr.Protocol) +
1da177e4
LT
4390 data_offset);
4391 memcpy(&tcon->fsDevInfo, response_data,
26f57364 4392 sizeof(FILE_SYSTEM_DEVICE_INFO));
1da177e4
LT
4393 }
4394 }
4395 cifs_buf_release(pSMB);
4396
4397 if (rc == -EAGAIN)
4398 goto QFSDeviceRetry;
4399
4400 return rc;
4401}
4402
4403int
737b758c 4404CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
4405{
4406/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4407 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4408 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4409 FILE_SYSTEM_UNIX_INFO *response_data;
4410 int rc = 0;
4411 int bytes_returned = 0;
4412 __u16 params, byte_count;
4413
4414 cFYI(1, ("In QFSUnixInfo"));
4415QFSUnixRetry:
4416 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4417 (void **) &pSMBr);
4418 if (rc)
4419 return rc;
4420
4421 params = 2; /* level */
4422 pSMB->TotalDataCount = 0;
4423 pSMB->DataCount = 0;
4424 pSMB->DataOffset = 0;
4425 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4426 /* BB find exact max SMB PDU from sess structure BB */
4427 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
4428 pSMB->MaxSetupCount = 0;
4429 pSMB->Reserved = 0;
4430 pSMB->Flags = 0;
4431 pSMB->Timeout = 0;
4432 pSMB->Reserved2 = 0;
4433 byte_count = params + 1 /* pad */ ;
4434 pSMB->ParameterCount = cpu_to_le16(params);
4435 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
4436 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4437 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4438 pSMB->SetupCount = 1;
4439 pSMB->Reserved3 = 0;
4440 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4441 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4442 pSMB->hdr.smb_buf_length += byte_count;
4443 pSMB->ByteCount = cpu_to_le16(byte_count);
4444
4445 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4446 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4447 if (rc) {
4448 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4449 } else { /* decode response */
4450 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4451
4452 if (rc || (pSMBr->ByteCount < 13)) {
4453 rc = -EIO; /* bad smb */
4454 } else {
4455 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4456 response_data =
4457 (FILE_SYSTEM_UNIX_INFO
4458 *) (((char *) &pSMBr->hdr.Protocol) +
4459 data_offset);
4460 memcpy(&tcon->fsUnixInfo, response_data,
26f57364 4461 sizeof(FILE_SYSTEM_UNIX_INFO));
1da177e4
LT
4462 }
4463 }
4464 cifs_buf_release(pSMB);
4465
4466 if (rc == -EAGAIN)
4467 goto QFSUnixRetry;
4468
4469
4470 return rc;
4471}
4472
ac67055e 4473int
45abc6ee 4474CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
ac67055e
JA
4475{
4476/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4477 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4478 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4479 int rc = 0;
4480 int bytes_returned = 0;
4481 __u16 params, param_offset, offset, byte_count;
4482
4483 cFYI(1, ("In SETFSUnixInfo"));
4484SETFSUnixRetry:
f26282c9 4485 /* BB switch to small buf init to save memory */
ac67055e
JA
4486 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4487 (void **) &pSMBr);
4488 if (rc)
4489 return rc;
4490
4491 params = 4; /* 2 bytes zero followed by info level. */
4492 pSMB->MaxSetupCount = 0;
4493 pSMB->Reserved = 0;
4494 pSMB->Flags = 0;
4495 pSMB->Timeout = 0;
4496 pSMB->Reserved2 = 0;
50c2f753
SF
4497 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4498 - 4;
ac67055e
JA
4499 offset = param_offset + params;
4500
4501 pSMB->MaxParameterCount = cpu_to_le16(4);
582d21e5
SF
4502 /* BB find exact max SMB PDU from sess structure BB */
4503 pSMB->MaxDataCount = cpu_to_le16(100);
ac67055e
JA
4504 pSMB->SetupCount = 1;
4505 pSMB->Reserved3 = 0;
4506 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4507 byte_count = 1 /* pad */ + params + 12;
4508
4509 pSMB->DataCount = cpu_to_le16(12);
4510 pSMB->ParameterCount = cpu_to_le16(params);
4511 pSMB->TotalDataCount = pSMB->DataCount;
4512 pSMB->TotalParameterCount = pSMB->ParameterCount;
4513 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4514 pSMB->DataOffset = cpu_to_le16(offset);
4515
4516 /* Params. */
4517 pSMB->FileNum = 0;
4518 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4519
4520 /* Data. */
4521 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4522 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4523 pSMB->ClientUnixCap = cpu_to_le64(cap);
4524
4525 pSMB->hdr.smb_buf_length += byte_count;
4526 pSMB->ByteCount = cpu_to_le16(byte_count);
4527
4528 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4529 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4530 if (rc) {
4531 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4532 } else { /* decode response */
4533 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
ad7a2926 4534 if (rc)
ac67055e 4535 rc = -EIO; /* bad smb */
ac67055e
JA
4536 }
4537 cifs_buf_release(pSMB);
4538
4539 if (rc == -EAGAIN)
4540 goto SETFSUnixRetry;
4541
4542 return rc;
4543}
4544
4545
1da177e4
LT
4546
4547int
4548CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
737b758c 4549 struct kstatfs *FSData)
1da177e4
LT
4550{
4551/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4552 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4553 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4554 FILE_SYSTEM_POSIX_INFO *response_data;
4555 int rc = 0;
4556 int bytes_returned = 0;
4557 __u16 params, byte_count;
4558
4559 cFYI(1, ("In QFSPosixInfo"));
4560QFSPosixRetry:
4561 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4562 (void **) &pSMBr);
4563 if (rc)
4564 return rc;
4565
4566 params = 2; /* level */
4567 pSMB->TotalDataCount = 0;
4568 pSMB->DataCount = 0;
4569 pSMB->DataOffset = 0;
4570 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4571 /* BB find exact max SMB PDU from sess structure BB */
4572 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
4573 pSMB->MaxSetupCount = 0;
4574 pSMB->Reserved = 0;
4575 pSMB->Flags = 0;
4576 pSMB->Timeout = 0;
4577 pSMB->Reserved2 = 0;
4578 byte_count = params + 1 /* pad */ ;
4579 pSMB->ParameterCount = cpu_to_le16(params);
4580 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
4581 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4582 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4583 pSMB->SetupCount = 1;
4584 pSMB->Reserved3 = 0;
4585 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4586 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4587 pSMB->hdr.smb_buf_length += byte_count;
4588 pSMB->ByteCount = cpu_to_le16(byte_count);
4589
4590 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4591 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4592 if (rc) {
4593 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4594 } else { /* decode response */
4595 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4596
4597 if (rc || (pSMBr->ByteCount < 13)) {
4598 rc = -EIO; /* bad smb */
4599 } else {
4600 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4601 response_data =
4602 (FILE_SYSTEM_POSIX_INFO
4603 *) (((char *) &pSMBr->hdr.Protocol) +
4604 data_offset);
4605 FSData->f_bsize =
4606 le32_to_cpu(response_data->BlockSize);
4607 FSData->f_blocks =
4608 le64_to_cpu(response_data->TotalBlocks);
4609 FSData->f_bfree =
4610 le64_to_cpu(response_data->BlocksAvail);
790fe579 4611 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
1da177e4
LT
4612 FSData->f_bavail = FSData->f_bfree;
4613 } else {
4614 FSData->f_bavail =
50c2f753 4615 le64_to_cpu(response_data->UserBlocksAvail);
1da177e4 4616 }
790fe579 4617 if (response_data->TotalFileNodes != cpu_to_le64(-1))
1da177e4 4618 FSData->f_files =
50c2f753 4619 le64_to_cpu(response_data->TotalFileNodes);
790fe579 4620 if (response_data->FreeFileNodes != cpu_to_le64(-1))
1da177e4 4621 FSData->f_ffree =
50c2f753 4622 le64_to_cpu(response_data->FreeFileNodes);
1da177e4
LT
4623 }
4624 }
4625 cifs_buf_release(pSMB);
4626
4627 if (rc == -EAGAIN)
4628 goto QFSPosixRetry;
4629
4630 return rc;
4631}
4632
4633
50c2f753
SF
4634/* We can not use write of zero bytes trick to
4635 set file size due to need for large file support. Also note that
4636 this SetPathInfo is preferred to SetFileInfo based method in next
1da177e4
LT
4637 routine which is only needed to work around a sharing violation bug
4638 in Samba which this routine can run into */
4639
4640int
4641CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4b18f2a9 4642 __u64 size, bool SetAllocation,
737b758c 4643 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4644{
4645 struct smb_com_transaction2_spi_req *pSMB = NULL;
4646 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4647 struct file_end_of_file_info *parm_data;
4648 int name_len;
4649 int rc = 0;
4650 int bytes_returned = 0;
4651 __u16 params, byte_count, data_count, param_offset, offset;
4652
4653 cFYI(1, ("In SetEOF"));
4654SetEOFRetry:
4655 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4656 (void **) &pSMBr);
4657 if (rc)
4658 return rc;
4659
4660 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4661 name_len =
b1a45695 4662 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 4663 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4664 name_len++; /* trailing null */
4665 name_len *= 2;
3e87d803 4666 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4667 name_len = strnlen(fileName, PATH_MAX);
4668 name_len++; /* trailing null */
4669 strncpy(pSMB->FileName, fileName, name_len);
4670 }
4671 params = 6 + name_len;
26f57364 4672 data_count = sizeof(struct file_end_of_file_info);
1da177e4 4673 pSMB->MaxParameterCount = cpu_to_le16(2);
3e87d803 4674 pSMB->MaxDataCount = cpu_to_le16(4100);
1da177e4
LT
4675 pSMB->MaxSetupCount = 0;
4676 pSMB->Reserved = 0;
4677 pSMB->Flags = 0;
4678 pSMB->Timeout = 0;
4679 pSMB->Reserved2 = 0;
4680 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 4681 InformationLevel) - 4;
1da177e4 4682 offset = param_offset + params;
790fe579 4683 if (SetAllocation) {
50c2f753
SF
4684 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4685 pSMB->InformationLevel =
4686 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4687 else
4688 pSMB->InformationLevel =
4689 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4690 } else /* Set File Size */ {
1da177e4
LT
4691 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4692 pSMB->InformationLevel =
50c2f753 4693 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
4694 else
4695 pSMB->InformationLevel =
50c2f753 4696 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
4697 }
4698
4699 parm_data =
4700 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4701 offset);
4702 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4703 pSMB->DataOffset = cpu_to_le16(offset);
4704 pSMB->SetupCount = 1;
4705 pSMB->Reserved3 = 0;
4706 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4707 byte_count = 3 /* pad */ + params + data_count;
4708 pSMB->DataCount = cpu_to_le16(data_count);
4709 pSMB->TotalDataCount = pSMB->DataCount;
4710 pSMB->ParameterCount = cpu_to_le16(params);
4711 pSMB->TotalParameterCount = pSMB->ParameterCount;
4712 pSMB->Reserved4 = 0;
4713 pSMB->hdr.smb_buf_length += byte_count;
4714 parm_data->FileSize = cpu_to_le64(size);
4715 pSMB->ByteCount = cpu_to_le16(byte_count);
4716 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4717 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 4718 if (rc)
1da177e4 4719 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
1da177e4
LT
4720
4721 cifs_buf_release(pSMB);
4722
4723 if (rc == -EAGAIN)
4724 goto SetEOFRetry;
4725
4726 return rc;
4727}
4728
4729int
50c2f753 4730CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4b18f2a9 4731 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
1da177e4
LT
4732{
4733 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
4734 char *data_offset;
4735 struct file_end_of_file_info *parm_data;
4736 int rc = 0;
1da177e4
LT
4737 __u16 params, param_offset, offset, byte_count, count;
4738
4739 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4740 (long long)size));
cd63499c
SF
4741 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4742
1da177e4
LT
4743 if (rc)
4744 return rc;
4745
4746 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4747 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
50c2f753 4748
1da177e4
LT
4749 params = 6;
4750 pSMB->MaxSetupCount = 0;
4751 pSMB->Reserved = 0;
4752 pSMB->Flags = 0;
4753 pSMB->Timeout = 0;
4754 pSMB->Reserved2 = 0;
4755 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4756 offset = param_offset + params;
4757
50c2f753 4758 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1da177e4
LT
4759
4760 count = sizeof(struct file_end_of_file_info);
4761 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4762 /* BB find exact max SMB PDU from sess structure BB */
4763 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4764 pSMB->SetupCount = 1;
4765 pSMB->Reserved3 = 0;
4766 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4767 byte_count = 3 /* pad */ + params + count;
4768 pSMB->DataCount = cpu_to_le16(count);
4769 pSMB->ParameterCount = cpu_to_le16(params);
4770 pSMB->TotalDataCount = pSMB->DataCount;
4771 pSMB->TotalParameterCount = pSMB->ParameterCount;
4772 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4773 parm_data =
50c2f753
SF
4774 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4775 + offset);
1da177e4
LT
4776 pSMB->DataOffset = cpu_to_le16(offset);
4777 parm_data->FileSize = cpu_to_le64(size);
4778 pSMB->Fid = fid;
790fe579 4779 if (SetAllocation) {
1da177e4
LT
4780 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4781 pSMB->InformationLevel =
4782 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4783 else
4784 pSMB->InformationLevel =
4785 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
50c2f753 4786 } else /* Set File Size */ {
1da177e4
LT
4787 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4788 pSMB->InformationLevel =
50c2f753 4789 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
4790 else
4791 pSMB->InformationLevel =
50c2f753 4792 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
4793 }
4794 pSMB->Reserved4 = 0;
4795 pSMB->hdr.smb_buf_length += byte_count;
4796 pSMB->ByteCount = cpu_to_le16(byte_count);
133672ef 4797 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1da177e4
LT
4798 if (rc) {
4799 cFYI(1,
4800 ("Send error in SetFileInfo (SetFileSize) = %d",
4801 rc));
4802 }
4803
50c2f753 4804 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
4805 since file handle passed in no longer valid */
4806
4807 return rc;
4808}
4809
50c2f753 4810/* Some legacy servers such as NT4 require that the file times be set on
1da177e4
LT
4811 an open handle, rather than by pathname - this is awkward due to
4812 potential access conflicts on the open, but it is unavoidable for these
4813 old servers since the only other choice is to go from 100 nanosecond DCE
4814 time and resort to the original setpathinfo level which takes the ancient
4815 DOS time format with 2 second granularity */
4816int
50c2f753
SF
4817CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4818 const FILE_BASIC_INFO *data, __u16 fid)
1da177e4
LT
4819{
4820 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
4821 char *data_offset;
4822 int rc = 0;
1da177e4
LT
4823 __u16 params, param_offset, offset, byte_count, count;
4824
4825 cFYI(1, ("Set Times (via SetFileInfo)"));
cd63499c
SF
4826 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4827
1da177e4
LT
4828 if (rc)
4829 return rc;
4830
4831 /* At this point there is no need to override the current pid
4832 with the pid of the opener, but that could change if we someday
4833 use an existing handle (rather than opening one on the fly) */
4834 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4835 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
50c2f753 4836
1da177e4
LT
4837 params = 6;
4838 pSMB->MaxSetupCount = 0;
4839 pSMB->Reserved = 0;
4840 pSMB->Flags = 0;
4841 pSMB->Timeout = 0;
4842 pSMB->Reserved2 = 0;
4843 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4844 offset = param_offset + params;
4845
50c2f753 4846 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1da177e4 4847
26f57364 4848 count = sizeof(FILE_BASIC_INFO);
1da177e4 4849 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4850 /* BB find max SMB PDU from sess */
4851 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4852 pSMB->SetupCount = 1;
4853 pSMB->Reserved3 = 0;
4854 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4855 byte_count = 3 /* pad */ + params + count;
4856 pSMB->DataCount = cpu_to_le16(count);
4857 pSMB->ParameterCount = cpu_to_le16(params);
4858 pSMB->TotalDataCount = pSMB->DataCount;
4859 pSMB->TotalParameterCount = pSMB->ParameterCount;
4860 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4861 pSMB->DataOffset = cpu_to_le16(offset);
4862 pSMB->Fid = fid;
4863 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4864 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4865 else
4866 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4867 pSMB->Reserved4 = 0;
4868 pSMB->hdr.smb_buf_length += byte_count;
4869 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 4870 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
133672ef 4871 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
ad7a2926 4872 if (rc)
50c2f753 4873 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
1da177e4 4874
50c2f753 4875 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
4876 since file handle passed in no longer valid */
4877
4878 return rc;
4879}
4880
4881
4882int
4883CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
50c2f753 4884 const FILE_BASIC_INFO *data,
737b758c 4885 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4886{
4887 TRANSACTION2_SPI_REQ *pSMB = NULL;
4888 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4889 int name_len;
4890 int rc = 0;
4891 int bytes_returned = 0;
4892 char *data_offset;
4893 __u16 params, param_offset, offset, byte_count, count;
4894
4895 cFYI(1, ("In SetTimes"));
4896
4897SetTimesRetry:
4898 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4899 (void **) &pSMBr);
4900 if (rc)
4901 return rc;
4902
4903 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4904 name_len =
b1a45695 4905 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 4906 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4907 name_len++; /* trailing null */
4908 name_len *= 2;
50c2f753 4909 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4910 name_len = strnlen(fileName, PATH_MAX);
4911 name_len++; /* trailing null */
4912 strncpy(pSMB->FileName, fileName, name_len);
4913 }
4914
4915 params = 6 + name_len;
26f57364 4916 count = sizeof(FILE_BASIC_INFO);
1da177e4 4917 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4918 /* BB find max SMB PDU from sess structure BB */
4919 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4920 pSMB->MaxSetupCount = 0;
4921 pSMB->Reserved = 0;
4922 pSMB->Flags = 0;
4923 pSMB->Timeout = 0;
4924 pSMB->Reserved2 = 0;
4925 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 4926 InformationLevel) - 4;
1da177e4
LT
4927 offset = param_offset + params;
4928 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4929 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4930 pSMB->DataOffset = cpu_to_le16(offset);
4931 pSMB->SetupCount = 1;
4932 pSMB->Reserved3 = 0;
4933 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4934 byte_count = 3 /* pad */ + params + count;
4935
4936 pSMB->DataCount = cpu_to_le16(count);
4937 pSMB->ParameterCount = cpu_to_le16(params);
4938 pSMB->TotalDataCount = pSMB->DataCount;
4939 pSMB->TotalParameterCount = pSMB->ParameterCount;
4940 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4941 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4942 else
4943 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4944 pSMB->Reserved4 = 0;
4945 pSMB->hdr.smb_buf_length += byte_count;
26f57364 4946 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
1da177e4
LT
4947 pSMB->ByteCount = cpu_to_le16(byte_count);
4948 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4949 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 4950 if (rc)
1da177e4 4951 cFYI(1, ("SetPathInfo (times) returned %d", rc));
1da177e4
LT
4952
4953 cifs_buf_release(pSMB);
4954
4955 if (rc == -EAGAIN)
4956 goto SetTimesRetry;
4957
4958 return rc;
4959}
4960
4961/* Can not be used to set time stamps yet (due to old DOS time format) */
4962/* Can be used to set attributes */
4963#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4964 handling it anyway and NT4 was what we thought it would be needed for
4965 Do not delete it until we prove whether needed for Win9x though */
4966int
4967CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4968 __u16 dos_attrs, const struct nls_table *nls_codepage)
4969{
4970 SETATTR_REQ *pSMB = NULL;
4971 SETATTR_RSP *pSMBr = NULL;
4972 int rc = 0;
4973 int bytes_returned;
4974 int name_len;
4975
4976 cFYI(1, ("In SetAttrLegacy"));
4977
4978SetAttrLgcyRetry:
4979 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4980 (void **) &pSMBr);
4981 if (rc)
4982 return rc;
4983
4984 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4985 name_len =
50c2f753 4986 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
1da177e4
LT
4987 PATH_MAX, nls_codepage);
4988 name_len++; /* trailing null */
4989 name_len *= 2;
50c2f753 4990 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4991 name_len = strnlen(fileName, PATH_MAX);
4992 name_len++; /* trailing null */
4993 strncpy(pSMB->fileName, fileName, name_len);
4994 }
4995 pSMB->attr = cpu_to_le16(dos_attrs);
4996 pSMB->BufferFormat = 0x04;
4997 pSMB->hdr.smb_buf_length += name_len + 1;
4998 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5001 if (rc)
1da177e4 5002 cFYI(1, ("Error in LegacySetAttr = %d", rc));
1da177e4
LT
5003
5004 cifs_buf_release(pSMB);
5005
5006 if (rc == -EAGAIN)
5007 goto SetAttrLgcyRetry;
5008
5009 return rc;
5010}
5011#endif /* temporarily unneeded SetAttr legacy function */
5012
5013int
5014CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
50c2f753
SF
5015 char *fileName, __u64 mode, __u64 uid, __u64 gid,
5016 dev_t device, const struct nls_table *nls_codepage,
737b758c 5017 int remap)
1da177e4
LT
5018{
5019 TRANSACTION2_SPI_REQ *pSMB = NULL;
5020 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5021 int name_len;
5022 int rc = 0;
5023 int bytes_returned = 0;
5024 FILE_UNIX_BASIC_INFO *data_offset;
5025 __u16 params, param_offset, offset, count, byte_count;
5026
5027 cFYI(1, ("In SetUID/GID/Mode"));
5028setPermsRetry:
5029 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5030 (void **) &pSMBr);
5031 if (rc)
5032 return rc;
5033
5034 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5035 name_len =
50c2f753 5036 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 5037 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5038 name_len++; /* trailing null */
5039 name_len *= 2;
3e87d803 5040 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5041 name_len = strnlen(fileName, PATH_MAX);
5042 name_len++; /* trailing null */
5043 strncpy(pSMB->FileName, fileName, name_len);
5044 }
5045
5046 params = 6 + name_len;
26f57364 5047 count = sizeof(FILE_UNIX_BASIC_INFO);
1da177e4 5048 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5049 /* BB find max SMB PDU from sess structure BB */
5050 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5051 pSMB->MaxSetupCount = 0;
5052 pSMB->Reserved = 0;
5053 pSMB->Flags = 0;
5054 pSMB->Timeout = 0;
5055 pSMB->Reserved2 = 0;
5056 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5057 InformationLevel) - 4;
1da177e4
LT
5058 offset = param_offset + params;
5059 data_offset =
5060 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5061 offset);
5062 memset(data_offset, 0, count);
5063 pSMB->DataOffset = cpu_to_le16(offset);
5064 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5065 pSMB->SetupCount = 1;
5066 pSMB->Reserved3 = 0;
5067 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5068 byte_count = 3 /* pad */ + params + count;
5069 pSMB->ParameterCount = cpu_to_le16(params);
5070 pSMB->DataCount = cpu_to_le16(count);
5071 pSMB->TotalParameterCount = pSMB->ParameterCount;
5072 pSMB->TotalDataCount = pSMB->DataCount;
5073 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5074 pSMB->Reserved4 = 0;
5075 pSMB->hdr.smb_buf_length += byte_count;
c7af1857
SF
5076 /* Samba server ignores set of file size to zero due to bugs in some
5077 older clients, but we should be precise - we use SetFileSize to
5078 set file size and do not want to truncate file size to zero
5079 accidently as happened on one Samba server beta by putting
50c2f753 5080 zero instead of -1 here */
c7af1857
SF
5081 data_offset->EndOfFile = NO_CHANGE_64;
5082 data_offset->NumOfBytes = NO_CHANGE_64;
5083 data_offset->LastStatusChange = NO_CHANGE_64;
5084 data_offset->LastAccessTime = NO_CHANGE_64;
5085 data_offset->LastModificationTime = NO_CHANGE_64;
1da177e4
LT
5086 data_offset->Uid = cpu_to_le64(uid);
5087 data_offset->Gid = cpu_to_le64(gid);
5088 /* better to leave device as zero when it is */
5089 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5090 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5091 data_offset->Permissions = cpu_to_le64(mode);
50c2f753 5092
790fe579 5093 if (S_ISREG(mode))
1da177e4 5094 data_offset->Type = cpu_to_le32(UNIX_FILE);
790fe579 5095 else if (S_ISDIR(mode))
1da177e4 5096 data_offset->Type = cpu_to_le32(UNIX_DIR);
790fe579 5097 else if (S_ISLNK(mode))
1da177e4 5098 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
790fe579 5099 else if (S_ISCHR(mode))
1da177e4 5100 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
790fe579 5101 else if (S_ISBLK(mode))
1da177e4 5102 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
790fe579 5103 else if (S_ISFIFO(mode))
1da177e4 5104 data_offset->Type = cpu_to_le32(UNIX_FIFO);
790fe579 5105 else if (S_ISSOCK(mode))
1da177e4
LT
5106 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5107
5108
5109 pSMB->ByteCount = cpu_to_le16(byte_count);
5110 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5111 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5112 if (rc)
1da177e4 5113 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
1da177e4 5114
0d817bc0 5115 cifs_buf_release(pSMB);
1da177e4
LT
5116 if (rc == -EAGAIN)
5117 goto setPermsRetry;
5118 return rc;
5119}
5120
50c2f753 5121int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
167a251a 5122 const int notify_subdirs, const __u16 netfid,
50c2f753 5123 __u32 filter, struct file *pfile, int multishot,
167a251a 5124 const struct nls_table *nls_codepage)
1da177e4
LT
5125{
5126 int rc = 0;
50c2f753
SF
5127 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5128 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
abb15b8a 5129 struct dir_notify_req *dnotify_req;
1da177e4
LT
5130 int bytes_returned;
5131
50c2f753 5132 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
1da177e4 5133 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
50c2f753 5134 (void **) &pSMBr);
1da177e4
LT
5135 if (rc)
5136 return rc;
5137
5138 pSMB->TotalParameterCount = 0 ;
5139 pSMB->TotalDataCount = 0;
5140 pSMB->MaxParameterCount = cpu_to_le32(2);
5141 /* BB find exact data count max from sess structure BB */
5142 pSMB->MaxDataCount = 0; /* same in little endian or be */
0a4b92c0
SF
5143/* BB VERIFY verify which is correct for above BB */
5144 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5145 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5146
1da177e4
LT
5147 pSMB->MaxSetupCount = 4;
5148 pSMB->Reserved = 0;
5149 pSMB->ParameterOffset = 0;
5150 pSMB->DataCount = 0;
5151 pSMB->DataOffset = 0;
5152 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5153 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5154 pSMB->ParameterCount = pSMB->TotalParameterCount;
790fe579 5155 if (notify_subdirs)
1da177e4
LT
5156 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5157 pSMB->Reserved2 = 0;
5158 pSMB->CompletionFilter = cpu_to_le32(filter);
5159 pSMB->Fid = netfid; /* file handle always le */
5160 pSMB->ByteCount = 0;
5161
5162 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
133672ef
SF
5163 (struct smb_hdr *)pSMBr, &bytes_returned,
5164 CIFS_ASYNC_OP);
1da177e4
LT
5165 if (rc) {
5166 cFYI(1, ("Error in Notify = %d", rc));
ff5dbd9e
SF
5167 } else {
5168 /* Add file to outstanding requests */
50c2f753 5169 /* BB change to kmem cache alloc */
5cbded58 5170 dnotify_req = kmalloc(
47c786e7
SF
5171 sizeof(struct dir_notify_req),
5172 GFP_KERNEL);
790fe579 5173 if (dnotify_req) {
47c786e7
SF
5174 dnotify_req->Pid = pSMB->hdr.Pid;
5175 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5176 dnotify_req->Mid = pSMB->hdr.Mid;
5177 dnotify_req->Tid = pSMB->hdr.Tid;
5178 dnotify_req->Uid = pSMB->hdr.Uid;
5179 dnotify_req->netfid = netfid;
5180 dnotify_req->pfile = pfile;
5181 dnotify_req->filter = filter;
5182 dnotify_req->multishot = multishot;
5183 spin_lock(&GlobalMid_Lock);
50c2f753 5184 list_add_tail(&dnotify_req->lhead,
47c786e7
SF
5185 &GlobalDnotifyReqList);
5186 spin_unlock(&GlobalMid_Lock);
50c2f753 5187 } else
47c786e7 5188 rc = -ENOMEM;
1da177e4
LT
5189 }
5190 cifs_buf_release(pSMB);
50c2f753 5191 return rc;
1da177e4
LT
5192}
5193#ifdef CONFIG_CIFS_XATTR
5194ssize_t
5195CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5196 const unsigned char *searchName,
50c2f753 5197 char *EAData, size_t buf_size,
737b758c 5198 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5199{
5200 /* BB assumes one setup word */
5201 TRANSACTION2_QPI_REQ *pSMB = NULL;
5202 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5203 int rc = 0;
5204 int bytes_returned;
5205 int name_len;
50c2f753
SF
5206 struct fea *temp_fea;
5207 char *temp_ptr;
1da177e4
LT
5208 __u16 params, byte_count;
5209
5210 cFYI(1, ("In Query All EAs path %s", searchName));
5211QAllEAsRetry:
5212 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5213 (void **) &pSMBr);
5214 if (rc)
5215 return rc;
5216
5217 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5218 name_len =
50c2f753 5219 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 5220 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5221 name_len++; /* trailing null */
5222 name_len *= 2;
5223 } else { /* BB improve the check for buffer overruns BB */
5224 name_len = strnlen(searchName, PATH_MAX);
5225 name_len++; /* trailing null */
5226 strncpy(pSMB->FileName, searchName, name_len);
5227 }
5228
50c2f753 5229 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
5230 pSMB->TotalDataCount = 0;
5231 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5232 /* BB find exact max SMB PDU from sess structure BB */
5233 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
5234 pSMB->MaxSetupCount = 0;
5235 pSMB->Reserved = 0;
5236 pSMB->Flags = 0;
5237 pSMB->Timeout = 0;
5238 pSMB->Reserved2 = 0;
5239 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 5240 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
5241 pSMB->DataCount = 0;
5242 pSMB->DataOffset = 0;
5243 pSMB->SetupCount = 1;
5244 pSMB->Reserved3 = 0;
5245 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5246 byte_count = params + 1 /* pad */ ;
5247 pSMB->TotalParameterCount = cpu_to_le16(params);
5248 pSMB->ParameterCount = pSMB->TotalParameterCount;
5249 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5250 pSMB->Reserved4 = 0;
5251 pSMB->hdr.smb_buf_length += byte_count;
5252 pSMB->ByteCount = cpu_to_le16(byte_count);
5253
5254 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5255 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5256 if (rc) {
5257 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5258 } else { /* decode response */
5259 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5260
5261 /* BB also check enough total bytes returned */
5262 /* BB we need to improve the validity checking
5263 of these trans2 responses */
50c2f753 5264 if (rc || (pSMBr->ByteCount < 4))
1da177e4
LT
5265 rc = -EIO; /* bad smb */
5266 /* else if (pFindData){
5267 memcpy((char *) pFindData,
5268 (char *) &pSMBr->hdr.Protocol +
5269 data_offset, kl);
5270 }*/ else {
5271 /* check that length of list is not more than bcc */
5272 /* check that each entry does not go beyond length
5273 of list */
5274 /* check that each element of each entry does not
5275 go beyond end of list */
5276 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
50c2f753 5277 struct fealist *ea_response_data;
1da177e4
LT
5278 rc = 0;
5279 /* validate_trans2_offsets() */
790fe579 5280 /* BB check if start of smb + data_offset > &bcc+ bcc */
1da177e4
LT
5281 ea_response_data = (struct fealist *)
5282 (((char *) &pSMBr->hdr.Protocol) +
5283 data_offset);
5284 name_len = le32_to_cpu(ea_response_data->list_len);
50c2f753 5285 cFYI(1, ("ea length %d", name_len));
790fe579 5286 if (name_len <= 8) {
1da177e4 5287 /* returned EA size zeroed at top of function */
50c2f753 5288 cFYI(1, ("empty EA list returned from server"));
1da177e4
LT
5289 } else {
5290 /* account for ea list len */
5291 name_len -= 4;
5292 temp_fea = ea_response_data->list;
5293 temp_ptr = (char *)temp_fea;
50c2f753 5294 while (name_len > 0) {
1da177e4
LT
5295 __u16 value_len;
5296 name_len -= 4;
5297 temp_ptr += 4;
5298 rc += temp_fea->name_len;
5299 /* account for prefix user. and trailing null */
790fe579
SF
5300 rc = rc + 5 + 1;
5301 if (rc < (int)buf_size) {
50c2f753
SF
5302 memcpy(EAData, "user.", 5);
5303 EAData += 5;
5304 memcpy(EAData, temp_ptr,
5305 temp_fea->name_len);
5306 EAData += temp_fea->name_len;
1da177e4
LT
5307 /* null terminate name */
5308 *EAData = 0;
5309 EAData = EAData + 1;
790fe579 5310 } else if (buf_size == 0) {
1da177e4
LT
5311 /* skip copy - calc size only */
5312 } else {
5313 /* stop before overrun buffer */
5314 rc = -ERANGE;
5315 break;
5316 }
5317 name_len -= temp_fea->name_len;
5318 temp_ptr += temp_fea->name_len;
5319 /* account for trailing null */
5320 name_len--;
5321 temp_ptr++;
50c2f753
SF
5322 value_len =
5323 le16_to_cpu(temp_fea->value_len);
1da177e4
LT
5324 name_len -= value_len;
5325 temp_ptr += value_len;
50c2f753
SF
5326 /* BB check that temp_ptr is still
5327 within the SMB BB*/
5328
5329 /* no trailing null to account for
5330 in value len */
1da177e4
LT
5331 /* go on to next EA */
5332 temp_fea = (struct fea *)temp_ptr;
5333 }
5334 }
5335 }
5336 }
0d817bc0 5337 cifs_buf_release(pSMB);
1da177e4
LT
5338 if (rc == -EAGAIN)
5339 goto QAllEAsRetry;
5340
5341 return (ssize_t)rc;
5342}
5343
50c2f753
SF
5344ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5345 const unsigned char *searchName, const unsigned char *ea_name,
5346 unsigned char *ea_value, size_t buf_size,
737b758c 5347 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5348{
5349 TRANSACTION2_QPI_REQ *pSMB = NULL;
5350 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5351 int rc = 0;
5352 int bytes_returned;
5353 int name_len;
50c2f753
SF
5354 struct fea *temp_fea;
5355 char *temp_ptr;
1da177e4
LT
5356 __u16 params, byte_count;
5357
5358 cFYI(1, ("In Query EA path %s", searchName));
5359QEARetry:
5360 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5361 (void **) &pSMBr);
5362 if (rc)
5363 return rc;
5364
5365 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5366 name_len =
50c2f753 5367 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 5368 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5369 name_len++; /* trailing null */
5370 name_len *= 2;
5371 } else { /* BB improve the check for buffer overruns BB */
5372 name_len = strnlen(searchName, PATH_MAX);
5373 name_len++; /* trailing null */
5374 strncpy(pSMB->FileName, searchName, name_len);
5375 }
5376
50c2f753 5377 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
5378 pSMB->TotalDataCount = 0;
5379 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5380 /* BB find exact max SMB PDU from sess structure BB */
5381 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
5382 pSMB->MaxSetupCount = 0;
5383 pSMB->Reserved = 0;
5384 pSMB->Flags = 0;
5385 pSMB->Timeout = 0;
5386 pSMB->Reserved2 = 0;
5387 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 5388 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
5389 pSMB->DataCount = 0;
5390 pSMB->DataOffset = 0;
5391 pSMB->SetupCount = 1;
5392 pSMB->Reserved3 = 0;
5393 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5394 byte_count = params + 1 /* pad */ ;
5395 pSMB->TotalParameterCount = cpu_to_le16(params);
5396 pSMB->ParameterCount = pSMB->TotalParameterCount;
5397 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5398 pSMB->Reserved4 = 0;
5399 pSMB->hdr.smb_buf_length += byte_count;
5400 pSMB->ByteCount = cpu_to_le16(byte_count);
5401
5402 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5403 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5404 if (rc) {
5405 cFYI(1, ("Send error in Query EA = %d", rc));
5406 } else { /* decode response */
5407 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5408
5409 /* BB also check enough total bytes returned */
5410 /* BB we need to improve the validity checking
5411 of these trans2 responses */
50c2f753 5412 if (rc || (pSMBr->ByteCount < 4))
1da177e4
LT
5413 rc = -EIO; /* bad smb */
5414 /* else if (pFindData){
5415 memcpy((char *) pFindData,
5416 (char *) &pSMBr->hdr.Protocol +
5417 data_offset, kl);
5418 }*/ else {
5419 /* check that length of list is not more than bcc */
5420 /* check that each entry does not go beyond length
5421 of list */
5422 /* check that each element of each entry does not
5423 go beyond end of list */
5424 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
50c2f753 5425 struct fealist *ea_response_data;
1da177e4
LT
5426 rc = -ENODATA;
5427 /* validate_trans2_offsets() */
790fe579 5428 /* BB check if start of smb + data_offset > &bcc+ bcc*/
1da177e4
LT
5429 ea_response_data = (struct fealist *)
5430 (((char *) &pSMBr->hdr.Protocol) +
5431 data_offset);
5432 name_len = le32_to_cpu(ea_response_data->list_len);
50c2f753 5433 cFYI(1, ("ea length %d", name_len));
790fe579 5434 if (name_len <= 8) {
1da177e4 5435 /* returned EA size zeroed at top of function */
50c2f753 5436 cFYI(1, ("empty EA list returned from server"));
1da177e4
LT
5437 } else {
5438 /* account for ea list len */
5439 name_len -= 4;
5440 temp_fea = ea_response_data->list;
5441 temp_ptr = (char *)temp_fea;
5442 /* loop through checking if we have a matching
5443 name and then return the associated value */
50c2f753 5444 while (name_len > 0) {
1da177e4
LT
5445 __u16 value_len;
5446 name_len -= 4;
5447 temp_ptr += 4;
50c2f753
SF
5448 value_len =
5449 le16_to_cpu(temp_fea->value_len);
5450 /* BB validate that value_len falls within SMB,
5451 even though maximum for name_len is 255 */
790fe579 5452 if (memcmp(temp_fea->name, ea_name,
1da177e4
LT
5453 temp_fea->name_len) == 0) {
5454 /* found a match */
5455 rc = value_len;
5456 /* account for prefix user. and trailing null */
790fe579 5457 if (rc <= (int)buf_size) {
1da177e4
LT
5458 memcpy(ea_value,
5459 temp_fea->name+temp_fea->name_len+1,
5460 rc);
50c2f753
SF
5461 /* ea values, unlike ea
5462 names, are not null
5463 terminated */
790fe579 5464 } else if (buf_size == 0) {
1da177e4
LT
5465 /* skip copy - calc size only */
5466 } else {
50c2f753 5467 /* stop before overrun buffer */
1da177e4
LT
5468 rc = -ERANGE;
5469 }
5470 break;
5471 }
5472 name_len -= temp_fea->name_len;
5473 temp_ptr += temp_fea->name_len;
5474 /* account for trailing null */
5475 name_len--;
5476 temp_ptr++;
5477 name_len -= value_len;
5478 temp_ptr += value_len;
50c2f753
SF
5479 /* No trailing null to account for in
5480 value_len. Go on to next EA */
1da177e4
LT
5481 temp_fea = (struct fea *)temp_ptr;
5482 }
50c2f753 5483 }
1da177e4
LT
5484 }
5485 }
0d817bc0 5486 cifs_buf_release(pSMB);
1da177e4
LT
5487 if (rc == -EAGAIN)
5488 goto QEARetry;
5489
5490 return (ssize_t)rc;
5491}
5492
5493int
5494CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
50c2f753
SF
5495 const char *ea_name, const void *ea_value,
5496 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5497 int remap)
1da177e4
LT
5498{
5499 struct smb_com_transaction2_spi_req *pSMB = NULL;
5500 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5501 struct fealist *parm_data;
5502 int name_len;
5503 int rc = 0;
5504 int bytes_returned = 0;
5505 __u16 params, param_offset, byte_count, offset, count;
5506
5507 cFYI(1, ("In SetEA"));
5508SetEARetry:
5509 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5510 (void **) &pSMBr);
5511 if (rc)
5512 return rc;
5513
5514 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5515 name_len =
50c2f753 5516 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 5517 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5518 name_len++; /* trailing null */
5519 name_len *= 2;
50c2f753 5520 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5521 name_len = strnlen(fileName, PATH_MAX);
5522 name_len++; /* trailing null */
5523 strncpy(pSMB->FileName, fileName, name_len);
5524 }
5525
5526 params = 6 + name_len;
5527
5528 /* done calculating parms using name_len of file name,
5529 now use name_len to calculate length of ea name
5530 we are going to create in the inode xattrs */
790fe579 5531 if (ea_name == NULL)
1da177e4
LT
5532 name_len = 0;
5533 else
50c2f753 5534 name_len = strnlen(ea_name, 255);
1da177e4 5535
dae5dbdb 5536 count = sizeof(*parm_data) + ea_value_len + name_len;
1da177e4 5537 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5538 /* BB find max SMB PDU from sess */
5539 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5540 pSMB->MaxSetupCount = 0;
5541 pSMB->Reserved = 0;
5542 pSMB->Flags = 0;
5543 pSMB->Timeout = 0;
5544 pSMB->Reserved2 = 0;
5545 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5546 InformationLevel) - 4;
1da177e4
LT
5547 offset = param_offset + params;
5548 pSMB->InformationLevel =
5549 cpu_to_le16(SMB_SET_FILE_EA);
5550
5551 parm_data =
5552 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5553 offset);
5554 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5555 pSMB->DataOffset = cpu_to_le16(offset);
5556 pSMB->SetupCount = 1;
5557 pSMB->Reserved3 = 0;
5558 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5559 byte_count = 3 /* pad */ + params + count;
5560 pSMB->DataCount = cpu_to_le16(count);
5561 parm_data->list_len = cpu_to_le32(count);
5562 parm_data->list[0].EA_flags = 0;
5563 /* we checked above that name len is less than 255 */
53b3531b 5564 parm_data->list[0].name_len = (__u8)name_len;
1da177e4 5565 /* EA names are always ASCII */
790fe579 5566 if (ea_name)
50c2f753 5567 strncpy(parm_data->list[0].name, ea_name, name_len);
1da177e4
LT
5568 parm_data->list[0].name[name_len] = 0;
5569 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5570 /* caller ensures that ea_value_len is less than 64K but
5571 we need to ensure that it fits within the smb */
5572
50c2f753
SF
5573 /*BB add length check to see if it would fit in
5574 negotiated SMB buffer size BB */
790fe579
SF
5575 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5576 if (ea_value_len)
50c2f753
SF
5577 memcpy(parm_data->list[0].name+name_len+1,
5578 ea_value, ea_value_len);
1da177e4
LT
5579
5580 pSMB->TotalDataCount = pSMB->DataCount;
5581 pSMB->ParameterCount = cpu_to_le16(params);
5582 pSMB->TotalParameterCount = pSMB->ParameterCount;
5583 pSMB->Reserved4 = 0;
5584 pSMB->hdr.smb_buf_length += byte_count;
5585 pSMB->ByteCount = cpu_to_le16(byte_count);
5586 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5587 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5588 if (rc)
1da177e4 5589 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
1da177e4
LT
5590
5591 cifs_buf_release(pSMB);
5592
5593 if (rc == -EAGAIN)
5594 goto SetEARetry;
5595
5596 return rc;
5597}
5598
5599#endif
This page took 1.862012 seconds and 5 git commands to generate.