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