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