vserver 1.9.5.x5
[linux-2.6.git] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2003
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
41 #ifdef CONFIG_CIFS_POSIX
42 static struct {
43         int index;
44         char *name;
45 } protocols[] = {
46         {CIFS_PROT, "\2NT LM 0.12"}, 
47         {CIFS_PROT, "\2POSIX 2"},
48         {BAD_PROT, "\2"}
49 };
50 #else
51 static struct {
52         int index;
53         char *name;
54 } protocols[] = {
55         {CIFS_PROT, "\2NT LM 0.12"}, 
56         {BAD_PROT, "\2"}
57 };
58 #endif
59
60
61 /* Mark as invalid, all open files on tree connections since they
62    were closed when session to server was lost */
63 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
64 {
65         struct cifsFileInfo *open_file = NULL;
66         struct list_head * tmp;
67         struct list_head * tmp1;
68
69 /* list all files open on tree connection and mark them invalid */
70         write_lock(&GlobalSMBSeslock);
71         list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
72                 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
73                 if(open_file) {
74                         open_file->invalidHandle = TRUE;
75                 }
76         }
77         write_unlock(&GlobalSMBSeslock);
78         /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */
79 }
80
81 static int
82 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
83          void **request_buf /* returned */)
84 {
85         int rc = 0;
86
87         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
88            check for tcp and smb session status done differently
89            for those three - in the calling routine */
90         if(tcon) {
91                 if((tcon->ses) && (tcon->ses->server)){
92                         struct nls_table *nls_codepage;
93                                 /* Give Demultiplex thread up to 10 seconds to 
94                                         reconnect, should be greater than cifs socket
95                                         timeout which is 7 seconds */
96                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
97                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
98                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
99                                 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
100                                         /* on "soft" mounts we wait once */
101                                         if((tcon->retry == FALSE) || 
102                                            (tcon->ses->status == CifsExiting)) {
103                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
104                                                 return -EHOSTDOWN;
105                                         } /* else "hard" mount - keep retrying until 
106                                         process is killed or server comes back up */
107                                 } else /* TCP session is reestablished now */
108                                         break;
109                                  
110                         }
111                         
112                         nls_codepage = load_nls_default();
113                 /* need to prevent multiple threads trying to
114                 simultaneously reconnect the same SMB session */
115                         down(&tcon->ses->sesSem);
116                         if(tcon->ses->status == CifsNeedReconnect)
117                                 rc = cifs_setup_session(0, tcon->ses, nls_codepage);
118                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
119                                 mark_open_files_invalid(tcon);
120                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
121                                         nls_codepage);
122                                 up(&tcon->ses->sesSem);
123                                 if(rc == 0)
124                                         atomic_inc(&tconInfoReconnectCount);
125
126                                 cFYI(1, ("reconnect tcon rc = %d", rc));
127                                 /* Removed call to reopen open files here - 
128                                         it is safer (and faster) to reopen files
129                                         one at a time as needed in read and write */
130
131                                 /* Check if handle based operation so we 
132                                         know whether we can continue or not without
133                                         returning to caller to reset file handle */
134                                 switch(smb_command) {
135                                         case SMB_COM_READ_ANDX:
136                                         case SMB_COM_WRITE_ANDX:
137                                         case SMB_COM_CLOSE:
138                                         case SMB_COM_FIND_CLOSE2:
139                                         case SMB_COM_LOCKING_ANDX: {
140                                                 unload_nls(nls_codepage);
141                                                 return -EAGAIN;
142                                         }
143                                 }
144                         } else {
145                                 up(&tcon->ses->sesSem);
146                         }
147                         unload_nls(nls_codepage);
148
149                 } else {
150                         return -EIO;
151                 }
152         }
153         if(rc)
154                 return rc;
155
156         *request_buf = cifs_small_buf_get();
157         if (*request_buf == 0) {
158                 /* BB should we add a retry in here if not a writepage? */
159                 return -ENOMEM;
160         }
161
162         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
163
164 #ifdef CONFIG_CIFS_STATS
165         if(tcon != NULL) {
166                 atomic_inc(&tcon->num_smbs_sent);
167         }
168 #endif /* CONFIG_CIFS_STATS */
169         return rc;
170 }  
171
172 static int
173 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
174          void **request_buf /* returned */ ,
175          void **response_buf /* returned */ )
176 {
177         int rc = 0;
178
179         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
180            check for tcp and smb session status done differently
181            for those three - in the calling routine */
182         if(tcon) {
183                 if((tcon->ses) && (tcon->ses->server)){
184                         struct nls_table *nls_codepage;
185                                 /* Give Demultiplex thread up to 10 seconds to 
186                                         reconnect, should be greater than cifs socket
187                                         timeout which is 7 seconds */
188                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
189                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
190                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
191                                 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
192                                         /* on "soft" mounts we wait once */
193                                         if((tcon->retry == FALSE) || 
194                                            (tcon->ses->status == CifsExiting)) {
195                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
196                                                 return -EHOSTDOWN;
197                                         } /* else "hard" mount - keep retrying until 
198                                         process is killed or server comes back up */
199                                 } else /* TCP session is reestablished now */
200                                         break;
201                                  
202                         }
203                         
204                         nls_codepage = load_nls_default();
205                 /* need to prevent multiple threads trying to
206                 simultaneously reconnect the same SMB session */
207                         down(&tcon->ses->sesSem);
208                         if(tcon->ses->status == CifsNeedReconnect)
209                                 rc = cifs_setup_session(0, tcon->ses, nls_codepage);
210                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
211                                 mark_open_files_invalid(tcon);
212                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
213                                         nls_codepage);
214                                 up(&tcon->ses->sesSem);
215                                 if(rc == 0)
216                                         atomic_inc(&tconInfoReconnectCount);
217
218                                 cFYI(1, ("reconnect tcon rc = %d", rc));
219                                 /* Removed call to reopen open files here - 
220                                         it is safer (and faster) to reopen files
221                                         one at a time as needed in read and write */
222
223                                 /* Check if handle based operation so we 
224                                         know whether we can continue or not without
225                                         returning to caller to reset file handle */
226                                 switch(smb_command) {
227                                         case SMB_COM_READ_ANDX:
228                                         case SMB_COM_WRITE_ANDX:
229                                         case SMB_COM_CLOSE:
230                                         case SMB_COM_FIND_CLOSE2:
231                                         case SMB_COM_LOCKING_ANDX: {
232                                                 unload_nls(nls_codepage);
233                                                 return -EAGAIN;
234                                         }
235                                 }
236                         } else {
237                                 up(&tcon->ses->sesSem);
238                         }
239                         unload_nls(nls_codepage);
240
241                 } else {
242                         return -EIO;
243                 }
244         }
245         if(rc)
246                 return rc;
247
248         *request_buf = cifs_buf_get();
249         if (*request_buf == 0) {
250                 /* BB should we add a retry in here if not a writepage? */
251                 return -ENOMEM;
252         }
253     /* Although the original thought was we needed the response buf for  */
254     /* potential retries of smb operations it turns out we can determine */
255     /* from the mid flags when the request buffer can be resent without  */
256     /* having to use a second distinct buffer for the response */
257         *response_buf = *request_buf; 
258
259         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
260                         wct /*wct */ );
261
262 #ifdef CONFIG_CIFS_STATS
263         if(tcon != NULL) {
264                 atomic_inc(&tcon->num_smbs_sent);
265         }
266 #endif /* CONFIG_CIFS_STATS */
267         return rc;
268 }
269
270 static int validate_t2(struct smb_t2_rsp * pSMB) 
271 {
272         int rc = -EINVAL;
273         int total_size;
274         char * pBCC;
275
276         /* check for plausible wct, bcc and t2 data and parm sizes */
277         /* check for parm and data offset going beyond end of smb */
278         if(pSMB->hdr.WordCount >= 10) {
279                 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
280                    (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
281                         /* check that bcc is at least as big as parms + data */
282                         /* check that bcc is less than negotiated smb buffer */
283                         total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
284                         if(total_size < 512) {
285                                 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
286                                 /* BCC le converted in SendReceive */
287                                 pBCC = (pSMB->hdr.WordCount * 2) + sizeof(struct smb_hdr) + 
288                                         (char *)pSMB;
289                                 if((total_size <= (*(u16 *)pBCC)) && 
290                                    (total_size < 
291                                         CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
292                                         return 0;
293                                 }
294                                 
295                         }
296                 }
297         }
298         cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
299                 sizeof(struct smb_t2_rsp) + 16);
300         return rc;
301 }
302 int
303 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
304 {
305         NEGOTIATE_REQ *pSMB;
306         NEGOTIATE_RSP *pSMBr;
307         int rc = 0;
308         int bytes_returned;
309         struct TCP_Server_Info * server;
310         u16 count;
311
312         if(ses->server)
313                 server = ses->server;
314         else {
315                 rc = -EIO;
316                 return rc;
317         }
318         rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
319                       (void **) &pSMB, (void **) &pSMBr);
320         if (rc)
321                 return rc;
322
323         pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
324         if (extended_security)
325                 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
326
327         count = strlen(protocols[0].name) + 1;
328         strncpy(pSMB->DialectsArray, protocols[0].name, 30);    
329     /* null guaranteed to be at end of source and target buffers anyway */
330
331         pSMB->hdr.smb_buf_length += count;
332         pSMB->ByteCount = cpu_to_le16(count);
333
334         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
335                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
336         if (rc == 0) {
337                 server->secMode = pSMBr->SecurityMode;  
338                 server->secType = NTLM; /* BB override default for NTLMv2 or krb*/
339                 /* one byte - no need to convert this or EncryptionKeyLen from le,*/
340                 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
341                 /* probably no need to store and check maxvcs */
342                 server->maxBuf =
343                         min(le32_to_cpu(pSMBr->MaxBufferSize),
344                         (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
345                 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
346                 cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
347                 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
348                 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
349                 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
350         /* BB with UTC do we ever need to be using srvr timezone? */
351                 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
352                         memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
353                                CIFS_CRYPTO_KEY_SIZE);
354                 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
355                            && (pSMBr->EncryptionKeyLength == 0)) {
356                         /* decode security blob */
357                 } else
358                         rc = -EIO;
359
360                 /* BB might be helpful to save off the domain of server here */
361
362                 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
363                         (server->capabilities & CAP_EXTENDED_SECURITY)) {
364                         count = pSMBr->ByteCount;
365                         if (count < 16)
366                                 rc = -EIO;
367                         else if (count == 16) {
368                                 server->secType = RawNTLMSSP;
369                                 if (server->socketUseCount.counter > 1) {
370                                         if (memcmp
371                                                 (server->server_GUID,
372                                                 pSMBr->u.extended_response.
373                                                 GUID, 16) != 0) {
374                                                 cFYI(1,
375                                                         ("UID of server does not match previous connection to same ip address"));
376                                                 memcpy(server->
377                                                         server_GUID,
378                                                         pSMBr->u.
379                                                         extended_response.
380                                                         GUID, 16);
381                                         }
382                                 } else
383                                         memcpy(server->server_GUID,
384                                                pSMBr->u.extended_response.
385                                                GUID, 16);
386                         } else {
387                                 rc = decode_negTokenInit(pSMBr->u.
388                                                          extended_response.
389                                                          SecurityBlob,
390                                                          count - 16,
391                                                          &server->secType);
392                                 if(rc == 1) {
393                                 /* BB Need to fill struct for sessetup here */
394                                         rc = -EOPNOTSUPP;
395                                 } else {
396                                         rc = -EINVAL;
397                                 }
398                         }
399                 } else
400                         server->capabilities &= ~CAP_EXTENDED_SECURITY;
401                 if(sign_CIFS_PDUs == FALSE) {        
402                         if(server->secMode & SECMODE_SIGN_REQUIRED)
403                                 cERROR(1,
404                                  ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
405                         server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
406                 } else if(sign_CIFS_PDUs == 1) {
407                         if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
408                                 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
409                 }
410                                 
411         }
412         if (pSMB)
413                 cifs_buf_release(pSMB);
414         return rc;
415 }
416
417 int
418 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
419 {
420         struct smb_hdr *smb_buffer;
421         struct smb_hdr *smb_buffer_response; /* BB removeme BB */
422         int rc = 0;
423         int length;
424
425         cFYI(1, ("In tree disconnect"));
426         /*
427          *  If last user of the connection and
428          *  connection alive - disconnect it
429          *  If this is the last connection on the server session disconnect it
430          *  (and inside session disconnect we should check if tcp socket needs 
431          *  to be freed and kernel thread woken up).
432          */
433         if (tcon)
434                 down(&tcon->tconSem);
435         else
436                 return -EIO;
437
438         atomic_dec(&tcon->useCount);
439         if (atomic_read(&tcon->useCount) > 0) {
440                 up(&tcon->tconSem);
441                 return -EBUSY;
442         }
443
444         /* No need to return error on this operation if tid invalidated and 
445         closed on server already e.g. due to tcp session crashing */
446         if(tcon->tidStatus == CifsNeedReconnect) {
447                 up(&tcon->tconSem);
448                 return 0;  
449         }
450
451         if((tcon->ses == 0) || (tcon->ses->server == 0)) {    
452                 up(&tcon->tconSem);
453                 return -EIO;
454         }
455         rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **)&smb_buffer);
456         if (rc) {
457                 up(&tcon->tconSem);
458                 return rc;
459         } else {
460                 smb_buffer_response = smb_buffer; /* BB removeme BB */
461     }
462         rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
463                          &length, 0);
464         if (rc)
465                 cFYI(1, (" Tree disconnect failed %d", rc));
466
467         if (smb_buffer)
468                 cifs_small_buf_release(smb_buffer);
469         up(&tcon->tconSem);
470
471         /* No need to return error on this operation if tid invalidated and 
472         closed on server already e.g. due to tcp session crashing */
473         if (rc == -EAGAIN)
474                 rc = 0;
475
476         return rc;
477 }
478
479 int
480 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
481 {
482         struct smb_hdr *smb_buffer_response;
483         LOGOFF_ANDX_REQ *pSMB;
484         int rc = 0;
485         int length;
486
487         cFYI(1, ("In SMBLogoff for session disconnect"));
488         if (ses)
489                 down(&ses->sesSem);
490         else
491                 return -EIO;
492
493         atomic_dec(&ses->inUse);
494         if (atomic_read(&ses->inUse) > 0) {
495                 up(&ses->sesSem);
496                 return -EBUSY;
497         }
498         rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
499         smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
500         
501         if(ses->server) {
502                 if(ses->server->secMode & 
503                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
504                         pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
505         }
506
507         if (rc) {
508                 up(&ses->sesSem);
509                 return rc;
510         }
511
512         pSMB->hdr.Uid = ses->Suid;
513
514         pSMB->AndXCommand = 0xFF;
515         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
516                          smb_buffer_response, &length, 0);
517         if (ses->server) {
518                 atomic_dec(&ses->server->socketUseCount);
519                 if (atomic_read(&ses->server->socketUseCount) == 0) {
520                         spin_lock(&GlobalMid_Lock);
521                         ses->server->tcpStatus = CifsExiting;
522                         spin_unlock(&GlobalMid_Lock);
523                         rc = -ESHUTDOWN;
524                 }
525         }
526         if (pSMB)
527                 cifs_small_buf_release(pSMB);
528         up(&ses->sesSem);
529
530         /* if session dead then we do not need to do ulogoff,
531                 since server closed smb session, no sense reporting 
532                 error */
533         if (rc == -EAGAIN)
534                 rc = 0;
535         return rc;
536 }
537
538 int
539 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
540                const char *fileName, const struct nls_table *nls_codepage)
541 {
542         DELETE_FILE_REQ *pSMB = NULL;
543         DELETE_FILE_RSP *pSMBr = NULL;
544         int rc = 0;
545         int bytes_returned;
546         int name_len;
547
548 DelFileRetry:
549         rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
550                       (void **) &pSMBr);
551         if (rc)
552                 return rc;
553
554         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
555                 name_len =
556                     cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, PATH_MAX
557                                   /* find define for this maxpathcomponent */
558                                   , nls_codepage);
559                 name_len++;     /* trailing null */
560                 name_len *= 2;
561         } else {                /* BB improve the check for buffer overruns BB */
562                 name_len = strnlen(fileName, PATH_MAX);
563                 name_len++;     /* trailing null */
564                 strncpy(pSMB->fileName, fileName, name_len);
565         }
566         pSMB->SearchAttributes =
567             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
568         pSMB->BufferFormat = 0x04;
569         pSMB->hdr.smb_buf_length += name_len + 1;
570         pSMB->ByteCount = cpu_to_le16(name_len + 1);
571         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
572                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
573         if (rc) {
574                 cFYI(1, ("Error in RMFile = %d", rc));
575         } 
576 #ifdef CONFIG_CIFS_STATS
577         else {
578                 atomic_inc(&tcon->num_deletes);
579         }
580 #endif
581
582         if (pSMB)
583                 cifs_buf_release(pSMB);
584         if (rc == -EAGAIN)
585                 goto DelFileRetry;
586
587         return rc;
588 }
589
590 int
591 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
592              const char *dirName, const struct nls_table *nls_codepage)
593 {
594         DELETE_DIRECTORY_REQ *pSMB = NULL;
595         DELETE_DIRECTORY_RSP *pSMBr = NULL;
596         int rc = 0;
597         int bytes_returned;
598         int name_len;
599
600         cFYI(1, ("In CIFSSMBRmDir"));
601 RmDirRetry:
602         rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
603                       (void **) &pSMBr);
604         if (rc)
605                 return rc;
606
607         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
608                 name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, PATH_MAX
609                                 /* find define for this maxpathcomponent */
610                                 , nls_codepage);
611                 name_len++;     /* trailing null */
612                 name_len *= 2;
613         } else {                /* BB improve the check for buffer overruns BB */
614                 name_len = strnlen(dirName, PATH_MAX);
615                 name_len++;     /* trailing null */
616                 strncpy(pSMB->DirName, dirName, name_len);
617         }
618
619         pSMB->BufferFormat = 0x04;
620         pSMB->hdr.smb_buf_length += name_len + 1;
621         pSMB->ByteCount = cpu_to_le16(name_len + 1);
622         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
623                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
624         if (rc) {
625                 cFYI(1, ("Error in RMDir = %d", rc));
626         }
627 #ifdef CONFIG_CIFS_STATS
628         else {
629                 atomic_inc(&tcon->num_rmdirs);
630         }
631 #endif
632
633         if (pSMB)
634                 cifs_buf_release(pSMB);
635         if (rc == -EAGAIN)
636                 goto RmDirRetry;
637         return rc;
638 }
639
640 int
641 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
642              const char *name, const struct nls_table *nls_codepage)
643 {
644         int rc = 0;
645         CREATE_DIRECTORY_REQ *pSMB = NULL;
646         CREATE_DIRECTORY_RSP *pSMBr = NULL;
647         int bytes_returned;
648         int name_len;
649
650         cFYI(1, ("In CIFSSMBMkDir"));
651 MkDirRetry:
652         rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
653                       (void **) &pSMBr);
654         if (rc)
655                 return rc;
656
657         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
658                 name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, PATH_MAX
659                                          /* find define for this maxpathcomponent */
660                                          , nls_codepage);
661                 name_len++;     /* trailing null */
662                 name_len *= 2;
663         } else {                /* BB improve the check for buffer overruns BB */
664                 name_len = strnlen(name, PATH_MAX);
665                 name_len++;     /* trailing null */
666                 strncpy(pSMB->DirName, name, name_len);
667         }
668
669         pSMB->BufferFormat = 0x04;
670         pSMB->hdr.smb_buf_length += name_len + 1;
671         pSMB->ByteCount = cpu_to_le16(name_len + 1);
672         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
673                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
674         if (rc) {
675                 cFYI(1, ("Error in Mkdir = %d", rc));
676         }
677 #ifdef CONFIG_CIFS_STATS
678         else {
679                 atomic_inc(&tcon->num_mkdirs);
680         }
681 #endif
682         if (pSMB)
683                 cifs_buf_release(pSMB);
684         if (rc == -EAGAIN)
685                 goto MkDirRetry;
686         return rc;
687 }
688
689 int
690 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
691             const char *fileName, const int openDisposition,
692             const int access_flags, const int create_options, __u16 * netfid,
693             int *pOplock, FILE_ALL_INFO * pfile_info, 
694             const struct nls_table *nls_codepage)
695 {
696         int rc = -EACCES;
697         OPEN_REQ *pSMB = NULL;
698         OPEN_RSP *pSMBr = NULL;
699         int bytes_returned;
700         int name_len;
701         __u16 count;
702
703 openRetry:
704         rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
705                       (void **) &pSMBr);
706         if (rc)
707                 return rc;
708
709         pSMB->AndXCommand = 0xFF;       /* none */
710
711         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
712                 count = 1;      /* account for one byte pad to word boundary */
713                 name_len =
714                     cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1),
715                                   fileName, PATH_MAX
716                                   /* find define for this maxpathcomponent */
717                                   , nls_codepage);
718                 name_len++;     /* trailing null */
719                 name_len *= 2;
720                 pSMB->NameLength = cpu_to_le16(name_len);
721         } else {                /* BB improve the check for buffer overruns BB */
722                 count = 0;      /* no pad */
723                 name_len = strnlen(fileName, PATH_MAX);
724                 name_len++;     /* trailing null */
725                 pSMB->NameLength = cpu_to_le16(name_len);
726                 strncpy(pSMB->fileName, fileName, name_len);
727         }
728         if (*pOplock & REQ_OPLOCK)
729                 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
730         else if (*pOplock & REQ_BATCHOPLOCK) {
731                 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
732         }
733         pSMB->DesiredAccess = cpu_to_le32(access_flags);
734         pSMB->AllocationSize = 0;
735         pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
736         /* XP does not handle ATTR_POSIX_SEMANTICS */
737         /* but it helps speed up case sensitive checks for other
738         servers such as Samba */
739         if (tcon->ses->capabilities & CAP_UNIX)
740                 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
741
742         /* if ((omode & S_IWUGO) == 0)
743                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
744         /*  Above line causes problems due to vfs splitting create into two
745                 pieces - need to set mode after file created not while it is
746                 being created */
747         pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
748         pSMB->CreateDisposition = cpu_to_le32(openDisposition);
749         pSMB->CreateOptions = cpu_to_le32(create_options);
750         pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/
751         pSMB->SecurityFlags =
752             SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
753
754         count += name_len;
755         pSMB->hdr.smb_buf_length += count;
756
757         pSMB->ByteCount = cpu_to_le16(count);
758         /* long_op set to 1 to allow for oplock break timeouts */
759         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
760                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
761         if (rc) {
762                 cFYI(1, ("Error in Open = %d", rc));
763         } else {
764                 *pOplock = pSMBr->OplockLevel;  /* one byte no need to le_to_cpu */
765                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
766                 /* Let caller know file was created so we can set the mode. */
767                 /* Do we care about the CreateAction in any other cases? */
768                 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
769                         *pOplock |= CIFS_CREATE_ACTION; 
770                 if(pfile_info) {
771                     memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
772                         36 /* CreationTime to Attributes */);
773                     /* the file_info buf is endian converted by caller */
774                     pfile_info->AllocationSize = pSMBr->AllocationSize;
775                     pfile_info->EndOfFile = pSMBr->EndOfFile;
776                     pfile_info->NumberOfLinks = cpu_to_le32(1);
777                 }
778
779 #ifdef CONFIG_CIFS_STATS
780                 atomic_inc(&tcon->num_opens);
781 #endif
782         }
783         if (pSMB)
784                 cifs_buf_release(pSMB);
785         if (rc == -EAGAIN)
786                 goto openRetry;
787         return rc;
788 }
789
790 /* If no buffer passed in, then caller wants to do the copy
791         as in the case of readpages so the SMB buffer must be
792         freed by the caller */
793
794 int
795 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
796             const int netfid, const unsigned int count,
797             const __u64 lseek, unsigned int *nbytes, char **buf)
798 {
799         int rc = -EACCES;
800         READ_REQ *pSMB = NULL;
801         READ_RSP *pSMBr = NULL;
802         char *pReadData = NULL;
803         int bytes_returned;
804
805         *nbytes = 0;
806         rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
807                       (void **) &pSMBr);
808         if (rc)
809                 return rc;
810
811         /* tcon and ses pointer are checked in smb_init */
812         if (tcon->ses->server == NULL)
813                 return -ECONNABORTED;
814
815         pSMB->AndXCommand = 0xFF;       /* none */
816         pSMB->Fid = netfid;
817         pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
818         pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
819         pSMB->Remaining = 0;
820         pSMB->MaxCount = cpu_to_le16(count);
821         pSMB->MaxCountHigh = 0;
822         pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
823
824         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
825                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
826         if (rc) {
827                 cERROR(1, ("Send error in read = %d", rc));
828         } else {
829                 __u16 data_length = le16_to_cpu(pSMBr->DataLength);
830                 *nbytes = data_length;
831                 /*check that DataLength would not go beyond end of SMB */
832                 if ((data_length > CIFSMaxBufSize) 
833                                 || (data_length > count)) {
834                         cFYI(1,("bad length %d for count %d",data_length,count));
835                         rc = -EIO;
836                         *nbytes = 0;
837                 } else {
838                         pReadData =
839                             (char *) (&pSMBr->hdr.Protocol) +
840                             le16_to_cpu(pSMBr->DataOffset);
841 /*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
842                                 cERROR(1,("Faulting on read rc = %d",rc));
843                                 rc = -EFAULT;
844                         }*/ /* can not use copy_to_user when using page cache*/
845                         if(*buf)
846                             memcpy(*buf,pReadData,data_length);
847                 }
848         }
849         if (pSMB) {
850                 if(*buf)
851                         cifs_buf_release(pSMB);
852                 else
853                         *buf = (char *)pSMB;
854         }
855
856         /* Note: On -EAGAIN error only caller can retry on handle based calls 
857                 since file handle passed in no longer valid */
858         return rc;
859 }
860
861 int
862 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
863              const int netfid, const unsigned int count,
864              const __u64 offset, unsigned int *nbytes, const char *buf,
865              const char __user * ubuf, const int long_op)
866 {
867         int rc = -EACCES;
868         WRITE_REQ *pSMB = NULL;
869         WRITE_RSP *pSMBr = NULL;
870         int bytes_returned;
871         unsigned bytes_sent;
872         __u16 byte_count;
873
874         rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
875                       (void **) &pSMBr);
876         if (rc)
877                 return rc;
878         /* tcon and ses pointer are checked in smb_init */
879         if (tcon->ses->server == NULL)
880                 return -ECONNABORTED;
881
882         pSMB->AndXCommand = 0xFF;       /* none */
883         pSMB->Fid = netfid;
884         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
885         pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
886         pSMB->Reserved = 0xFFFFFFFF;
887         pSMB->WriteMode = 0;
888         pSMB->Remaining = 0;
889         /* BB can relax this if buffer is big enough in some cases - ie we can 
890         send more  if LARGE_WRITE_X capability returned by the server and if
891         our buffer is big enough or if we convert to iovecs on socket writes
892         and eliminate the copy to the CIFS buffer */
893         bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
894         if (bytes_sent > count)
895                 bytes_sent = count;
896         pSMB->DataLengthHigh = 0;
897         pSMB->DataOffset =
898             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
899     if(buf)
900             memcpy(pSMB->Data,buf,bytes_sent);
901         else if(ubuf)
902                 copy_from_user(pSMB->Data,ubuf,bytes_sent);
903     else {
904                 /* No buffer */
905                 if(pSMB)
906                         cifs_buf_release(pSMB);
907                 return -EINVAL;
908         }
909
910         byte_count = bytes_sent + 1 /* pad */ ;
911         pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
912         pSMB->DataLengthHigh = 0;
913         pSMB->hdr.smb_buf_length += byte_count;
914         pSMB->ByteCount = cpu_to_le16(byte_count);
915
916         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
917                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
918         if (rc) {
919                 cFYI(1, ("Send error in write = %d", rc));
920                 *nbytes = 0;
921         } else
922                 *nbytes = le16_to_cpu(pSMBr->Count);
923
924         if (pSMB)
925                 cifs_buf_release(pSMB);
926
927         /* Note: On -EAGAIN error only caller can retry on handle based calls 
928                 since file handle passed in no longer valid */
929
930         return rc;
931 }
932
933 #ifdef CONFIG_CIFS_EXPERIMENTAL
934 int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
935              const int netfid, const unsigned int count,
936              const __u64 offset, unsigned int *nbytes, const char __user *buf,
937              const int long_op)
938 {
939         int rc = -EACCES;
940         WRITE_REQ *pSMB = NULL;
941         WRITE_RSP *pSMBr = NULL;
942         /*int bytes_returned;*/
943         unsigned bytes_sent;
944         __u16 byte_count;
945
946         rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
947         pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
948     
949     if (rc)
950                 return rc;
951         /* tcon and ses pointer are checked in smb_init */
952         if (tcon->ses->server == NULL)
953                 return -ECONNABORTED;
954
955         pSMB->AndXCommand = 0xFF; /* none */
956         pSMB->Fid = netfid;
957         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
958         pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
959         pSMB->Reserved = 0xFFFFFFFF;
960         pSMB->WriteMode = 0;
961         pSMB->Remaining = 0;
962         bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
963         if (bytes_sent > count)
964                 bytes_sent = count;
965         pSMB->DataLengthHigh = 0;
966         pSMB->DataOffset =
967             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
968
969         byte_count = bytes_sent + 1 /* pad */ ;
970         pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
971         pSMB->DataLengthHigh = 0;
972         pSMB->hdr.smb_buf_length += byte_count;
973         pSMB->ByteCount = cpu_to_le16(byte_count);
974
975 /*      rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB,
976                          (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */  /* BB fixme BB */
977         if (rc) {
978                 cFYI(1, ("Send error in write2 (large write) = %d", rc));
979                 *nbytes = 0;
980         } else
981                 *nbytes = le16_to_cpu(pSMBr->Count);
982
983         if (pSMB)
984                 cifs_small_buf_release(pSMB);
985
986         /* Note: On -EAGAIN error only caller can retry on handle based calls 
987                 since file handle passed in no longer valid */
988
989         return rc;
990 }
991 #endif /* CIFS_EXPERIMENTAL */
992
993 int
994 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
995             const __u16 smb_file_id, const __u64 len,
996             const __u64 offset, const __u32 numUnlock,
997             const __u32 numLock, const __u8 lockType, const int waitFlag)
998 {
999         int rc = 0;
1000         LOCK_REQ *pSMB = NULL;
1001         LOCK_RSP *pSMBr = NULL;
1002         int bytes_returned;
1003         int timeout = 0;
1004         __u16 count;
1005
1006         cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1007         rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
1008                       (void **) &pSMBr);
1009         if (rc)
1010                 return rc;
1011
1012         if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1013                 timeout = -1; /* no response expected */
1014                 pSMB->Timeout = 0;
1015         } else if (waitFlag == TRUE) {
1016                 timeout = 3;  /* blocking operation, no timeout */
1017                 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1018         } else {
1019                 pSMB->Timeout = 0;
1020         }
1021
1022         pSMB->NumberOfLocks = cpu_to_le16(numLock);
1023         pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1024         pSMB->LockType = lockType;
1025         pSMB->AndXCommand = 0xFF;       /* none */
1026         pSMB->Fid = smb_file_id; /* netfid stays le */
1027
1028         if((numLock != 0) || (numUnlock != 0)) {
1029                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1030                 /* BB where to store pid high? */
1031                 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1032                 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1033                 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1034                 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1035                 count = sizeof(LOCKING_ANDX_RANGE);
1036         } else {
1037                 /* oplock break */
1038                 count = 0;
1039         }
1040         pSMB->hdr.smb_buf_length += count;
1041         pSMB->ByteCount = cpu_to_le16(count);
1042
1043         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1044                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1045
1046         if (rc) {
1047                 cFYI(1, ("Send error in Lock = %d", rc));
1048         }
1049         if (pSMB)
1050                 cifs_buf_release(pSMB);
1051
1052         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1053         since file handle passed in no longer valid */
1054         return rc;
1055 }
1056
1057 int
1058 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1059 {
1060         int rc = 0;
1061         CLOSE_REQ *pSMB = NULL;
1062         CLOSE_RSP *pSMBr = NULL;
1063         int bytes_returned;
1064         cFYI(1, ("In CIFSSMBClose"));
1065
1066 /* do not retry on dead session on close */
1067         rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1068         pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1069         if(rc == -EAGAIN)
1070                 return 0;
1071         if (rc)
1072                 return rc;
1073
1074         pSMB->FileID = (__u16) smb_file_id;
1075         pSMB->LastWriteTime = 0;
1076         pSMB->ByteCount = 0;
1077         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1078                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1079         if (rc) {
1080                 if(rc!=-EINTR) {
1081                         /* EINTR is expected when user ctl-c to kill app */
1082                         cERROR(1, ("Send error in Close = %d", rc));
1083                 }
1084         }
1085
1086         if (pSMB)
1087                 cifs_small_buf_release(pSMB);
1088
1089         /* Since session is dead, file will be closed on server already */
1090         if(rc == -EAGAIN)
1091                 rc = 0;
1092
1093         return rc;
1094 }
1095
1096 int
1097 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1098               const char *fromName, const char *toName,
1099               const struct nls_table *nls_codepage)
1100 {
1101         int rc = 0;
1102         RENAME_REQ *pSMB = NULL;
1103         RENAME_RSP *pSMBr = NULL;
1104         int bytes_returned;
1105         int name_len, name_len2;
1106         __u16 count;
1107
1108         cFYI(1, ("In CIFSSMBRename"));
1109 renameRetry:
1110         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1111                       (void **) &pSMBr);
1112         if (rc)
1113                 return rc;
1114
1115         pSMB->BufferFormat = 0x04;
1116         pSMB->SearchAttributes =
1117             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1118                         ATTR_DIRECTORY);
1119
1120         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1121                 name_len =
1122                     cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX
1123                                   /* find define for this maxpathcomponent */
1124                                   , nls_codepage);
1125                 name_len++;     /* trailing null */
1126                 name_len *= 2;
1127                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1128         /* protocol requires ASCII signature byte on Unicode string */
1129                 pSMB->OldFileName[name_len + 1] = 0x00;
1130                 name_len2 =
1131                     cifs_strtoUCS((wchar_t *) & pSMB->
1132                                   OldFileName[name_len + 2], toName, PATH_MAX,
1133                                   nls_codepage);
1134                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1135                 name_len2 *= 2; /* convert to bytes */
1136         } else {                /* BB improve the check for buffer overruns BB */
1137                 name_len = strnlen(fromName, PATH_MAX);
1138                 name_len++;     /* trailing null */
1139                 strncpy(pSMB->OldFileName, fromName, name_len);
1140                 name_len2 = strnlen(toName, PATH_MAX);
1141                 name_len2++;    /* trailing null */
1142                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1143                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1144                 name_len2++;    /* trailing null */
1145                 name_len2++;    /* signature byte */
1146         }
1147
1148         count = 1 /* 1st signature byte */  + name_len + name_len2;
1149         pSMB->hdr.smb_buf_length += count;
1150         pSMB->ByteCount = cpu_to_le16(count);
1151
1152         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1153                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1154         if (rc) {
1155                 cFYI(1, ("Send error in rename = %d", rc));
1156         } 
1157
1158 #ifdef CONFIG_CIFS_STATS
1159           else {
1160                 atomic_inc(&tcon->num_renames);
1161         }
1162 #endif
1163
1164         if (pSMB)
1165                 cifs_buf_release(pSMB);
1166
1167         if (rc == -EAGAIN)
1168                 goto renameRetry;
1169
1170         return rc;
1171 }
1172
1173 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
1174                 int netfid, char * target_name, const struct nls_table * nls_codepage) 
1175 {
1176         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1177         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1178         struct set_file_rename * rename_info;
1179         char *data_offset;
1180         char dummy_string[30];
1181         int rc = 0;
1182         int bytes_returned = 0;
1183         int len_of_str;
1184         __u16 params, param_offset, offset, count, byte_count;
1185
1186         cFYI(1, ("Rename to File by handle"));
1187         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1188                         (void **) &pSMBr);
1189         if (rc)
1190                 return rc;
1191
1192         params = 6;
1193         pSMB->MaxSetupCount = 0;
1194         pSMB->Reserved = 0;
1195         pSMB->Flags = 0;
1196         pSMB->Timeout = 0;
1197         pSMB->Reserved2 = 0;
1198         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1199         offset = param_offset + params;
1200
1201         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1202         rename_info = (struct set_file_rename *) data_offset;
1203         pSMB->MaxParameterCount = cpu_to_le16(2);
1204         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1205         pSMB->SetupCount = 1;
1206         pSMB->Reserved3 = 0;
1207         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1208         byte_count = 3 /* pad */  + params;
1209         pSMB->ParameterCount = cpu_to_le16(params);
1210         pSMB->TotalParameterCount = pSMB->ParameterCount;
1211         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1212         pSMB->DataOffset = cpu_to_le16(offset);
1213         /* construct random name ".cifs_tmp<inodenum><mid>" */
1214         rename_info->overwrite = cpu_to_le32(1);
1215         rename_info->root_fid  = 0;
1216         /* unicode only call */
1217         if(target_name == NULL) {
1218                 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1219                 len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage);
1220         } else {
1221                 len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, PATH_MAX, nls_codepage);
1222         }
1223         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1224         count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1225         byte_count += count;
1226         pSMB->DataCount = cpu_to_le16(count);
1227         pSMB->TotalDataCount = pSMB->DataCount;
1228         pSMB->Fid = netfid;
1229         pSMB->InformationLevel =
1230                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1231         pSMB->Reserved4 = 0;
1232         pSMB->hdr.smb_buf_length += byte_count;
1233         pSMB->ByteCount = cpu_to_le16(byte_count);
1234         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1235                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1236         if (rc) {
1237                 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1238         }
1239 #ifdef CONFIG_CIFS_STATS
1240           else {
1241                 atomic_inc(&pTcon->num_t2renames);
1242         }
1243 #endif
1244         if (pSMB)
1245                 cifs_buf_release(pSMB);
1246
1247         /* Note: On -EAGAIN error only caller can retry on handle based calls
1248                 since file handle passed in no longer valid */
1249
1250         return rc;
1251 }
1252
1253 int
1254 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
1255             const __u16 target_tid, const char *toName, const int flags,
1256             const struct nls_table *nls_codepage)
1257 {
1258         int rc = 0;
1259         COPY_REQ *pSMB = NULL;
1260         COPY_RSP *pSMBr = NULL;
1261         int bytes_returned;
1262         int name_len, name_len2;
1263         __u16 count;
1264
1265         cFYI(1, ("In CIFSSMBCopy"));
1266 copyRetry:
1267         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1268                         (void **) &pSMBr);
1269         if (rc)
1270                 return rc;
1271
1272         pSMB->BufferFormat = 0x04;
1273         pSMB->Tid2 = target_tid;
1274
1275         pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1276
1277         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1278                 name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, 
1279                                 fromName, 
1280                                 PATH_MAX /* find define for this maxpathcomponent */,
1281                                 nls_codepage);
1282                 name_len++;     /* trailing null */
1283                 name_len *= 2;
1284                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1285                 /* protocol requires ASCII signature byte on Unicode string */
1286                 pSMB->OldFileName[name_len + 1] = 0x00;
1287                 name_len2 = cifs_strtoUCS((wchar_t *) & pSMB->
1288                                 OldFileName[name_len + 2], toName, PATH_MAX,
1289                                 nls_codepage);
1290                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1291                 name_len2 *= 2; /* convert to bytes */
1292         } else {                /* BB improve the check for buffer overruns BB */
1293                 name_len = strnlen(fromName, PATH_MAX);
1294                 name_len++;     /* trailing null */
1295                 strncpy(pSMB->OldFileName, fromName, name_len);
1296                 name_len2 = strnlen(toName, PATH_MAX);
1297                 name_len2++;    /* trailing null */
1298                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1299                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1300                 name_len2++;    /* trailing null */
1301                 name_len2++;    /* signature byte */
1302         }
1303
1304         count = 1 /* 1st signature byte */  + name_len + name_len2;
1305         pSMB->hdr.smb_buf_length += count;
1306         pSMB->ByteCount = cpu_to_le16(count);
1307
1308         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1309                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1310         if (rc) {
1311                 cFYI(1, ("Send error in copy = %d with %d files copied",
1312                         rc, le16_to_cpu(pSMBr->CopyCount)));
1313         }
1314         if (pSMB)
1315                 cifs_buf_release(pSMB);
1316
1317         if (rc == -EAGAIN)
1318                 goto copyRetry;
1319
1320         return rc;
1321 }
1322
1323 int
1324 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1325                       const char *fromName, const char *toName,
1326                       const struct nls_table *nls_codepage)
1327 {
1328         TRANSACTION2_SPI_REQ *pSMB = NULL;
1329         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1330         char *data_offset;
1331         int name_len;
1332         int name_len_target;
1333         int rc = 0;
1334         int bytes_returned = 0;
1335         __u16 params, param_offset, offset, byte_count;
1336
1337         cFYI(1, ("In Symlink Unix style"));
1338 createSymLinkRetry:
1339         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1340                       (void **) &pSMBr);
1341         if (rc)
1342                 return rc;
1343
1344         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1345                 name_len =
1346                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1347                                   /* find define for this maxpathcomponent */
1348                                   , nls_codepage);
1349                 name_len++;     /* trailing null */
1350                 name_len *= 2;
1351
1352         } else {                /* BB improve the check for buffer overruns BB */
1353                 name_len = strnlen(fromName, PATH_MAX);
1354                 name_len++;     /* trailing null */
1355                 strncpy(pSMB->FileName, fromName, name_len);
1356         }
1357         params = 6 + name_len;
1358         pSMB->MaxSetupCount = 0;
1359         pSMB->Reserved = 0;
1360         pSMB->Flags = 0;
1361         pSMB->Timeout = 0;
1362         pSMB->Reserved2 = 0;
1363         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1364                                      InformationLevel) - 4;
1365         offset = param_offset + params;
1366
1367         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1368         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1369                 name_len_target =
1370                     cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1371                                   /* find define for this maxpathcomponent */
1372                                   , nls_codepage);
1373                 name_len_target++;      /* trailing null */
1374                 name_len_target *= 2;
1375         } else {                /* BB improve the check for buffer overruns BB */
1376                 name_len_target = strnlen(toName, PATH_MAX);
1377                 name_len_target++;      /* trailing null */
1378                 strncpy(data_offset, toName, name_len_target);
1379         }
1380
1381         pSMB->MaxParameterCount = cpu_to_le16(2);
1382         /* BB find exact max on data count below from sess */
1383         pSMB->MaxDataCount = cpu_to_le16(1000);
1384         pSMB->SetupCount = 1;
1385         pSMB->Reserved3 = 0;
1386         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1387         byte_count = 3 /* pad */  + params + name_len_target;
1388         pSMB->DataCount = cpu_to_le16(name_len_target);
1389         pSMB->ParameterCount = cpu_to_le16(params);
1390         pSMB->TotalDataCount = pSMB->DataCount;
1391         pSMB->TotalParameterCount = pSMB->ParameterCount;
1392         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1393         pSMB->DataOffset = cpu_to_le16(offset);
1394         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1395         pSMB->Reserved4 = 0;
1396         pSMB->hdr.smb_buf_length += byte_count;
1397         pSMB->ByteCount = cpu_to_le16(byte_count);
1398         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1399                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1400         if (rc) {
1401                 cFYI(1,
1402                      ("Send error in SetPathInfo (create symlink) = %d",
1403                       rc));
1404         }
1405
1406         if (pSMB)
1407                 cifs_buf_release(pSMB);
1408
1409         if (rc == -EAGAIN)
1410                 goto createSymLinkRetry;
1411
1412         return rc;
1413 }
1414
1415 int
1416 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1417                        const char *fromName, const char *toName,
1418                        const struct nls_table *nls_codepage)
1419 {
1420         TRANSACTION2_SPI_REQ *pSMB = NULL;
1421         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1422         char *data_offset;
1423         int name_len;
1424         int name_len_target;
1425         int rc = 0;
1426         int bytes_returned = 0;
1427         __u16 params, param_offset, offset, byte_count;
1428
1429         cFYI(1, ("In Create Hard link Unix style"));
1430 createHardLinkRetry:
1431         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1432                       (void **) &pSMBr);
1433         if (rc)
1434                 return rc;
1435
1436         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1437                 name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, PATH_MAX
1438                                          /* find define for this maxpathcomponent */
1439                                          , nls_codepage);
1440                 name_len++;     /* trailing null */
1441                 name_len *= 2;
1442
1443         } else {                /* BB improve the check for buffer overruns BB */
1444                 name_len = strnlen(toName, PATH_MAX);
1445                 name_len++;     /* trailing null */
1446                 strncpy(pSMB->FileName, toName, name_len);
1447         }
1448         params = 6 + name_len;
1449         pSMB->MaxSetupCount = 0;
1450         pSMB->Reserved = 0;
1451         pSMB->Flags = 0;
1452         pSMB->Timeout = 0;
1453         pSMB->Reserved2 = 0;
1454         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1455                                      InformationLevel) - 4;
1456         offset = param_offset + params;
1457
1458         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1459         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1460                 name_len_target =
1461                     cifs_strtoUCS((wchar_t *) data_offset, fromName, PATH_MAX
1462                                   /* find define for this maxpathcomponent */
1463                                   , nls_codepage);
1464                 name_len_target++;      /* trailing null */
1465                 name_len_target *= 2;
1466         } else {                /* BB improve the check for buffer overruns BB */
1467                 name_len_target = strnlen(fromName, PATH_MAX);
1468                 name_len_target++;      /* trailing null */
1469                 strncpy(data_offset, fromName, name_len_target);
1470         }
1471
1472         pSMB->MaxParameterCount = cpu_to_le16(2);
1473         /* BB find exact max on data count below from sess*/
1474         pSMB->MaxDataCount = cpu_to_le16(1000);
1475         pSMB->SetupCount = 1;
1476         pSMB->Reserved3 = 0;
1477         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1478         byte_count = 3 /* pad */  + params + name_len_target;
1479         pSMB->ParameterCount = cpu_to_le16(params);
1480         pSMB->TotalParameterCount = pSMB->ParameterCount;
1481         pSMB->DataCount = cpu_to_le16(name_len_target);
1482         pSMB->TotalDataCount = pSMB->DataCount;
1483         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1484         pSMB->DataOffset = cpu_to_le16(offset);
1485         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1486         pSMB->Reserved4 = 0;
1487         pSMB->hdr.smb_buf_length += byte_count;
1488         pSMB->ByteCount = cpu_to_le16(byte_count);
1489         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1490                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1491         if (rc) {
1492                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1493         }
1494
1495         if (pSMB)
1496                 cifs_buf_release(pSMB);
1497         if (rc == -EAGAIN)
1498                 goto createHardLinkRetry;
1499
1500         return rc;
1501 }
1502
1503 int
1504 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1505                    const char *fromName, const char *toName,
1506                    const struct nls_table *nls_codepage)
1507 {
1508         int rc = 0;
1509         NT_RENAME_REQ *pSMB = NULL;
1510         RENAME_RSP *pSMBr = NULL;
1511         int bytes_returned;
1512         int name_len, name_len2;
1513         __u16 count;
1514
1515         cFYI(1, ("In CIFSCreateHardLink"));
1516 winCreateHardLinkRetry:
1517
1518         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1519                       (void **) &pSMBr);
1520         if (rc)
1521                 return rc;
1522
1523         pSMB->SearchAttributes =
1524             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1525                         ATTR_DIRECTORY);
1526         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1527         pSMB->ClusterCount = 0;
1528
1529         pSMB->BufferFormat = 0x04;
1530
1531         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1532                 name_len =
1533                     cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX
1534                                   /* find define for this maxpathcomponent */
1535                                   , nls_codepage);
1536                 name_len++;     /* trailing null */
1537                 name_len *= 2;
1538                 pSMB->OldFileName[name_len] = 0;        /* pad */
1539                 pSMB->OldFileName[name_len + 1] = 0x04; 
1540                 name_len2 =
1541                     cifs_strtoUCS((wchar_t *) & pSMB->
1542                                   OldFileName[name_len + 2], toName, PATH_MAX,
1543                                   nls_codepage);
1544                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1545                 name_len2 *= 2; /* convert to bytes */
1546         } else {                /* BB improve the check for buffer overruns BB */
1547                 name_len = strnlen(fromName, PATH_MAX);
1548                 name_len++;     /* trailing null */
1549                 strncpy(pSMB->OldFileName, fromName, name_len);
1550                 name_len2 = strnlen(toName, PATH_MAX);
1551                 name_len2++;    /* trailing null */
1552                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
1553                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1554                 name_len2++;    /* trailing null */
1555                 name_len2++;    /* signature byte */
1556         }
1557
1558         count = 1 /* string type byte */  + name_len + name_len2;
1559         pSMB->hdr.smb_buf_length += count;
1560         pSMB->ByteCount = cpu_to_le16(count);
1561
1562         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1563                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1564         if (rc) {
1565                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1566         }
1567         if (pSMB)
1568                 cifs_buf_release(pSMB);
1569         if (rc == -EAGAIN)
1570                 goto winCreateHardLinkRetry;
1571
1572         return rc;
1573 }
1574
1575 int
1576 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1577                         const unsigned char *searchName,
1578                         char *symlinkinfo, const int buflen,
1579                         const struct nls_table *nls_codepage)
1580 {
1581 /* SMB_QUERY_FILE_UNIX_LINK */
1582         TRANSACTION2_QPI_REQ *pSMB = NULL;
1583         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1584         int rc = 0;
1585         int bytes_returned;
1586         int name_len;
1587         __u16 params, byte_count;
1588
1589         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1590
1591 querySymLinkRetry:
1592         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1593                       (void **) &pSMBr);
1594         if (rc)
1595                 return rc;
1596
1597         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1598                 name_len =
1599                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1600                                   /* find define for this maxpathcomponent */
1601                                   , nls_codepage);
1602                 name_len++;     /* trailing null */
1603                 name_len *= 2;
1604         } else {                /* BB improve the check for buffer overruns BB */
1605                 name_len = strnlen(searchName, PATH_MAX);
1606                 name_len++;     /* trailing null */
1607                 strncpy(pSMB->FileName, searchName, name_len);
1608         }
1609
1610         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1611         pSMB->TotalDataCount = 0;
1612         pSMB->MaxParameterCount = cpu_to_le16(2);
1613         /* BB find exact max data count below from sess structure BB */
1614         pSMB->MaxDataCount = cpu_to_le16(4000);
1615         pSMB->MaxSetupCount = 0;
1616         pSMB->Reserved = 0;
1617         pSMB->Flags = 0;
1618         pSMB->Timeout = 0;
1619         pSMB->Reserved2 = 0;
1620         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1621         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1622         pSMB->DataCount = 0;
1623         pSMB->DataOffset = 0;
1624         pSMB->SetupCount = 1;
1625         pSMB->Reserved3 = 0;
1626         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1627         byte_count = params + 1 /* pad */ ;
1628         pSMB->TotalParameterCount = cpu_to_le16(params);
1629         pSMB->ParameterCount = pSMB->TotalParameterCount;
1630         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1631         pSMB->Reserved4 = 0;
1632         pSMB->hdr.smb_buf_length += byte_count;
1633         pSMB->ByteCount = cpu_to_le16(byte_count);
1634
1635         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1636                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1637         if (rc) {
1638                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1639         } else {
1640                 /* decode response */
1641
1642                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1643                 if (rc || (pSMBr->ByteCount < 2))
1644                 /* BB also check enough total bytes returned */
1645                         rc = -EIO;      /* bad smb */
1646                 else {
1647                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1648                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1649
1650                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1651                                 name_len = UniStrnlen((wchar_t *) ((char *)
1652                                         &pSMBr->hdr.Protocol +data_offset),
1653                                         min_t(const int, buflen,count) / 2);
1654                                 cifs_strfromUCS_le(symlinkinfo,
1655                                         (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1656                                                 data_offset),
1657                                         name_len, nls_codepage);
1658                         } else {
1659                                 strncpy(symlinkinfo,
1660                                         (char *) &pSMBr->hdr.Protocol + 
1661                                                 data_offset,
1662                                         min_t(const int, buflen, count));
1663                         }
1664                         symlinkinfo[buflen] = 0;
1665         /* just in case so calling code does not go off the end of buffer */
1666                 }
1667         }
1668         if (pSMB)
1669                 cifs_buf_release(pSMB);
1670         if (rc == -EAGAIN)
1671                 goto querySymLinkRetry;
1672         return rc;
1673 }
1674
1675
1676
1677 int
1678 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1679                         const unsigned char *searchName,
1680                         char *symlinkinfo, const int buflen,__u16 fid,
1681                         const struct nls_table *nls_codepage)
1682 {
1683         int rc = 0;
1684         int bytes_returned;
1685         int name_len;
1686         struct smb_com_transaction_ioctl_req * pSMB;
1687         struct smb_com_transaction_ioctl_rsp * pSMBr;
1688
1689         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1690         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1691                       (void **) &pSMBr);
1692         if (rc)
1693                 return rc;
1694
1695         pSMB->TotalParameterCount = 0 ;
1696         pSMB->TotalDataCount = 0;
1697         pSMB->MaxParameterCount = cpu_to_le32(2);
1698         /* BB find exact data count max from sess structure BB */
1699         pSMB->MaxDataCount = cpu_to_le32(4000);
1700         pSMB->MaxSetupCount = 4;
1701         pSMB->Reserved = 0;
1702         pSMB->ParameterOffset = 0;
1703         pSMB->DataCount = 0;
1704         pSMB->DataOffset = 0;
1705         pSMB->SetupCount = 4;
1706         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1707         pSMB->ParameterCount = pSMB->TotalParameterCount;
1708         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1709         pSMB->IsFsctl = 1; /* FSCTL */
1710         pSMB->IsRootFlag = 0;
1711         pSMB->Fid = fid; /* file handle always le */
1712         pSMB->ByteCount = 0;
1713
1714         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1715                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1716         if (rc) {
1717                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1718         } else {                /* decode response */
1719                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1720                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1721                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1722                 /* BB also check enough total bytes returned */
1723                         rc = -EIO;      /* bad smb */
1724                 else {
1725                         if(data_count && (data_count < 2048)) {
1726                 /* could also validate reparse tag && better check name length */
1727                                 struct reparse_data * reparse_buf = (struct reparse_data *)
1728                                         ((char *)&pSMBr->hdr.Protocol + data_offset);
1729                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1730                                         name_len = UniStrnlen((wchar_t *)
1731                                                         (reparse_buf->LinkNamesBuf + 
1732                                                         reparse_buf->TargetNameOffset),
1733                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
1734                                         cifs_strfromUCS_le(symlinkinfo,
1735                                                 (wchar_t *) (reparse_buf->LinkNamesBuf + 
1736                                                 reparse_buf->TargetNameOffset),
1737                                                 name_len, nls_codepage);
1738                                 } else { /* ASCII names */
1739                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
1740                                                 reparse_buf->TargetNameOffset, 
1741                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
1742                                 }
1743                         } else {
1744                                 rc = -EIO;
1745                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1746                         }
1747                         symlinkinfo[buflen] = 0; /* just in case so the caller
1748                                         does not go off the end of the buffer */
1749                         cFYI(1,("readlink result - %s ",symlinkinfo));
1750                 }
1751         }
1752         if (pSMB)
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 #ifdef CONFIG_CIFS_POSIX
1762
1763 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1764 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1765 {
1766         /* u8 cifs fields do not need le conversion */
1767         ace->e_perm = (__u16)cifs_ace->cifs_e_perm; 
1768         ace->e_tag  = (__u16)cifs_ace->cifs_e_tag;
1769         ace->e_id   = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1770         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1771
1772         return;
1773 }
1774
1775 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
1776 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,const int acl_type,const int size_of_data_area)
1777 {
1778         int size =  0;
1779         int i;
1780         __u16 count;
1781         struct cifs_posix_ace * pACE;
1782         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1783         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1784
1785         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1786                 return -EOPNOTSUPP;
1787
1788         if(acl_type & ACL_TYPE_ACCESS) {
1789                 count = le16_to_cpu(cifs_acl->access_entry_count);
1790                 pACE = &cifs_acl->ace_array[0];
1791                 size = sizeof(struct cifs_posix_acl);
1792                 size += sizeof(struct cifs_posix_ace) * count;
1793                 /* check if we would go beyond end of SMB */
1794                 if(size_of_data_area < size) {
1795                         cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
1796                         return -EINVAL;
1797                 }
1798         } else if(acl_type & ACL_TYPE_DEFAULT) {
1799                 count = le16_to_cpu(cifs_acl->access_entry_count);
1800                 size = sizeof(struct cifs_posix_acl);
1801                 size += sizeof(struct cifs_posix_ace) * count;
1802 /* skip past access ACEs to get to default ACEs */
1803                 pACE = &cifs_acl->ace_array[count];
1804                 count = le16_to_cpu(cifs_acl->default_entry_count);
1805                 size += sizeof(struct cifs_posix_ace) * count;
1806                 /* check if we would go beyond end of SMB */
1807                 if(size_of_data_area < size)
1808                         return -EINVAL;
1809         } else {
1810                 /* illegal type */
1811                 return -EINVAL;
1812         }
1813
1814         size = posix_acl_xattr_size(count);
1815         if((buflen == 0) || (local_acl == NULL)) {
1816                 /* used to query ACL EA size */                         
1817         } else if(size > buflen) {
1818                 return -ERANGE;
1819         } else /* buffer big enough */ {
1820                 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
1821                 for(i = 0;i < count ;i++) {
1822                         cifs_convert_ace(&local_acl->a_entries[i],pACE);
1823                         pACE ++;
1824                 }
1825         }
1826         return size;
1827 }
1828
1829 __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
1830                         const posix_acl_xattr_entry * local_ace)
1831 {
1832         __u16 rc = 0; /* 0 = ACL converted ok */
1833
1834         cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
1835         cifs_ace->cifs_e_tag =  (__u8)cpu_to_le16(local_ace->e_tag);
1836         /* BB is there a better way to handle the large uid? */
1837         if(local_ace->e_id == -1) {
1838         /* Probably no need to le convert -1 on any arch but can not hurt */
1839                 cifs_ace->cifs_uid = cpu_to_le64(-1);
1840         } else 
1841                 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
1842         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
1843         return rc;
1844 }
1845
1846 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
1847 __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
1848                 const int acl_type)
1849 {
1850         __u16 rc = 0;
1851         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
1852         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
1853         int count;
1854         int i;
1855
1856         if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1857                 return 0;
1858
1859         count = posix_acl_xattr_count((size_t)buflen);
1860         cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
1861                 count,buflen,local_acl->a_version));
1862         if(local_acl->a_version != 2) {
1863                 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
1864                 return 0;
1865         }
1866         cifs_acl->version = cpu_to_le16(1);
1867         if(acl_type == ACL_TYPE_ACCESS) 
1868                 cifs_acl->access_entry_count = count;
1869         else if(acl_type == ACL_TYPE_DEFAULT)
1870                 cifs_acl->default_entry_count = count;
1871         else {
1872                 cFYI(1,("unknown ACL type %d",acl_type));
1873                 return 0;
1874         }
1875         for(i=0;i<count;i++) {
1876                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
1877                                         &local_acl->a_entries[i]);
1878                 if(rc != 0) {
1879                         /* ACE not converted */
1880                         break;
1881                 }
1882         }
1883         if(rc == 0) {
1884                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
1885                 rc += sizeof(struct cifs_posix_acl);
1886                 /* BB add check to make sure ACL does not overflow SMB */
1887         }
1888         return rc;
1889 }
1890
1891 int
1892 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
1893                         const unsigned char *searchName,
1894                         char *acl_inf, const int buflen, const int acl_type,
1895                         const struct nls_table *nls_codepage)
1896 {
1897 /* SMB_QUERY_POSIX_ACL */
1898         TRANSACTION2_QPI_REQ *pSMB = NULL;
1899         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1900         int rc = 0;
1901         int bytes_returned;
1902         int name_len;
1903         __u16 params, byte_count;
1904                                                                                                                                              
1905         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
1906
1907 queryAclRetry:
1908         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1909                 (void **) &pSMBr);
1910         if (rc)
1911                 return rc;
1912                                                                                                                                              
1913         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1914                 name_len =
1915                         cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1916                                 /* BB fixme find define for this maxpathcomponent */
1917                                 , nls_codepage);
1918                 name_len++;     /* trailing null */
1919                 name_len *= 2;
1920                 pSMB->FileName[name_len] = 0;
1921                 pSMB->FileName[name_len+1] = 0;
1922         } else {                /* BB improve the check for buffer overruns BB */
1923                 name_len = strnlen(searchName, PATH_MAX /* BB fixme */);
1924                 name_len++;     /* trailing null */
1925                 strncpy(pSMB->FileName, searchName, name_len);
1926         }
1927
1928         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1929         pSMB->TotalDataCount = 0;
1930         pSMB->MaxParameterCount = cpu_to_le16(2);
1931         /* BB find exact max data count below from sess structure BB */
1932         pSMB->MaxDataCount = cpu_to_le16(4000);
1933         pSMB->MaxSetupCount = 0;
1934         pSMB->Reserved = 0;
1935         pSMB->Flags = 0;
1936         pSMB->Timeout = 0;
1937         pSMB->Reserved2 = 0;
1938         pSMB->ParameterOffset = cpu_to_le16(
1939                 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1940         pSMB->DataCount = 0;
1941         pSMB->DataOffset = 0;
1942         pSMB->SetupCount = 1;
1943         pSMB->Reserved3 = 0;
1944         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1945         byte_count = params + 1 /* pad */ ;
1946         pSMB->TotalParameterCount = cpu_to_le16(params);
1947         pSMB->ParameterCount = pSMB->TotalParameterCount;
1948         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
1949         pSMB->Reserved4 = 0;
1950         pSMB->hdr.smb_buf_length += byte_count;
1951         pSMB->ByteCount = cpu_to_le16(byte_count);
1952
1953         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1954                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1955         if (rc) {
1956                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
1957         } else {
1958                 /* decode response */
1959  
1960                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1961                 if (rc || (pSMBr->ByteCount < 2))
1962                 /* BB also check enough total bytes returned */
1963                         rc = -EIO;      /* bad smb */
1964                 else {
1965                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1966                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1967                         rc = cifs_copy_posix_acl(acl_inf,
1968                                 (char *)&pSMBr->hdr.Protocol+data_offset,
1969                                 buflen,acl_type,count);
1970                 }
1971         }
1972         if (pSMB)
1973                 cifs_buf_release(pSMB);
1974         if (rc == -EAGAIN)
1975                 goto queryAclRetry;
1976         return rc;
1977 }
1978
1979 int
1980 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
1981                         const unsigned char *fileName,
1982                         const char *local_acl, const int buflen, const int acl_type,
1983                         const struct nls_table *nls_codepage)
1984 {
1985         struct smb_com_transaction2_spi_req *pSMB = NULL;
1986         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
1987         char *parm_data;
1988         int name_len;
1989         int rc = 0;
1990         int bytes_returned = 0;
1991         __u16 params, byte_count, data_count, param_offset, offset;
1992
1993         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
1994 setAclRetry:
1995         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1996                       (void **) &pSMBr);
1997         if (rc)
1998                 return rc;
1999                                                                                                                 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2000                 name_len =
2001                         cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
2002                                 /* BB fixme find define for this maxpathcomponent */
2003                                 , nls_codepage);
2004                 name_len++;     /* trailing null */
2005                 name_len *= 2;
2006         } else {                /* BB improve the check for buffer overruns BB */
2007                 name_len = strnlen(fileName, PATH_MAX);
2008                 name_len++;     /* trailing null */
2009                 strncpy(pSMB->FileName, fileName, name_len);
2010         }
2011         params = 6 + name_len;
2012         pSMB->MaxParameterCount = cpu_to_le16(2);
2013         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2014         pSMB->MaxSetupCount = 0;
2015         pSMB->Reserved = 0;
2016         pSMB->Flags = 0;
2017         pSMB->Timeout = 0;
2018         pSMB->Reserved2 = 0;
2019         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2020                                      InformationLevel) - 4;
2021         offset = param_offset + params;
2022         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2023         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2024
2025         /* convert to on the wire format for POSIX ACL */
2026         data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2027
2028         if(data_count == 0) {
2029                 rc = -EOPNOTSUPP;
2030                 goto setACLerrorExit;
2031         }
2032         pSMB->DataOffset = cpu_to_le16(offset);
2033         pSMB->SetupCount = 1;
2034         pSMB->Reserved3 = 0;
2035         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2036         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2037         byte_count = 3 /* pad */  + params + data_count;
2038         pSMB->DataCount = cpu_to_le16(data_count);
2039         pSMB->TotalDataCount = pSMB->DataCount;
2040         pSMB->ParameterCount = cpu_to_le16(params);
2041         pSMB->TotalParameterCount = pSMB->ParameterCount;
2042         pSMB->Reserved4 = 0;
2043         pSMB->hdr.smb_buf_length += byte_count;
2044         pSMB->ByteCount = cpu_to_le16(byte_count);
2045         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2046                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2047         if (rc) {
2048                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2049         }
2050
2051 setACLerrorExit:
2052         if (pSMB)
2053                 cifs_buf_release(pSMB);
2054                                                                                                                 if (rc == -EAGAIN)
2055                 goto setAclRetry;
2056                                                                                                                 return rc;
2057 }
2058
2059 #endif
2060
2061 int
2062 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2063                  const unsigned char *searchName,
2064                  FILE_ALL_INFO * pFindData,
2065                  const struct nls_table *nls_codepage)
2066 {
2067 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2068         TRANSACTION2_QPI_REQ *pSMB = NULL;
2069         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2070         int rc = 0;
2071         int bytes_returned;
2072         int name_len;
2073         __u16 params, byte_count;
2074
2075 /* cFYI(1, ("In QPathInfo path %s", searchName)); */ /* BB fixme BB */
2076 QPathInfoRetry:
2077         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2078                       (void **) &pSMBr);
2079         if (rc)
2080                 return rc;
2081
2082         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2083                 name_len =
2084                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
2085                                   /* find define for this maxpathcomponent */
2086                                   , nls_codepage);
2087                 name_len++;     /* trailing null */
2088                 name_len *= 2;
2089         } else {                /* BB improve the check for buffer overruns BB */
2090                 name_len = strnlen(searchName, PATH_MAX);
2091                 name_len++;     /* trailing null */
2092                 strncpy(pSMB->FileName, searchName, name_len);
2093         }
2094
2095         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2096         pSMB->TotalDataCount = 0;
2097         pSMB->MaxParameterCount = cpu_to_le16(2);
2098         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2099         pSMB->MaxSetupCount = 0;
2100         pSMB->Reserved = 0;
2101         pSMB->Flags = 0;
2102         pSMB->Timeout = 0;
2103         pSMB->Reserved2 = 0;
2104         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2105         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2106         pSMB->DataCount = 0;
2107         pSMB->DataOffset = 0;
2108         pSMB->SetupCount = 1;
2109         pSMB->Reserved3 = 0;
2110         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2111         byte_count = params + 1 /* pad */ ;
2112         pSMB->TotalParameterCount = cpu_to_le16(params);
2113         pSMB->ParameterCount = pSMB->TotalParameterCount;
2114         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2115         pSMB->Reserved4 = 0;
2116         pSMB->hdr.smb_buf_length += byte_count;
2117         pSMB->ByteCount = cpu_to_le16(byte_count);
2118
2119         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2120                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2121         if (rc) {
2122                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2123         } else {                /* decode response */
2124                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2125
2126                 if (rc || (pSMBr->ByteCount < 40)) 
2127                         rc = -EIO;      /* bad smb */
2128                 else if (pFindData){
2129                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2130                         memcpy((char *) pFindData,
2131                                (char *) &pSMBr->hdr.Protocol +
2132                                data_offset, sizeof (FILE_ALL_INFO));
2133                 } else
2134                     rc = -ENOMEM;
2135         }
2136         if (pSMB)
2137                 cifs_buf_release(pSMB);
2138         if (rc == -EAGAIN)
2139                 goto QPathInfoRetry;
2140
2141         return rc;
2142 }
2143
2144 int
2145 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2146                      const unsigned char *searchName,
2147                      FILE_UNIX_BASIC_INFO * pFindData,
2148                      const struct nls_table *nls_codepage)
2149 {
2150 /* SMB_QUERY_FILE_UNIX_BASIC */
2151         TRANSACTION2_QPI_REQ *pSMB = NULL;
2152         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2153         int rc = 0;
2154         int bytes_returned = 0;
2155         int name_len;
2156         __u16 params, byte_count;
2157
2158         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2159 UnixQPathInfoRetry:
2160         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2161                       (void **) &pSMBr);
2162         if (rc)
2163                 return rc;
2164
2165         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2166                 name_len =
2167                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
2168                                   /* find define for this maxpathcomponent */
2169                                   , nls_codepage);
2170                 name_len++;     /* trailing null */
2171                 name_len *= 2;
2172         } else {                /* BB improve the check for buffer overruns BB */
2173                 name_len = strnlen(searchName, PATH_MAX);
2174                 name_len++;     /* trailing null */
2175                 strncpy(pSMB->FileName, searchName, name_len);
2176         }
2177
2178         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2179         pSMB->TotalDataCount = 0;
2180         pSMB->MaxParameterCount = cpu_to_le16(2);
2181         /* BB find exact max SMB PDU from sess structure BB */
2182         pSMB->MaxDataCount = cpu_to_le16(4000); 
2183         pSMB->MaxSetupCount = 0;
2184         pSMB->Reserved = 0;
2185         pSMB->Flags = 0;
2186         pSMB->Timeout = 0;
2187         pSMB->Reserved2 = 0;
2188         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2189         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2190         pSMB->DataCount = 0;
2191         pSMB->DataOffset = 0;
2192         pSMB->SetupCount = 1;
2193         pSMB->Reserved3 = 0;
2194         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2195         byte_count = params + 1 /* pad */ ;
2196         pSMB->TotalParameterCount = cpu_to_le16(params);
2197         pSMB->ParameterCount = pSMB->TotalParameterCount;
2198         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2199         pSMB->Reserved4 = 0;
2200         pSMB->hdr.smb_buf_length += byte_count;
2201         pSMB->ByteCount = cpu_to_le16(byte_count);
2202
2203         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2204                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2205         if (rc) {
2206                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2207         } else {                /* decode response */
2208                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2209
2210                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2211                         rc = -EIO;      /* bad smb */
2212                 } else {
2213                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2214                         memcpy((char *) pFindData,
2215                                (char *) &pSMBr->hdr.Protocol +
2216                                data_offset,
2217                                sizeof (FILE_UNIX_BASIC_INFO));
2218                 }
2219         }
2220         if (pSMB)
2221                 cifs_buf_release(pSMB);
2222         if (rc == -EAGAIN)
2223                 goto UnixQPathInfoRetry;
2224
2225         return rc;
2226 }
2227
2228 #ifdef CONFIG_CIFS_EXPERIMENTAL  /* function unused at present */
2229 int
2230 CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2231                const char *searchName, FILE_ALL_INFO * findData,
2232                const struct nls_table *nls_codepage)
2233 {
2234 /* level 257 SMB_ */
2235         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2236         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2237         int rc = 0;
2238         int bytes_returned;
2239         int name_len;
2240         __u16 params, byte_count;
2241
2242         cFYI(1, ("In FindUnique"));
2243 findUniqueRetry:
2244         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2245                       (void **) &pSMBr);
2246         if (rc)
2247                 return rc;
2248
2249         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2250                 name_len =
2251                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
2252                                   /* find define for this maxpathcomponent */
2253                                   , nls_codepage);
2254                 name_len++;     /* trailing null */
2255                 name_len *= 2;
2256         } else {                /* BB improve the check for buffer overruns BB */
2257                 name_len = strnlen(searchName, PATH_MAX);
2258                 name_len++;     /* trailing null */
2259                 strncpy(pSMB->FileName, searchName, name_len);
2260         }
2261
2262         params = 12 + name_len /* includes null */ ;
2263         pSMB->TotalDataCount = 0;       /* no EAs */
2264         pSMB->MaxParameterCount = cpu_to_le16(2);
2265         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2266         pSMB->MaxSetupCount = 0;
2267         pSMB->Reserved = 0;
2268         pSMB->Flags = 0;
2269         pSMB->Timeout = 0;
2270         pSMB->Reserved2 = 0;
2271         pSMB->ParameterOffset = cpu_to_le16(
2272          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2273         pSMB->DataCount = 0;
2274         pSMB->DataOffset = 0;
2275         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
2276         pSMB->Reserved3 = 0;
2277         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2278         byte_count = params + 1 /* pad */ ;
2279         pSMB->TotalParameterCount = cpu_to_le16(params);
2280         pSMB->ParameterCount = pSMB->TotalParameterCount;
2281         pSMB->SearchAttributes =
2282             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2283                         ATTR_DIRECTORY);
2284         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
2285         pSMB->SearchFlags = cpu_to_le16(1);
2286         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2287         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
2288         pSMB->hdr.smb_buf_length += byte_count;
2289         pSMB->ByteCount = cpu_to_le16(byte_count);
2290
2291         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2292                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2293
2294         if (rc) {
2295                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2296         } else {                /* decode response */
2297
2298                 /* BB fill in */
2299         }
2300         if (pSMB)
2301                 cifs_buf_release(pSMB);
2302         if (rc == -EAGAIN)
2303                 goto findUniqueRetry;
2304
2305         return rc;
2306 }
2307 #endif /* CIFS_EXPERIMENTAL */
2308
2309 int
2310 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2311               const char *searchName, FILE_DIRECTORY_INFO * findData,
2312               T2_FFIRST_RSP_PARMS * findParms,
2313               const struct nls_table *nls_codepage, int *pUnicodeFlag,
2314               int *pUnixFlag)
2315 {
2316 /* level 257 SMB_ */
2317         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2318         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2319         char *response_data;
2320         int rc = 0;
2321         int bytes_returned;
2322         int name_len;
2323         __u16 params, byte_count;
2324
2325         cFYI(1, ("In FindFirst"));
2326 findFirstRetry:
2327         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2328                       (void **) &pSMBr);
2329         if (rc)
2330                 return rc;
2331
2332         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2333                 name_len =
2334                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
2335                                   /* find define for this maxpathcomponent */
2336                                   , nls_codepage);
2337                 name_len++;     /* trailing null */
2338                 name_len *= 2;
2339         } else {                /* BB improve the check for buffer overruns BB */
2340                 name_len = strnlen(searchName, PATH_MAX);
2341                 name_len++;     /* trailing null */
2342                 strncpy(pSMB->FileName, searchName, name_len);
2343         }
2344
2345         params = 12 + name_len /* includes null */ ;
2346         pSMB->TotalDataCount = 0;       /* no EAs */
2347         pSMB->MaxParameterCount = cpu_to_le16(10);
2348         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2349                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2350         pSMB->MaxSetupCount = 0;
2351         pSMB->Reserved = 0;
2352         pSMB->Flags = 0;
2353         pSMB->Timeout = 0;
2354         pSMB->Reserved2 = 0;
2355         byte_count = params + 1 /* pad */ ;
2356         pSMB->TotalParameterCount = cpu_to_le16(params);
2357         pSMB->ParameterCount = pSMB->TotalParameterCount;
2358         pSMB->ParameterOffset = cpu_to_le16(
2359                 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2360         pSMB->DataCount = 0;
2361         pSMB->DataOffset = 0;
2362         pSMB->SetupCount = 1;   /* one byte no need to make endian neutral */
2363         pSMB->Reserved3 = 0;
2364         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2365         pSMB->SearchAttributes =
2366             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2367                         ATTR_DIRECTORY);
2368         pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_DIRECTORY_INFO)); /* should this be shrunk even more ? */
2369         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2370
2371         /* test for Unix extensions */
2372         if (tcon->ses->capabilities & CAP_UNIX) {
2373                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2374                 *pUnixFlag = TRUE;
2375         } else {
2376                 pSMB->InformationLevel =
2377                     cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2378                 *pUnixFlag = FALSE;
2379         }
2380         pSMB->SearchStorageType = 0;    /* BB what should we set this to? It is not clear if it matters BB */
2381         pSMB->hdr.smb_buf_length += byte_count;
2382         pSMB->ByteCount = cpu_to_le16(byte_count);
2383
2384         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2385                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2386
2387         if (rc) {               /* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2388                 cFYI(1, ("Error in FindFirst = %d", rc));
2389         } else {
2390                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2391                 if(!rc) {
2392                 /* decode response */
2393                 /* BB add safety checks for these memcpys */
2394                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2395                                 *pUnicodeFlag = TRUE;
2396                         else
2397                                 *pUnicodeFlag = FALSE;
2398                         memcpy(findParms,
2399                                (char *) &pSMBr->hdr.Protocol +
2400                                le16_to_cpu(pSMBr->t2.ParameterOffset),
2401                                sizeof (T2_FFIRST_RSP_PARMS));
2402                         response_data =
2403                             (char *) &pSMBr->hdr.Protocol +
2404                             le16_to_cpu(pSMBr->t2.DataOffset);
2405                         memcpy(findData, response_data, 
2406                                 le16_to_cpu(pSMBr->t2.DataCount));
2407                 }
2408         }
2409         if (pSMB)
2410                 cifs_buf_release(pSMB);
2411
2412         if (rc == -EAGAIN)
2413                 goto findFirstRetry;
2414
2415         return rc;
2416 }
2417
2418 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2419 int
2420 CIFSFindFirst2(const int xid, struct cifsTconInfo *tcon,
2421               const char *searchName, 
2422               const struct nls_table *nls_codepage,
2423               __u16 *   pnetfid,
2424               struct cifs_search_info * psrch_inf)
2425 {
2426 /* level 257 SMB_ */
2427         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2428         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2429         T2_FFIRST_RSP_PARMS * parms;
2430         int rc = 0;
2431         int bytes_returned = 0;
2432         int name_len;
2433         __u16 params, byte_count;
2434
2435         cFYI(1, ("In FindFirst2"));
2436
2437 findFirst2Retry:
2438         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2439                       (void **) &pSMBr);
2440         if (rc)
2441                 return rc;
2442
2443         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2444                 name_len =
2445                     cifs_strtoUCS((wchar_t *) pSMB->FileName,searchName,
2446                                  PATH_MAX, nls_codepage);
2447                 name_len++;     /* trailing null */
2448                 name_len *= 2;
2449                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2450                 pSMB->FileName[name_len+1] = 0;
2451         } else {        /* BB add check for overrun of SMB buf BB */
2452                 name_len = strnlen(searchName, PATH_MAX);
2453                 name_len++;     /* trailing null */
2454 /* BB fix here and in unicode clause above ie
2455                 if(name_len > buffersize-header)
2456                         free buffer exit; BB */
2457                 strncpy(pSMB->FileName, searchName, name_len);
2458                 pSMB->FileName[name_len] = 0; /* just in case */
2459         }
2460
2461         params = 12 + name_len /* includes null */ ;
2462         pSMB->TotalDataCount = 0;       /* no EAs */
2463         pSMB->MaxParameterCount = cpu_to_le16(10);
2464         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2465                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2466         pSMB->MaxSetupCount = 0;
2467         pSMB->Reserved = 0;
2468         pSMB->Flags = 0;
2469         pSMB->Timeout = 0;
2470         pSMB->Reserved2 = 0;
2471         byte_count = params + 1 /* pad */ ;
2472         pSMB->TotalParameterCount = cpu_to_le16(params);
2473         pSMB->ParameterCount = pSMB->TotalParameterCount;
2474         pSMB->ParameterOffset = cpu_to_le16(
2475           offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2476         pSMB->DataCount = 0;
2477         pSMB->DataOffset = 0;
2478         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
2479         pSMB->Reserved3 = 0;
2480         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2481         pSMB->SearchAttributes =
2482             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2483                         ATTR_DIRECTORY);
2484         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2485         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
2486                 CIFS_SEARCH_RETURN_RESUME);
2487         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2488
2489         /* BB what should we set StorageType to? Does it matter? BB */
2490         pSMB->SearchStorageType = 0;
2491         pSMB->hdr.smb_buf_length += byte_count;
2492         pSMB->ByteCount = cpu_to_le16(byte_count);
2493
2494         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2495                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2496
2497         if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2498                 /* BB Add code to handle unsupported level rc */
2499                 cFYI(1, ("Error in FindFirst = %d", rc));
2500
2501                 if (pSMB)
2502                         cifs_buf_release(pSMB);
2503
2504                 /* BB eventually could optimize out free and realloc of buf */
2505                 /*    for this case */
2506                 if (rc == -EAGAIN)
2507                         goto findFirst2Retry;
2508         } else { /* decode response */
2509                 /* BB remember to free buffer if error BB */
2510                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2511                 if(rc == 0) {
2512                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2513                                 psrch_inf->unicode = TRUE;
2514                         else
2515                                 psrch_inf->unicode = FALSE;
2516
2517                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2518                         psrch_inf->srch_entries_start = 
2519                                 (char *) &pSMBr->hdr.Protocol + 
2520                                         le16_to_cpu(pSMBr->t2.DataOffset);
2521
2522                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2523                                le16_to_cpu(pSMBr->t2.ParameterOffset));
2524
2525                         if(parms->EndofSearch)
2526                                 psrch_inf->endOfSearch = TRUE;
2527                         else
2528                                 psrch_inf->endOfSearch = FALSE;
2529
2530                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2531                         psrch_inf->index_of_last_entry = 
2532                                 psrch_inf->entries_in_buffer;
2533 /*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry));  */
2534                         *pnetfid = parms->SearchHandle;
2535                 } else {
2536                         if(pSMB)
2537                                 cifs_buf_release(pSMB);
2538                 }
2539         }
2540
2541         return rc;
2542 }
2543
2544 int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
2545             __u16 searchHandle, struct cifs_search_info * psrch_inf)
2546 {
2547         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2548         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2549         T2_FNEXT_RSP_PARMS * parms;
2550         char *response_data;
2551         int rc = 0;
2552         int bytes_returned, name_len;
2553         __u16 params, byte_count;
2554
2555         cFYI(1, ("In FindNext2"));
2556
2557         if(psrch_inf->endOfSearch == TRUE)
2558                 return -ENOENT;
2559
2560         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2561                 (void **) &pSMBr);
2562         if (rc)
2563                 return rc;
2564
2565         params = 14;    /* includes 2 bytes of null string, converted to LE below */
2566         byte_count = 0;
2567         pSMB->TotalDataCount = 0;       /* no EAs */
2568         pSMB->MaxParameterCount = cpu_to_le16(8);
2569         pSMB->MaxDataCount =
2570             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2571         pSMB->MaxSetupCount = 0;
2572         pSMB->Reserved = 0;
2573         pSMB->Flags = 0;
2574         pSMB->Timeout = 0;
2575         pSMB->Reserved2 = 0;
2576         pSMB->ParameterOffset =  cpu_to_le16(
2577               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2578         pSMB->DataCount = 0;
2579         pSMB->DataOffset = 0;
2580         pSMB->SetupCount = 1;
2581         pSMB->Reserved3 = 0;
2582         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2583         pSMB->SearchHandle = searchHandle;      /* always kept as le */
2584         pSMB->SearchCount =
2585                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2586         /* test for Unix extensions */
2587 /*      if (tcon->ses->capabilities & CAP_UNIX) {
2588                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2589                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2590         } else {
2591                 pSMB->InformationLevel =
2592                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2593                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2594         } */
2595         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2596         pSMB->ResumeKey = psrch_inf->resume_key;
2597         pSMB->SearchFlags =
2598               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2599
2600         name_len = psrch_inf->resume_name_len;
2601         params += name_len;
2602         if(name_len < PATH_MAX) {
2603                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2604                 byte_count += name_len;
2605         } else {
2606                 rc = -EINVAL;
2607                 goto FNext2_err_exit;
2608         }
2609         byte_count = params + 1 /* pad */ ;
2610         pSMB->TotalParameterCount = cpu_to_le16(params);
2611         pSMB->ParameterCount = pSMB->TotalParameterCount;
2612         pSMB->hdr.smb_buf_length += byte_count;
2613         pSMB->ByteCount = cpu_to_le16(byte_count);
2614                                                                                               
2615         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2616                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2617                                                                                               
2618         if (rc) {
2619                 if (rc == -EBADF) {
2620                         psrch_inf->endOfSearch = TRUE;
2621                         rc = 0; /* search probably was closed at end of search above */
2622                 } else
2623                         cFYI(1, ("FindNext returned = %d", rc));
2624         } else {                /* decode response */
2625                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2626                 
2627                 if(rc == 0) {
2628                         /* BB fixme add lock for file (srch_info) struct here */
2629                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2630                                 psrch_inf->unicode = TRUE;
2631                         else
2632                                 psrch_inf->unicode = FALSE;
2633                         response_data = (char *) &pSMBr->hdr.Protocol +
2634                                le16_to_cpu(pSMBr->t2.ParameterOffset);
2635                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
2636                         response_data = (char *)&pSMBr->hdr.Protocol +
2637                                 le16_to_cpu(pSMBr->t2.DataOffset);
2638                         cifs_buf_release(psrch_inf->ntwrk_buf_start);
2639                         psrch_inf->srch_entries_start = response_data;
2640                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
2641                         if(parms->EndofSearch)
2642                                 psrch_inf->endOfSearch = TRUE;
2643                         else
2644                                 psrch_inf->endOfSearch = FALSE;
2645                                                                                               
2646                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2647                         psrch_inf->index_of_last_entry +=
2648                                 psrch_inf->entries_in_buffer;
2649 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2650
2651                         /* BB fixme add unlock here */
2652                 }
2653
2654         }
2655
2656         /* BB On error, should we leave previous search buf (and count and
2657         last entry fields) intact or free the previous one? */
2658
2659         /* Note: On -EAGAIN error only caller can retry on handle based calls
2660         since file handle passed in no longer valid */
2661 FNext2_err_exit:
2662         if ((rc != 0) && pSMB)
2663                 cifs_buf_release(pSMB);
2664                                                                                               
2665         return rc;
2666 }
2667
2668 int
2669 CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2670                 FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms,
2671                 const __u16 searchHandle, char * resume_file_name, int name_len,
2672                 __u32 resume_key, int *pUnicodeFlag, int *pUnixFlag)
2673 {
2674 /* level 257 SMB_ */
2675         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2676         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2677         char *response_data;
2678         int rc = 0;
2679         int bytes_returned;
2680         __u16 params, byte_count;
2681
2682         cFYI(1, ("In FindNext"));
2683
2684         if(resume_file_name == NULL) {
2685                 return -EIO;
2686         }
2687         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2688                       (void **) &pSMBr);
2689         if (rc)
2690                 return rc;
2691
2692         params = 14;    /* includes 2 bytes of null string, converted to LE below */
2693         byte_count = 0;
2694         pSMB->TotalDataCount = 0;       /* no EAs */
2695         pSMB->MaxParameterCount = cpu_to_le16(8);
2696         pSMB->MaxDataCount =
2697             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2698         pSMB->MaxSetupCount = 0;
2699         pSMB->Reserved = 0;
2700         pSMB->Flags = 0;
2701         pSMB->Timeout = 0;
2702         pSMB->Reserved2 = 0;
2703         pSMB->ParameterOffset =  cpu_to_le16(
2704            offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2705         pSMB->DataCount = 0;
2706         pSMB->DataOffset = 0;
2707         pSMB->SetupCount = 1;
2708         pSMB->Reserved3 = 0;
2709         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2710         pSMB->SearchHandle = searchHandle;      /* always kept as le */
2711         findParms->SearchCount = 0;     /* set to zero in case of error */
2712         pSMB->SearchCount =
2713             cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2714         /* test for Unix extensions */
2715         if (tcon->ses->capabilities & CAP_UNIX) {
2716                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2717                 *pUnixFlag = TRUE;
2718         } else {
2719                 pSMB->InformationLevel =
2720                     cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2721                 *pUnixFlag = FALSE;
2722         }
2723         pSMB->ResumeKey = resume_key;
2724         pSMB->SearchFlags =
2725             cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2726         /* BB add check to make sure we do not cross end of smb */
2727         if(name_len < PATH_MAX) {
2728                 memcpy(pSMB->ResumeFileName, resume_file_name, name_len);
2729                 byte_count += name_len;
2730         }
2731         params += name_len;
2732         byte_count = params + 1 /* pad */ ;
2733         pSMB->TotalParameterCount = cpu_to_le16(params);
2734         pSMB->ParameterCount = pSMB->TotalParameterCount;
2735         /* BB improve error handling here */
2736         pSMB->hdr.smb_buf_length += byte_count;
2737         pSMB->ByteCount = cpu_to_le16(byte_count);
2738
2739         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2740                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2741
2742         if (rc) {
2743                 if (rc == -EBADF)
2744                         rc = 0; /* search probably was closed at end of search above */
2745                 else
2746                         cFYI(1, ("FindNext returned = %d", rc));
2747         } else {                /* decode response */
2748                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2749
2750                 /* BB add safety checks for these memcpys */
2751                 if(rc == 0) {
2752                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2753                                 *pUnicodeFlag = TRUE;
2754                         else
2755                                 *pUnicodeFlag = FALSE;
2756                         memcpy(findParms,
2757                                (char *) &pSMBr->hdr.Protocol +
2758                                le16_to_cpu(pSMBr->t2.ParameterOffset),
2759                                sizeof (T2_FNEXT_RSP_PARMS));
2760                         response_data =
2761                             (char *) &pSMBr->hdr.Protocol +
2762                             le16_to_cpu(pSMBr->t2.DataOffset);
2763                         memcpy(findData,response_data,le16_to_cpu(pSMBr->t2.DataCount));
2764                 }
2765         }
2766         if (pSMB)
2767                 cifs_buf_release(pSMB);
2768
2769         /* Note: On -EAGAIN error only caller can retry on handle based calls
2770                 since file handle passed in no longer valid */
2771
2772         return rc;
2773 }
2774
2775 int
2776 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2777 {
2778         int rc = 0;
2779         FINDCLOSE_REQ *pSMB = NULL;
2780         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2781         int bytes_returned;
2782
2783         cFYI(1, ("In CIFSSMBFindClose"));
2784         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2785         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
2786         /* no sense returning error if session restarted
2787                 file handle has been closed */
2788         if(rc == -EAGAIN)
2789                 return 0;
2790         if (rc)
2791                 return rc;
2792
2793         pSMB->FileID = searchHandle;
2794         pSMB->ByteCount = 0;
2795         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2796                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2797         if (rc) {
2798                 cERROR(1, ("Send error in FindClose = %d", rc));
2799         }
2800         if (pSMB)
2801                 cifs_small_buf_release(pSMB);
2802
2803         /* Since session is dead, search handle closed on server already */
2804         if (rc == -EAGAIN)
2805                 rc = 0;
2806
2807         return rc;
2808 }
2809
2810 #ifdef CONFIG_CIFS_EXPERIMENTAL
2811 int
2812 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2813                 const unsigned char *searchName,
2814                 __u64 * inode_number,
2815                 const struct nls_table *nls_codepage)
2816 {
2817         int rc = 0;
2818         TRANSACTION2_QPI_REQ *pSMB = NULL;
2819         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2820
2821         cFYI(1,("In GetSrvInodeNumber for %s",searchName));
2822         if(tcon == NULL)
2823                 return -ENODEV; 
2824
2825         cFYI(1, ("In QPathInfo path %s", searchName));
2826 GetInodeNumberRetry:
2827         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2828                       (void **) &pSMBr);
2829         if (rc)
2830                 return rc;
2831
2832 /* BB add missing code here */
2833
2834         if (pSMB)
2835                 cifs_buf_release(pSMB);
2836                                                                                                                          
2837         if (rc == -EAGAIN)
2838                 goto GetInodeNumberRetry;
2839         return rc;
2840 }
2841 #endif /* CIFS_EXPERIMENTAL */
2842
2843 int
2844 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2845                 const unsigned char *searchName,
2846                 unsigned char **targetUNCs,
2847                 unsigned int *number_of_UNC_in_array,
2848                 const struct nls_table *nls_codepage)
2849 {
2850 /* TRANS2_GET_DFS_REFERRAL */
2851         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2852         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2853         struct dfs_referral_level_3 * referrals = NULL;
2854         int rc = 0;
2855         int bytes_returned;
2856         int name_len;
2857         unsigned int i;
2858         char * temp;
2859         __u16 params, byte_count;
2860         *number_of_UNC_in_array = 0;
2861         *targetUNCs = NULL;
2862
2863         cFYI(1, ("In GetDFSRefer the path %s", searchName));
2864         if (ses == NULL)
2865                 return -ENODEV;
2866 getDFSRetry:
2867         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2868                       (void **) &pSMBr);
2869         if (rc)
2870                 return rc;
2871
2872         pSMB->hdr.Tid = ses->ipc_tid;
2873         pSMB->hdr.Uid = ses->Suid;
2874         if (ses->capabilities & CAP_STATUS32) {
2875                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2876         }
2877         if (ses->capabilities & CAP_DFS) {
2878                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2879         }
2880
2881         if (ses->capabilities & CAP_UNICODE) {
2882                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2883                 name_len =
2884                     cifs_strtoUCS((wchar_t *) pSMB->RequestFileName,
2885                                   searchName, PATH_MAX
2886                                   /* find define for this maxpathcomponent */
2887                                   , nls_codepage);
2888                 name_len++;     /* trailing null */
2889                 name_len *= 2;
2890         } else {                /* BB improve the check for buffer overruns BB */
2891                 name_len = strnlen(searchName, PATH_MAX);
2892                 name_len++;     /* trailing null */
2893                 strncpy(pSMB->RequestFileName, searchName, name_len);
2894         }
2895
2896         params = 2 /* level */  + name_len /*includes null */ ;
2897         pSMB->TotalDataCount = 0;
2898         pSMB->DataCount = 0;
2899         pSMB->DataOffset = 0;
2900         pSMB->MaxParameterCount = 0;
2901         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2902         pSMB->MaxSetupCount = 0;
2903         pSMB->Reserved = 0;
2904         pSMB->Flags = 0;
2905         pSMB->Timeout = 0;
2906         pSMB->Reserved2 = 0;
2907         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2908         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2909         pSMB->SetupCount = 1;
2910         pSMB->Reserved3 = 0;
2911         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2912         byte_count = params + 3 /* pad */ ;
2913         pSMB->ParameterCount = cpu_to_le16(params);
2914         pSMB->TotalParameterCount = pSMB->ParameterCount;
2915         pSMB->MaxReferralLevel = cpu_to_le16(3);
2916         pSMB->hdr.smb_buf_length += byte_count;
2917         pSMB->ByteCount = cpu_to_le16(byte_count);
2918
2919         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2920                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2921         if (rc) {
2922                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2923         } else {                /* decode response */
2924 /* BB Add logic to parse referrals here */
2925                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2926
2927                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
2928                         rc = -EIO;      /* bad smb */
2929                 else {
2930                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
2931                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2932
2933                         cFYI(1,
2934                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
2935                               pSMBr->ByteCount, data_offset));
2936                         referrals = 
2937                             (struct dfs_referral_level_3 *) 
2938                                         (8 /* sizeof start of data block */ +
2939                                         data_offset +
2940                                         (char *) &pSMBr->hdr.Protocol); 
2941                         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",
2942                                 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)));
2943                         /* BB This field is actually two bytes in from start of
2944                            data block so we could do safety check that DataBlock
2945                            begins at address of pSMBr->NumberOfReferrals */
2946                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2947
2948                         /* BB Fix below so can return more than one referral */
2949                         if(*number_of_UNC_in_array > 1)
2950                                 *number_of_UNC_in_array = 1;
2951
2952                         /* get the length of the strings describing refs */
2953                         name_len = 0;
2954                         for(i=0;i<*number_of_UNC_in_array;i++) {
2955                                 /* make sure that DfsPathOffset not past end */
2956                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2957                                 if (offset > data_count) {
2958                                         /* if invalid referral, stop here and do 
2959                                         not try to copy any more */
2960                                         *number_of_UNC_in_array = i;
2961                                         break;
2962                                 } 
2963                                 temp = ((char *)referrals) + offset;
2964
2965                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2966                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
2967                                 } else {
2968                                         name_len += strnlen(temp,data_count);
2969                                 }
2970                                 referrals++;
2971                                 /* BB add check that referral pointer does not fall off end PDU */
2972                                 
2973                         }
2974                         /* BB add check for name_len bigger than bcc */
2975                         *targetUNCs = 
2976                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2977                         if(*targetUNCs == NULL) {
2978                                 rc = -ENOMEM;
2979                                 goto GetDFSRefExit;
2980                         }
2981                         /* copy the ref strings */
2982                         referrals =  
2983                             (struct dfs_referral_level_3 *) 
2984                                         (8 /* sizeof data hdr */ +
2985                                         data_offset + 
2986                                         (char *) &pSMBr->hdr.Protocol);
2987
2988                         for(i=0;i<*number_of_UNC_in_array;i++) {
2989                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
2990                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2991                                         cifs_strfromUCS_le(*targetUNCs,
2992                                                 (wchar_t *) temp, name_len, nls_codepage);
2993                                 } else {
2994                                         strncpy(*targetUNCs,temp,name_len);
2995                                 }
2996                                 /*  BB update target_uncs pointers */
2997                                 referrals++;
2998                         }
2999                         temp = *targetUNCs;
3000                         temp[name_len] = 0;
3001                 }
3002
3003         }
3004 GetDFSRefExit:
3005         if (pSMB)
3006                 cifs_buf_release(pSMB);
3007
3008         if (rc == -EAGAIN)
3009                 goto getDFSRetry;
3010
3011         return rc;
3012 }
3013
3014 int
3015 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
3016                struct kstatfs *FSData, const struct nls_table *nls_codepage)
3017 {
3018 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3019         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3020         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3021         FILE_SYSTEM_INFO *response_data;
3022         int rc = 0;
3023         int bytes_returned = 0;
3024         __u16 params, byte_count;
3025
3026         cFYI(1, ("In QFSInfo"));
3027 QFSInfoRetry:
3028         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3029                       (void **) &pSMBr);
3030         if (rc)
3031                 return rc;
3032
3033         params = 2;     /* level */
3034         pSMB->TotalDataCount = 0;
3035         pSMB->MaxParameterCount = cpu_to_le16(2);
3036         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3037         pSMB->MaxSetupCount = 0;
3038         pSMB->Reserved = 0;
3039         pSMB->Flags = 0;
3040         pSMB->Timeout = 0;
3041         pSMB->Reserved2 = 0;
3042         byte_count = params + 1 /* pad */ ;
3043         pSMB->TotalParameterCount = cpu_to_le16(params);
3044         pSMB->ParameterCount = pSMB->TotalParameterCount;
3045         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3046         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3047         pSMB->DataCount = 0;
3048         pSMB->DataOffset = 0;
3049         pSMB->SetupCount = 1;
3050         pSMB->Reserved3 = 0;
3051         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3052         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3053         pSMB->hdr.smb_buf_length += byte_count;
3054         pSMB->ByteCount = cpu_to_le16(byte_count);
3055
3056         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3057                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3058         if (rc) {
3059                 cERROR(1, ("Send error in QFSInfo = %d", rc));
3060         } else {                /* decode response */
3061                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3062
3063                 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3064                         rc = -EIO;      /* bad smb */
3065                 else {
3066                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3067                         cFYI(1,
3068                                 ("Decoding qfsinfo response.  BCC: %d  Offset %d",
3069                                 pSMBr->ByteCount, data_offset));
3070
3071                         response_data =
3072                             (FILE_SYSTEM_INFO
3073                              *) (((char *) &pSMBr->hdr.Protocol) +
3074                                  data_offset);
3075                         FSData->f_bsize =
3076                             le32_to_cpu(response_data->BytesPerSector) *
3077                             le32_to_cpu(response_data->
3078                                         SectorsPerAllocationUnit);
3079                         FSData->f_blocks =
3080                             le64_to_cpu(response_data->TotalAllocationUnits);
3081                         FSData->f_bfree = FSData->f_bavail =
3082                             le64_to_cpu(response_data->FreeAllocationUnits);
3083                         cFYI(1,
3084                              ("Blocks: %lld  Free: %lld Block size %ld",
3085                               (unsigned long long)FSData->f_blocks,
3086                               (unsigned long long)FSData->f_bfree,
3087                               FSData->f_bsize));
3088                 }
3089         }
3090         if (pSMB)
3091                 cifs_buf_release(pSMB);
3092
3093         if (rc == -EAGAIN)
3094                 goto QFSInfoRetry;
3095
3096         return rc;
3097 }
3098
3099 int
3100 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon,
3101                         const struct nls_table *nls_codepage)
3102 {
3103 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3104         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3105         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3106         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3107         int rc = 0;
3108         int bytes_returned = 0;
3109         __u16 params, byte_count;
3110
3111         cFYI(1, ("In QFSAttributeInfo"));
3112 QFSAttributeRetry:
3113         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3114                       (void **) &pSMBr);
3115         if (rc)
3116                 return rc;
3117
3118         params = 2;     /* level */
3119         pSMB->TotalDataCount = 0;
3120         pSMB->MaxParameterCount = cpu_to_le16(2);
3121         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3122         pSMB->MaxSetupCount = 0;
3123         pSMB->Reserved = 0;
3124         pSMB->Flags = 0;
3125         pSMB->Timeout = 0;
3126         pSMB->Reserved2 = 0;
3127         byte_count = params + 1 /* pad */ ;
3128         pSMB->TotalParameterCount = cpu_to_le16(params);
3129         pSMB->ParameterCount = pSMB->TotalParameterCount;
3130         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3131         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3132         pSMB->DataCount = 0;
3133         pSMB->DataOffset = 0;
3134         pSMB->SetupCount = 1;
3135         pSMB->Reserved3 = 0;
3136         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3137         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3138         pSMB->hdr.smb_buf_length += byte_count;
3139         pSMB->ByteCount = cpu_to_le16(byte_count);
3140
3141         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3142                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3143         if (rc) {
3144                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3145         } else {                /* decode response */
3146                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3147
3148                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3149                         rc = -EIO;      /* bad smb */
3150                 } else {
3151                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3152                         response_data =
3153                             (FILE_SYSTEM_ATTRIBUTE_INFO
3154                              *) (((char *) &pSMBr->hdr.Protocol) +
3155                                  data_offset);
3156                         memcpy(&tcon->fsAttrInfo, response_data,
3157                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3158                 }
3159         }
3160         if (pSMB)
3161                 cifs_buf_release(pSMB);
3162
3163         if (rc == -EAGAIN)
3164                 goto QFSAttributeRetry;
3165
3166         return rc;
3167 }
3168
3169 int
3170 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
3171                      const struct nls_table *nls_codepage)
3172 {
3173 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3174         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3175         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3176         FILE_SYSTEM_DEVICE_INFO *response_data;
3177         int rc = 0;
3178         int bytes_returned = 0;
3179         __u16 params, byte_count;
3180
3181         cFYI(1, ("In QFSDeviceInfo"));
3182 QFSDeviceRetry:
3183         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3184                       (void **) &pSMBr);
3185         if (rc)
3186                 return rc;
3187
3188         params = 2;     /* level */
3189         pSMB->TotalDataCount = 0;
3190         pSMB->MaxParameterCount = cpu_to_le16(2);
3191         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3192         pSMB->MaxSetupCount = 0;
3193         pSMB->Reserved = 0;
3194         pSMB->Flags = 0;
3195         pSMB->Timeout = 0;
3196         pSMB->Reserved2 = 0;
3197         byte_count = params + 1 /* pad */ ;
3198         pSMB->TotalParameterCount = cpu_to_le16(params);
3199         pSMB->ParameterCount = pSMB->TotalParameterCount;
3200         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3201         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3202
3203         pSMB->DataCount = 0;
3204         pSMB->DataOffset = 0;
3205         pSMB->SetupCount = 1;
3206         pSMB->Reserved3 = 0;
3207         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3208         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3209         pSMB->hdr.smb_buf_length += byte_count;
3210         pSMB->ByteCount = cpu_to_le16(byte_count);
3211
3212         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3213                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3214         if (rc) {
3215                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3216         } else {                /* decode response */
3217                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3218
3219                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3220                         rc = -EIO;      /* bad smb */
3221                 else {
3222                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3223                         response_data =
3224                             (FILE_SYSTEM_DEVICE_INFO
3225                              *) (((char *) &pSMBr->hdr.Protocol) +
3226                                  data_offset);
3227                         memcpy(&tcon->fsDevInfo, response_data,
3228                                sizeof (FILE_SYSTEM_DEVICE_INFO));
3229                 }
3230         }
3231         if (pSMB)
3232                 cifs_buf_release(pSMB);
3233
3234         if (rc == -EAGAIN)
3235                 goto QFSDeviceRetry;
3236
3237         return rc;
3238 }
3239
3240 int
3241 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
3242                    const struct nls_table *nls_codepage)
3243 {
3244 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
3245         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3246         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3247         FILE_SYSTEM_UNIX_INFO *response_data;
3248         int rc = 0;
3249         int bytes_returned = 0;
3250         __u16 params, byte_count;
3251
3252         cFYI(1, ("In QFSUnixInfo"));
3253 QFSUnixRetry:
3254         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3255                       (void **) &pSMBr);
3256         if (rc)
3257                 return rc;
3258
3259         params = 2;     /* level */
3260         pSMB->TotalDataCount = 0;
3261         pSMB->DataCount = 0;
3262         pSMB->DataOffset = 0;
3263         pSMB->MaxParameterCount = cpu_to_le16(2);
3264         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3265         pSMB->MaxSetupCount = 0;
3266         pSMB->Reserved = 0;
3267         pSMB->Flags = 0;
3268         pSMB->Timeout = 0;
3269         pSMB->Reserved2 = 0;
3270         byte_count = params + 1 /* pad */ ;
3271         pSMB->ParameterCount = cpu_to_le16(params);
3272         pSMB->TotalParameterCount = pSMB->ParameterCount;
3273         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3274         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3275         pSMB->SetupCount = 1;
3276         pSMB->Reserved3 = 0;
3277         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3278         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3279         pSMB->hdr.smb_buf_length += byte_count;
3280         pSMB->ByteCount = cpu_to_le16(byte_count);
3281
3282         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3283                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3284         if (rc) {
3285                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3286         } else {                /* decode response */
3287                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3288
3289                 if (rc || (pSMBr->ByteCount < 13)) {
3290                         rc = -EIO;      /* bad smb */
3291                 } else {
3292                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3293                         response_data =
3294                             (FILE_SYSTEM_UNIX_INFO
3295                              *) (((char *) &pSMBr->hdr.Protocol) +
3296                                  data_offset);
3297                         memcpy(&tcon->fsUnixInfo, response_data,
3298                                sizeof (FILE_SYSTEM_UNIX_INFO));
3299                 }
3300         }
3301         if (pSMB)
3302                 cifs_buf_release(pSMB);
3303
3304         if (rc == -EAGAIN)
3305                 goto QFSUnixRetry;
3306
3307
3308         return rc;
3309 }
3310
3311 /* We can not use write of zero bytes trick to 
3312    set file size due to need for large file support.  Also note that 
3313    this SetPathInfo is preferred to SetFileInfo based method in next 
3314    routine which is only needed to work around a sharing violation bug
3315    in Samba which this routine can run into */
3316
3317 int
3318 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3319               __u64 size, int SetAllocation, const struct nls_table *nls_codepage)
3320 {
3321         struct smb_com_transaction2_spi_req *pSMB = NULL;
3322         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3323         struct file_end_of_file_info *parm_data;
3324         int name_len;
3325         int rc = 0;
3326         int bytes_returned = 0;
3327         __u16 params, byte_count, data_count, param_offset, offset;
3328
3329         cFYI(1, ("In SetEOF"));
3330 SetEOFRetry:
3331         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3332                       (void **) &pSMBr);
3333         if (rc)
3334                 return rc;
3335
3336         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3337                 name_len =
3338                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
3339                                   /* find define for this maxpathcomponent */
3340                                   , nls_codepage);
3341                 name_len++;     /* trailing null */
3342                 name_len *= 2;
3343         } else {                /* BB improve the check for buffer overruns BB */
3344                 name_len = strnlen(fileName, PATH_MAX);
3345                 name_len++;     /* trailing null */
3346                 strncpy(pSMB->FileName, fileName, name_len);
3347         }
3348         params = 6 + name_len;
3349         data_count = sizeof (struct file_end_of_file_info);
3350         pSMB->MaxParameterCount = cpu_to_le16(2);
3351         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3352         pSMB->MaxSetupCount = 0;
3353         pSMB->Reserved = 0;
3354         pSMB->Flags = 0;
3355         pSMB->Timeout = 0;
3356         pSMB->Reserved2 = 0;
3357         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3358                                      InformationLevel) - 4;
3359         offset = param_offset + params;
3360         if(SetAllocation) {
3361                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3362                     pSMB->InformationLevel =
3363                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3364                 else
3365                     pSMB->InformationLevel =
3366                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3367         } else /* Set File Size */  {    
3368             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3369                     pSMB->InformationLevel =
3370                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3371             else
3372                     pSMB->InformationLevel =
3373                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3374         }
3375
3376         parm_data =
3377             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3378                                        offset);
3379         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3380         pSMB->DataOffset = cpu_to_le16(offset);
3381         pSMB->SetupCount = 1;
3382         pSMB->Reserved3 = 0;
3383         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3384         byte_count = 3 /* pad */  + params + data_count;
3385         pSMB->DataCount = cpu_to_le16(data_count);
3386         pSMB->TotalDataCount = pSMB->DataCount;
3387         pSMB->ParameterCount = cpu_to_le16(params);
3388         pSMB->TotalParameterCount = pSMB->ParameterCount;
3389         pSMB->Reserved4 = 0;
3390         pSMB->hdr.smb_buf_length += byte_count;
3391         parm_data->FileSize = cpu_to_le64(size);
3392         pSMB->ByteCount = cpu_to_le16(byte_count);
3393         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3394                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3395         if (rc) {
3396                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3397         }
3398
3399         if (pSMB)
3400                 cifs_buf_release(pSMB);
3401
3402         if (rc == -EAGAIN)
3403                 goto SetEOFRetry;
3404
3405         return rc;
3406 }
3407
3408 int
3409 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
3410                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
3411 {
3412         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
3413         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3414         char *data_offset;
3415         struct file_end_of_file_info *parm_data;
3416         int rc = 0;
3417         int bytes_returned = 0;
3418         __u16 params, param_offset, offset, byte_count, count;
3419
3420         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3421                         (long long)size));
3422         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3423                       (void **) &pSMBr);
3424         if (rc)
3425                 return rc;
3426
3427         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3428         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3429     
3430         params = 6;
3431         pSMB->MaxSetupCount = 0;
3432         pSMB->Reserved = 0;
3433         pSMB->Flags = 0;
3434         pSMB->Timeout = 0;
3435         pSMB->Reserved2 = 0;
3436         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3437         offset = param_offset + params;
3438
3439         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
3440
3441         count = sizeof(struct file_end_of_file_info);
3442         pSMB->MaxParameterCount = cpu_to_le16(2);
3443         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3444         pSMB->SetupCount = 1;
3445         pSMB->Reserved3 = 0;
3446         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3447         byte_count = 3 /* pad */  + params + count;
3448         pSMB->DataCount = cpu_to_le16(count);
3449         pSMB->ParameterCount = cpu_to_le16(params);
3450         pSMB->TotalDataCount = pSMB->DataCount;
3451         pSMB->TotalParameterCount = pSMB->ParameterCount;
3452         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3453         parm_data =
3454                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3455                         offset);
3456         pSMB->DataOffset = cpu_to_le16(offset);
3457         parm_data->FileSize = cpu_to_le64(size);
3458         pSMB->Fid = fid;
3459         if(SetAllocation) {
3460                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3461                         pSMB->InformationLevel =
3462                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3463                 else
3464                         pSMB->InformationLevel =
3465                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3466         } else /* Set File Size */  {    
3467             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3468                     pSMB->InformationLevel =
3469                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3470             else
3471                     pSMB->InformationLevel =
3472                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3473         }
3474         pSMB->Reserved4 = 0;
3475         pSMB->hdr.smb_buf_length += byte_count;
3476         pSMB->ByteCount = cpu_to_le16(byte_count);
3477         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3478                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3479         if (rc) {
3480                 cFYI(1,
3481                      ("Send error in SetFileInfo (SetFileSize) = %d",
3482                       rc));
3483         }
3484
3485         if (pSMB)
3486                 cifs_buf_release(pSMB);
3487
3488         /* Note: On -EAGAIN error only caller can retry on handle based calls 
3489                 since file handle passed in no longer valid */
3490
3491         return rc;
3492 }
3493
3494 int
3495 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3496                 const FILE_BASIC_INFO * data, 
3497                 const struct nls_table *nls_codepage)
3498 {
3499         TRANSACTION2_SPI_REQ *pSMB = NULL;
3500         TRANSACTION2_SPI_RSP *pSMBr = NULL;
3501         int name_len;
3502         int rc = 0;
3503         int bytes_returned = 0;
3504         char *data_offset;
3505         __u16 params, param_offset, offset, byte_count, count;
3506
3507         cFYI(1, ("In SetTimes"));
3508
3509 SetTimesRetry:
3510         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3511                       (void **) &pSMBr);
3512         if (rc)
3513                 return rc;
3514
3515         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3516                 name_len =
3517                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
3518                                   /* find define for this maxpathcomponent */
3519                                   , nls_codepage);
3520                 name_len++;     /* trailing null */
3521                 name_len *= 2;
3522         } else {                /* BB improve the check for buffer overruns BB */
3523                 name_len = strnlen(fileName, PATH_MAX);
3524                 name_len++;     /* trailing null */
3525                 strncpy(pSMB->FileName, fileName, name_len);
3526         }
3527
3528         params = 6 + name_len;
3529         count = sizeof (FILE_BASIC_INFO);
3530         pSMB->MaxParameterCount = cpu_to_le16(2);
3531         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3532         pSMB->MaxSetupCount = 0;
3533         pSMB->Reserved = 0;
3534         pSMB->Flags = 0;
3535         pSMB->Timeout = 0;
3536         pSMB->Reserved2 = 0;
3537         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3538                                      InformationLevel) - 4;
3539         offset = param_offset + params;
3540         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3541         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3542         pSMB->DataOffset = cpu_to_le16(offset);
3543         pSMB->SetupCount = 1;
3544         pSMB->Reserved3 = 0;
3545         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3546         byte_count = 3 /* pad */  + params + count;
3547
3548         pSMB->DataCount = cpu_to_le16(count);
3549         pSMB->ParameterCount = cpu_to_le16(params);
3550         pSMB->TotalDataCount = pSMB->DataCount;
3551         pSMB->TotalParameterCount = pSMB->ParameterCount;
3552         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3553                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3554         else
3555                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3556         pSMB->Reserved4 = 0;
3557         pSMB->hdr.smb_buf_length += byte_count;
3558         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3559         pSMB->ByteCount = cpu_to_le16(byte_count);
3560         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3561                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3562         if (rc) {
3563                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3564         }
3565
3566         if (pSMB)
3567                 cifs_buf_release(pSMB);
3568
3569         if (rc == -EAGAIN)
3570                 goto SetTimesRetry;
3571
3572         return rc;
3573 }
3574
3575 int
3576 CIFSSMBSetTimesLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3577                 FILE_INFO_STANDARD * data, const struct nls_table *nls_codepage)
3578 {
3579         TRANSACTION2_SPI_REQ *pSMB = NULL;
3580         TRANSACTION2_SPI_RSP *pSMBr = NULL;
3581         int name_len;
3582         int rc = 0;
3583         int bytes_returned = 0;
3584         char *data_offset;
3585         __u16 params, param_offset, count, offset, byte_count;
3586
3587         cFYI(1, ("In SetTimesLegacy"));
3588
3589 SetTimesRetryLegacy:
3590         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3591                       (void **) &pSMBr);
3592         if (rc)
3593                 return rc;
3594
3595         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3596                 name_len =
3597                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
3598                                   /* find define for this maxpathcomponent */
3599                                   , nls_codepage);
3600                 name_len++;     /* trailing null */
3601                 name_len *= 2;
3602         } else {                /* BB improve the check for buffer overruns BB */
3603                 name_len = strnlen(fileName, PATH_MAX);
3604                 name_len++;     /* trailing null */
3605                 strncpy(pSMB->FileName, fileName, name_len);
3606         }
3607 /* BB fixme - we have to map to FILE_STANDARD_INFO (level 1 info
3608         in parent function, from the better and ususal FILE_BASIC_INFO */
3609         params = 6 + name_len;
3610         count = sizeof (FILE_INFO_STANDARD);
3611         pSMB->MaxParameterCount = cpu_to_le16(2);
3612         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3613         pSMB->MaxSetupCount = 0;
3614         pSMB->Reserved = 0;
3615         pSMB->Flags = 0;
3616         pSMB->Timeout = 0;
3617         pSMB->Reserved2 = 0;
3618         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3619                                      InformationLevel) - 4;
3620         offset = param_offset + params;
3621         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3622         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3623         pSMB->DataOffset = cpu_to_le16(offset);
3624         pSMB->SetupCount = 1;
3625         pSMB->Reserved3 = 0;
3626         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3627         byte_count = 3 /* pad */  + params + count;
3628
3629         pSMB->DataCount = cpu_to_le16(count);
3630         pSMB->ParameterCount = cpu_to_le16(params);
3631         pSMB->TotalDataCount = pSMB->DataCount;
3632         pSMB->TotalParameterCount = pSMB->ParameterCount;
3633         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3634         pSMB->Reserved4 = 0;
3635         pSMB->hdr.smb_buf_length += byte_count;
3636         memcpy(data_offset, data, sizeof (FILE_INFO_STANDARD));
3637         pSMB->ByteCount = cpu_to_le16(byte_count);
3638         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3639                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3640         if (rc) {
3641                 cFYI(1, ("SetPathInfo (times legacy) returned %d", rc));
3642         }
3643
3644         if (pSMB)
3645                 cifs_buf_release(pSMB);
3646
3647         if (rc == -EAGAIN)
3648                 goto SetTimesRetryLegacy;
3649
3650         return rc;
3651 }
3652
3653 int
3654 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
3655                     char *fileName, __u64 mode, __u64 uid, __u64 gid,
3656                     dev_t device, const struct nls_table *nls_codepage)
3657 {
3658         TRANSACTION2_SPI_REQ *pSMB = NULL;
3659         TRANSACTION2_SPI_RSP *pSMBr = NULL;
3660         int name_len;
3661         int rc = 0;
3662         int bytes_returned = 0;
3663         FILE_UNIX_BASIC_INFO *data_offset;
3664         __u16 params, param_offset, offset, count, byte_count;
3665
3666         cFYI(1, ("In SetUID/GID/Mode"));
3667 setPermsRetry:
3668         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3669                       (void **) &pSMBr);
3670         if (rc)
3671                 return rc;
3672
3673         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3674                 name_len =
3675                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
3676                                   /* find define for this maxpathcomponent */
3677                                   , nls_codepage);
3678                 name_len++;     /* trailing null */
3679                 name_len *= 2;
3680         } else {                /* BB improve the check for buffer overruns BB */
3681                 name_len = strnlen(fileName, PATH_MAX);
3682                 name_len++;     /* trailing null */
3683                 strncpy(pSMB->FileName, fileName, name_len);
3684         }
3685
3686         params = 6 + name_len;
3687         count = sizeof (FILE_UNIX_BASIC_INFO);
3688         pSMB->MaxParameterCount = cpu_to_le16(2);
3689         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3690         pSMB->MaxSetupCount = 0;
3691         pSMB->Reserved = 0;
3692         pSMB->Flags = 0;
3693         pSMB->Timeout = 0;
3694         pSMB->Reserved2 = 0;
3695         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3696                                      InformationLevel) - 4;
3697         offset = param_offset + params;
3698         data_offset =
3699             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3700                                       offset);
3701         memset(data_offset, 0, count);
3702         pSMB->DataOffset = cpu_to_le16(offset);
3703         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3704         pSMB->SetupCount = 1;
3705         pSMB->Reserved3 = 0;
3706         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3707         byte_count = 3 /* pad */  + params + count;
3708         pSMB->ParameterCount = cpu_to_le16(params);
3709         pSMB->DataCount = cpu_to_le16(count);
3710         pSMB->TotalParameterCount = pSMB->ParameterCount;
3711         pSMB->TotalDataCount = pSMB->DataCount;
3712         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3713         pSMB->Reserved4 = 0;
3714         pSMB->hdr.smb_buf_length += byte_count;
3715         data_offset->Uid = cpu_to_le64(uid);
3716         data_offset->Gid = cpu_to_le64(gid);
3717         /* better to leave device as zero when it is  */
3718         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3719         data_offset->DevMinor = cpu_to_le64(MINOR(device));
3720         data_offset->Permissions = cpu_to_le64(mode);
3721     
3722         if(S_ISREG(mode))
3723                 data_offset->Type = cpu_to_le32(UNIX_FILE);
3724         else if(S_ISDIR(mode))
3725                 data_offset->Type = cpu_to_le32(UNIX_DIR);
3726         else if(S_ISLNK(mode))
3727                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3728         else if(S_ISCHR(mode))
3729                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3730         else if(S_ISBLK(mode))
3731                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3732         else if(S_ISFIFO(mode))
3733                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
3734         else if(S_ISSOCK(mode))
3735                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3736
3737
3738         pSMB->ByteCount = cpu_to_le16(byte_count);
3739         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3740                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3741         if (rc) {
3742                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3743         }
3744
3745         if (pSMB)
3746                 cifs_buf_release(pSMB);
3747         if (rc == -EAGAIN)
3748                 goto setPermsRetry;
3749         return rc;
3750 }
3751
3752 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
3753                         const int notify_subdirs, const __u16 netfid,
3754                         __u32 filter, const struct nls_table *nls_codepage)
3755 {
3756         int rc = 0;
3757         struct smb_com_transaction_change_notify_req * pSMB = NULL;
3758         struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
3759         int bytes_returned;
3760
3761         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3762         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3763                       (void **) &pSMBr);
3764         if (rc)
3765                 return rc;
3766
3767         pSMB->TotalParameterCount = 0 ;
3768         pSMB->TotalDataCount = 0;
3769         pSMB->MaxParameterCount = cpu_to_le32(2);
3770         /* BB find exact data count max from sess structure BB */
3771         pSMB->MaxDataCount = 0; /* same in little endian or be */
3772         pSMB->MaxSetupCount = 4;
3773         pSMB->Reserved = 0;
3774         pSMB->ParameterOffset = 0;
3775         pSMB->DataCount = 0;
3776         pSMB->DataOffset = 0;
3777         pSMB->SetupCount = 4; /* single byte does not need le conversion */
3778         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
3779         pSMB->ParameterCount = pSMB->TotalParameterCount;
3780         if(notify_subdirs)
3781                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
3782         pSMB->Reserved2 = 0;
3783         pSMB->CompletionFilter = cpu_to_le32(filter);
3784         pSMB->Fid = netfid; /* file handle always le */
3785         pSMB->ByteCount = 0;
3786
3787         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3788                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
3789         if (rc) {
3790                 cFYI(1, ("Error in Notify = %d", rc));
3791         }
3792         if (pSMB)
3793                 cifs_buf_release(pSMB);
3794 /*              if (rc == -EAGAIN)
3795                         goto NotifyRetry; */
3796         return rc;      
3797 }
3798 #ifdef CONFIG_CIFS_XATTR
3799 ssize_t
3800 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3801                  const unsigned char *searchName,
3802                  char * EAData, size_t buf_size,
3803                  const struct nls_table *nls_codepage)
3804 {
3805                 /* BB assumes one setup word */
3806         TRANSACTION2_QPI_REQ *pSMB = NULL;
3807         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3808         int rc = 0;
3809         int bytes_returned;
3810         int name_len;
3811         struct fea * temp_fea;
3812         char * temp_ptr;
3813         __u16 params, byte_count;
3814
3815         cFYI(1, ("In Query All EAs path %s", searchName));
3816 QAllEAsRetry:
3817         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3818                       (void **) &pSMBr);
3819         if (rc)
3820                 return rc;
3821
3822         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3823                 name_len =
3824                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
3825                                   /* find define for this maxpathcomponent */
3826                                   , nls_codepage);
3827                 name_len++;     /* trailing null */
3828                 name_len *= 2;
3829         } else {        /* BB improve the check for buffer overruns BB */
3830                 name_len = strnlen(searchName, PATH_MAX);
3831                 name_len++;     /* trailing null */
3832                 strncpy(pSMB->FileName, searchName, name_len);
3833         }
3834
3835         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3836         pSMB->TotalDataCount = 0;
3837         pSMB->MaxParameterCount = cpu_to_le16(2);
3838         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3839         pSMB->MaxSetupCount = 0;
3840         pSMB->Reserved = 0;
3841         pSMB->Flags = 0;
3842         pSMB->Timeout = 0;
3843         pSMB->Reserved2 = 0;
3844         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3845         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3846         pSMB->DataCount = 0;
3847         pSMB->DataOffset = 0;
3848         pSMB->SetupCount = 1;
3849         pSMB->Reserved3 = 0;
3850         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3851         byte_count = params + 1 /* pad */ ;
3852         pSMB->TotalParameterCount = cpu_to_le16(params);
3853         pSMB->ParameterCount = pSMB->TotalParameterCount;
3854         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3855         pSMB->Reserved4 = 0;
3856         pSMB->hdr.smb_buf_length += byte_count;
3857         pSMB->ByteCount = cpu_to_le16(byte_count);
3858
3859         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3860                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3861         if (rc) {
3862                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
3863         } else {                /* decode response */
3864                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3865
3866                 /* BB also check enough total bytes returned */
3867                 /* BB we need to improve the validity checking
3868                 of these trans2 responses */
3869                 if (rc || (pSMBr->ByteCount < 4)) 
3870                         rc = -EIO;      /* bad smb */
3871            /* else if (pFindData){
3872                         memcpy((char *) pFindData,
3873                                (char *) &pSMBr->hdr.Protocol +
3874                                data_offset, kl);
3875                 }*/ else {
3876                         /* check that length of list is not more than bcc */
3877                         /* check that each entry does not go beyond length
3878                            of list */
3879                         /* check that each element of each entry does not
3880                            go beyond end of list */
3881                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3882                         struct fealist * ea_response_data;
3883                         rc = 0;
3884                         /* validate_trans2_offsets() */
3885                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
3886                         ea_response_data = (struct fealist *)
3887                                 (((char *) &pSMBr->hdr.Protocol) +
3888                                 data_offset);
3889                         name_len = le32_to_cpu(ea_response_data->list_len);
3890                         cFYI(1,("ea length %d", name_len));
3891                         if(name_len <= 8) {
3892                         /* returned EA size zeroed at top of function */
3893                                 cFYI(1,("empty EA list returned from server"));
3894                         } else {
3895                                 /* account for ea list len */
3896                                 name_len -= 4;
3897                                 temp_fea = ea_response_data->list;
3898                                 temp_ptr = (char *)temp_fea;
3899                                 while(name_len > 0) {
3900                                         __u16 value_len;
3901                                         name_len -= 4;
3902                                         temp_ptr += 4;
3903                                         rc += temp_fea->name_len;
3904                                 /* account for prefix user. and trailing null */
3905                                         rc = rc + 5 + 1; 
3906                                         if(rc<(int)buf_size) {
3907                                                 memcpy(EAData,"user.",5);
3908                                                 EAData+=5;
3909                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
3910                                                 EAData+=temp_fea->name_len;
3911                                                 /* null terminate name */
3912                                                 *EAData = 0;
3913                                                 EAData = EAData + 1;
3914                                         } else if(buf_size == 0) {
3915                                                 /* skip copy - calc size only */
3916                                         } else {
3917                                                 /* stop before overrun buffer */
3918                                                 rc = -ERANGE;
3919                                                 break;
3920                                         }
3921                                         name_len -= temp_fea->name_len;
3922                                         temp_ptr += temp_fea->name_len;
3923                                         /* account for trailing null */
3924                                         name_len--;
3925                                         temp_ptr++;
3926                                         value_len = le16_to_cpu(temp_fea->value_len);
3927                                         name_len -= value_len;
3928                                         temp_ptr += value_len;
3929                                         /* BB check that temp_ptr is still within smb BB*/
3930                                 /* no trailing null to account for in value len */
3931                                         /* go on to next EA */
3932                                         temp_fea = (struct fea *)temp_ptr;
3933                                 }
3934                         }
3935                 }
3936         }
3937         if (pSMB)
3938                 cifs_buf_release(pSMB);
3939         if (rc == -EAGAIN)
3940                 goto QAllEAsRetry;
3941
3942         return (ssize_t)rc;
3943 }
3944
3945 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
3946                 const unsigned char * searchName,const unsigned char * ea_name,
3947                 unsigned char * ea_value, size_t buf_size, 
3948                 const struct nls_table *nls_codepage)
3949 {
3950         TRANSACTION2_QPI_REQ *pSMB = NULL;
3951         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3952         int rc = 0;
3953         int bytes_returned;
3954         int name_len;
3955         struct fea * temp_fea;
3956         char * temp_ptr;
3957         __u16 params, byte_count;
3958
3959         cFYI(1, ("In Query EA path %s", searchName));
3960 QEARetry:
3961         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3962                       (void **) &pSMBr);
3963         if (rc)
3964                 return rc;
3965
3966         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3967                 name_len =
3968                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
3969                                   /* find define for this maxpathcomponent */
3970                                   , nls_codepage);
3971                 name_len++;     /* trailing null */
3972                 name_len *= 2;
3973         } else {        /* BB improve the check for buffer overruns BB */
3974                 name_len = strnlen(searchName, PATH_MAX);
3975                 name_len++;     /* trailing null */
3976                 strncpy(pSMB->FileName, searchName, name_len);
3977         }
3978
3979         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3980         pSMB->TotalDataCount = 0;
3981         pSMB->MaxParameterCount = cpu_to_le16(2);
3982         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3983         pSMB->MaxSetupCount = 0;
3984         pSMB->Reserved = 0;
3985         pSMB->Flags = 0;
3986         pSMB->Timeout = 0;
3987         pSMB->Reserved2 = 0;
3988         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3989         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3990         pSMB->DataCount = 0;
3991         pSMB->DataOffset = 0;
3992         pSMB->SetupCount = 1;
3993         pSMB->Reserved3 = 0;
3994         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3995         byte_count = params + 1 /* pad */ ;
3996         pSMB->TotalParameterCount = cpu_to_le16(params);
3997         pSMB->ParameterCount = pSMB->TotalParameterCount;
3998         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3999         pSMB->Reserved4 = 0;
4000         pSMB->hdr.smb_buf_length += byte_count;
4001         pSMB->ByteCount = cpu_to_le16(byte_count);
4002
4003         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4004                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4005         if (rc) {
4006                 cFYI(1, ("Send error in Query EA = %d", rc));
4007         } else {                /* decode response */
4008                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4009
4010                 /* BB also check enough total bytes returned */
4011                 /* BB we need to improve the validity checking
4012                 of these trans2 responses */
4013                 if (rc || (pSMBr->ByteCount < 4)) 
4014                         rc = -EIO;      /* bad smb */
4015            /* else if (pFindData){
4016                         memcpy((char *) pFindData,
4017                                (char *) &pSMBr->hdr.Protocol +
4018                                data_offset, kl);
4019                 }*/ else {
4020                         /* check that length of list is not more than bcc */
4021                         /* check that each entry does not go beyond length
4022                            of list */
4023                         /* check that each element of each entry does not
4024                            go beyond end of list */
4025                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4026                         struct fealist * ea_response_data;
4027                         rc = -ENODATA;
4028                         /* validate_trans2_offsets() */
4029                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4030                         ea_response_data = (struct fealist *)
4031                                 (((char *) &pSMBr->hdr.Protocol) +
4032                                 data_offset);
4033                         name_len = le32_to_cpu(ea_response_data->list_len);
4034                         cFYI(1,("ea length %d", name_len));
4035                         if(name_len <= 8) {
4036                         /* returned EA size zeroed at top of function */
4037                                 cFYI(1,("empty EA list returned from server"));
4038                         } else {
4039                                 /* account for ea list len */
4040                                 name_len -= 4;
4041                                 temp_fea = ea_response_data->list;
4042                                 temp_ptr = (char *)temp_fea;
4043                                 /* loop through checking if we have a matching
4044                                 name and then return the associated value */
4045                                 while(name_len > 0) {
4046                                         __u16 value_len;
4047                                         name_len -= 4;
4048                                         temp_ptr += 4;
4049                                         value_len = le16_to_cpu(temp_fea->value_len);
4050                                 /* BB validate that value_len falls within SMB, 
4051                                 even though maximum for name_len is 255 */ 
4052                                         if(memcmp(temp_fea->name,ea_name,
4053                                                   temp_fea->name_len) == 0) {
4054                                                 /* found a match */
4055                                                 rc = value_len;
4056                                 /* account for prefix user. and trailing null */
4057                                                 if(rc<=(int)buf_size) {
4058                                                         memcpy(ea_value,
4059                                                                 temp_fea->name+temp_fea->name_len+1,
4060                                                                 rc);
4061                                                         /* ea values, unlike ea names,
4062                                                         are not null terminated */
4063                                                 } else if(buf_size == 0) {
4064                                                 /* skip copy - calc size only */
4065                                                 } else {
4066                                                         /* stop before overrun buffer */
4067                                                         rc = -ERANGE;
4068                                                 }
4069                                                 break;
4070                                         }
4071                                         name_len -= temp_fea->name_len;
4072                                         temp_ptr += temp_fea->name_len;
4073                                         /* account for trailing null */
4074                                         name_len--;
4075                                         temp_ptr++;
4076                                         name_len -= value_len;
4077                                         temp_ptr += value_len;
4078                                 /* no trailing null to account for in value len */
4079                                         /* go on to next EA */
4080                                         temp_fea = (struct fea *)temp_ptr;
4081                                 }
4082                         } 
4083                 }
4084         }
4085         if (pSMB)
4086                 cifs_buf_release(pSMB);
4087         if (rc == -EAGAIN)
4088                 goto QEARetry;
4089
4090         return (ssize_t)rc;
4091 }
4092
4093 int
4094 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4095                 const char * ea_name, const void * ea_value, 
4096                 const __u16 ea_value_len, const struct nls_table *nls_codepage)
4097 {
4098         struct smb_com_transaction2_spi_req *pSMB = NULL;
4099         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4100         struct fealist *parm_data;
4101         int name_len;
4102         int rc = 0;
4103         int bytes_returned = 0;
4104         __u16 params, param_offset, byte_count, offset, count;
4105
4106         cFYI(1, ("In SetEA"));
4107 SetEARetry:
4108         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4109                       (void **) &pSMBr);
4110         if (rc)
4111                 return rc;
4112
4113         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4114                 name_len =
4115                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
4116                                   /* find define for this maxpathcomponent */
4117                                   , nls_codepage);
4118                 name_len++;     /* trailing null */
4119                 name_len *= 2;
4120         } else {                /* BB improve the check for buffer overruns BB */
4121                 name_len = strnlen(fileName, PATH_MAX);
4122                 name_len++;     /* trailing null */
4123                 strncpy(pSMB->FileName, fileName, name_len);
4124         }
4125
4126         params = 6 + name_len;
4127
4128         /* done calculating parms using name_len of file name,
4129         now use name_len to calculate length of ea name
4130         we are going to create in the inode xattrs */
4131         if(ea_name == NULL)
4132                 name_len = 0;
4133         else
4134                 name_len = strnlen(ea_name,255);
4135
4136         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4137         pSMB->MaxParameterCount = cpu_to_le16(2);
4138         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4139         pSMB->MaxSetupCount = 0;
4140         pSMB->Reserved = 0;
4141         pSMB->Flags = 0;
4142         pSMB->Timeout = 0;
4143         pSMB->Reserved2 = 0;
4144         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4145                                      InformationLevel) - 4;
4146         offset = param_offset + params;
4147         pSMB->InformationLevel =
4148                 cpu_to_le16(SMB_SET_FILE_EA);
4149
4150         parm_data =
4151                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4152                                        offset);
4153         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4154         pSMB->DataOffset = cpu_to_le16(offset);
4155         pSMB->SetupCount = 1;
4156         pSMB->Reserved3 = 0;
4157         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4158         byte_count = 3 /* pad */  + params + count;
4159         pSMB->DataCount = cpu_to_le16(count);
4160         parm_data->list_len = cpu_to_le32(count);
4161         parm_data->list[0].EA_flags = 0;
4162         /* we checked above that name len is less than 255 */
4163         parm_data->list[0].name_len = (__u8)name_len;;
4164         /* EA names are always ASCII */
4165         strncpy(parm_data->list[0].name,ea_name,name_len);
4166         parm_data->list[0].name[name_len] = 0;
4167         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4168         /* caller ensures that ea_value_len is less than 64K but
4169         we need to ensure that it fits within the smb */
4170
4171         /*BB add length check that it would fit in negotiated SMB buffer size BB */
4172         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4173         if(ea_value_len)
4174                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4175
4176         pSMB->TotalDataCount = pSMB->DataCount;
4177         pSMB->ParameterCount = cpu_to_le16(params);
4178         pSMB->TotalParameterCount = pSMB->ParameterCount;
4179         pSMB->Reserved4 = 0;
4180         pSMB->hdr.smb_buf_length += byte_count;
4181         pSMB->ByteCount = cpu_to_le16(byte_count);
4182         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4183                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4184         if (rc) {
4185                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4186         }
4187
4188         if (pSMB)
4189                 cifs_buf_release(pSMB);
4190
4191         if (rc == -EAGAIN)
4192                 goto SetEARetry;
4193
4194         return rc;
4195 }
4196
4197 #endif