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