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