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