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