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