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