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