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