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