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