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