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