[CIFS] Fix missing entries in search results when very long file names and
[safe/jmp/linux-2.6] / 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 | SECMODE_SIGN_REQUIRED);
419                 } else if(sign_CIFS_PDUs == 1) {
420                         if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
421                                 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
422                 }
423                                 
424         }
425         if (pSMB)
426                 cifs_buf_release(pSMB);
427         return rc;
428 }
429
430 int
431 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
432 {
433         struct smb_hdr *smb_buffer;
434         struct smb_hdr *smb_buffer_response; /* BB removeme BB */
435         int rc = 0;
436         int length;
437
438         cFYI(1, ("In tree disconnect"));
439         /*
440          *  If last user of the connection and
441          *  connection alive - disconnect it
442          *  If this is the last connection on the server session disconnect it
443          *  (and inside session disconnect we should check if tcp socket needs 
444          *  to be freed and kernel thread woken up).
445          */
446         if (tcon)
447                 down(&tcon->tconSem);
448         else
449                 return -EIO;
450
451         atomic_dec(&tcon->useCount);
452         if (atomic_read(&tcon->useCount) > 0) {
453                 up(&tcon->tconSem);
454                 return -EBUSY;
455         }
456
457         /* No need to return error on this operation if tid invalidated and 
458         closed on server already e.g. due to tcp session crashing */
459         if(tcon->tidStatus == CifsNeedReconnect) {
460                 up(&tcon->tconSem);
461                 return 0;  
462         }
463
464         if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {    
465                 up(&tcon->tconSem);
466                 return -EIO;
467         }
468         rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 
469                             (void **)&smb_buffer);
470         if (rc) {
471                 up(&tcon->tconSem);
472                 return rc;
473         } else {
474                 smb_buffer_response = smb_buffer; /* BB removeme BB */
475         }
476         rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
477                          &length, 0);
478         if (rc)
479                 cFYI(1, ("Tree disconnect failed %d", rc));
480
481         if (smb_buffer)
482                 cifs_small_buf_release(smb_buffer);
483         up(&tcon->tconSem);
484
485         /* No need to return error on this operation if tid invalidated and 
486         closed on server already e.g. due to tcp session crashing */
487         if (rc == -EAGAIN)
488                 rc = 0;
489
490         return rc;
491 }
492
493 int
494 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
495 {
496         struct smb_hdr *smb_buffer_response;
497         LOGOFF_ANDX_REQ *pSMB;
498         int rc = 0;
499         int length;
500
501         cFYI(1, ("In SMBLogoff for session disconnect"));
502         if (ses)
503                 down(&ses->sesSem);
504         else
505                 return -EIO;
506
507         atomic_dec(&ses->inUse);
508         if (atomic_read(&ses->inUse) > 0) {
509                 up(&ses->sesSem);
510                 return -EBUSY;
511         }
512         rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
513         if (rc) {
514                 up(&ses->sesSem);
515                 return rc;
516         }
517
518         smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
519         
520         if(ses->server) {
521                 if(ses->server->secMode & 
522                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
523                         pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
524         }
525
526         pSMB->hdr.Uid = ses->Suid;
527
528         pSMB->AndXCommand = 0xFF;
529         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
530                          smb_buffer_response, &length, 0);
531         if (ses->server) {
532                 atomic_dec(&ses->server->socketUseCount);
533                 if (atomic_read(&ses->server->socketUseCount) == 0) {
534                         spin_lock(&GlobalMid_Lock);
535                         ses->server->tcpStatus = CifsExiting;
536                         spin_unlock(&GlobalMid_Lock);
537                         rc = -ESHUTDOWN;
538                 }
539         }
540         if (pSMB)
541                 cifs_small_buf_release(pSMB);
542         up(&ses->sesSem);
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         if (pSMB)
1800                 cifs_buf_release(pSMB);
1801
1802         /* Note: On -EAGAIN error only caller can retry on handle based calls
1803                 since file handle passed in no longer valid */
1804
1805         return rc;
1806 }
1807
1808 #ifdef CONFIG_CIFS_POSIX
1809
1810 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1811 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1812 {
1813         /* u8 cifs fields do not need le conversion */
1814         ace->e_perm = (__u16)cifs_ace->cifs_e_perm; 
1815         ace->e_tag  = (__u16)cifs_ace->cifs_e_tag;
1816         ace->e_id   = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1817         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1818
1819         return;
1820 }
1821
1822 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
1823 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1824                                 const int acl_type,const int size_of_data_area)
1825 {
1826         int size =  0;
1827         int i;
1828         __u16 count;
1829         struct cifs_posix_ace * pACE;
1830         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1831         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1832
1833         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1834                 return -EOPNOTSUPP;
1835
1836         if(acl_type & ACL_TYPE_ACCESS) {
1837                 count = le16_to_cpu(cifs_acl->access_entry_count);
1838                 pACE = &cifs_acl->ace_array[0];
1839                 size = sizeof(struct cifs_posix_acl);
1840                 size += sizeof(struct cifs_posix_ace) * count;
1841                 /* check if we would go beyond end of SMB */
1842                 if(size_of_data_area < size) {
1843                         cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
1844                         return -EINVAL;
1845                 }
1846         } else if(acl_type & ACL_TYPE_DEFAULT) {
1847                 count = le16_to_cpu(cifs_acl->access_entry_count);
1848                 size = sizeof(struct cifs_posix_acl);
1849                 size += sizeof(struct cifs_posix_ace) * count;
1850 /* skip past access ACEs to get to default ACEs */
1851                 pACE = &cifs_acl->ace_array[count];
1852                 count = le16_to_cpu(cifs_acl->default_entry_count);
1853                 size += sizeof(struct cifs_posix_ace) * count;
1854                 /* check if we would go beyond end of SMB */
1855                 if(size_of_data_area < size)
1856                         return -EINVAL;
1857         } else {
1858                 /* illegal type */
1859                 return -EINVAL;
1860         }
1861
1862         size = posix_acl_xattr_size(count);
1863         if((buflen == 0) || (local_acl == NULL)) {
1864                 /* used to query ACL EA size */                         
1865         } else if(size > buflen) {
1866                 return -ERANGE;
1867         } else /* buffer big enough */ {
1868                 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
1869                 for(i = 0;i < count ;i++) {
1870                         cifs_convert_ace(&local_acl->a_entries[i],pACE);
1871                         pACE ++;
1872                 }
1873         }
1874         return size;
1875 }
1876
1877 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
1878                         const posix_acl_xattr_entry * local_ace)
1879 {
1880         __u16 rc = 0; /* 0 = ACL converted ok */
1881
1882         cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
1883         cifs_ace->cifs_e_tag =  (__u8)cpu_to_le16(local_ace->e_tag);
1884         /* BB is there a better way to handle the large uid? */
1885         if(local_ace->e_id == -1) {
1886         /* Probably no need to le convert -1 on any arch but can not hurt */
1887                 cifs_ace->cifs_uid = cpu_to_le64(-1);
1888         } else 
1889                 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
1890         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
1891         return rc;
1892 }
1893
1894 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
1895 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
1896                 const int acl_type)
1897 {
1898         __u16 rc = 0;
1899         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
1900         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
1901         int count;
1902         int i;
1903
1904         if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1905                 return 0;
1906
1907         count = posix_acl_xattr_count((size_t)buflen);
1908         cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
1909                 count,buflen,local_acl->a_version));
1910         if(local_acl->a_version != 2) {
1911                 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
1912                 return 0;
1913         }
1914         cifs_acl->version = cpu_to_le16(1);
1915         if(acl_type == ACL_TYPE_ACCESS) 
1916                 cifs_acl->access_entry_count = count;
1917         else if(acl_type == ACL_TYPE_DEFAULT)
1918                 cifs_acl->default_entry_count = count;
1919         else {
1920                 cFYI(1,("unknown ACL type %d",acl_type));
1921                 return 0;
1922         }
1923         for(i=0;i<count;i++) {
1924                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
1925                                         &local_acl->a_entries[i]);
1926                 if(rc != 0) {
1927                         /* ACE not converted */
1928                         break;
1929                 }
1930         }
1931         if(rc == 0) {
1932                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
1933                 rc += sizeof(struct cifs_posix_acl);
1934                 /* BB add check to make sure ACL does not overflow SMB */
1935         }
1936         return rc;
1937 }
1938
1939 int
1940 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
1941                         const unsigned char *searchName,
1942                         char *acl_inf, const int buflen, const int acl_type,
1943                         const struct nls_table *nls_codepage, int remap)
1944 {
1945 /* SMB_QUERY_POSIX_ACL */
1946         TRANSACTION2_QPI_REQ *pSMB = NULL;
1947         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1948         int rc = 0;
1949         int bytes_returned;
1950         int name_len;
1951         __u16 params, byte_count;
1952                                                                                                                                              
1953         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
1954
1955 queryAclRetry:
1956         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1957                 (void **) &pSMBr);
1958         if (rc)
1959                 return rc;
1960                                                                                                                                              
1961         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1962                 name_len =
1963                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
1964                                          PATH_MAX, nls_codepage, remap);
1965                 name_len++;     /* trailing null */
1966                 name_len *= 2;
1967                 pSMB->FileName[name_len] = 0;
1968                 pSMB->FileName[name_len+1] = 0;
1969         } else {                /* BB improve the check for buffer overruns BB */
1970                 name_len = strnlen(searchName, PATH_MAX);
1971                 name_len++;     /* trailing null */
1972                 strncpy(pSMB->FileName, searchName, name_len);
1973         }
1974
1975         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1976         pSMB->TotalDataCount = 0;
1977         pSMB->MaxParameterCount = cpu_to_le16(2);
1978         /* BB find exact max data count below from sess structure BB */
1979         pSMB->MaxDataCount = cpu_to_le16(4000);
1980         pSMB->MaxSetupCount = 0;
1981         pSMB->Reserved = 0;
1982         pSMB->Flags = 0;
1983         pSMB->Timeout = 0;
1984         pSMB->Reserved2 = 0;
1985         pSMB->ParameterOffset = cpu_to_le16(
1986                 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1987         pSMB->DataCount = 0;
1988         pSMB->DataOffset = 0;
1989         pSMB->SetupCount = 1;
1990         pSMB->Reserved3 = 0;
1991         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1992         byte_count = params + 1 /* pad */ ;
1993         pSMB->TotalParameterCount = cpu_to_le16(params);
1994         pSMB->ParameterCount = pSMB->TotalParameterCount;
1995         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
1996         pSMB->Reserved4 = 0;
1997         pSMB->hdr.smb_buf_length += byte_count;
1998         pSMB->ByteCount = cpu_to_le16(byte_count);
1999
2000         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2001                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2002         if (rc) {
2003                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2004         } else {
2005                 /* decode response */
2006  
2007                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2008                 if (rc || (pSMBr->ByteCount < 2))
2009                 /* BB also check enough total bytes returned */
2010                         rc = -EIO;      /* bad smb */
2011                 else {
2012                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2013                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2014                         rc = cifs_copy_posix_acl(acl_inf,
2015                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2016                                 buflen,acl_type,count);
2017                 }
2018         }
2019         cifs_buf_release(pSMB);
2020         if (rc == -EAGAIN)
2021                 goto queryAclRetry;
2022         return rc;
2023 }
2024
2025 int
2026 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2027                         const unsigned char *fileName,
2028                         const char *local_acl, const int buflen, 
2029                         const int acl_type,
2030                         const struct nls_table *nls_codepage, int remap)
2031 {
2032         struct smb_com_transaction2_spi_req *pSMB = NULL;
2033         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2034         char *parm_data;
2035         int name_len;
2036         int rc = 0;
2037         int bytes_returned = 0;
2038         __u16 params, byte_count, data_count, param_offset, offset;
2039
2040         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2041 setAclRetry:
2042         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2043                       (void **) &pSMBr);
2044         if (rc)
2045                 return rc;
2046         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2047                 name_len =
2048                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
2049                                       PATH_MAX, nls_codepage, remap);
2050                 name_len++;     /* trailing null */
2051                 name_len *= 2;
2052         } else {                /* BB improve the check for buffer overruns BB */
2053                 name_len = strnlen(fileName, PATH_MAX);
2054                 name_len++;     /* trailing null */
2055                 strncpy(pSMB->FileName, fileName, name_len);
2056         }
2057         params = 6 + name_len;
2058         pSMB->MaxParameterCount = cpu_to_le16(2);
2059         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2060         pSMB->MaxSetupCount = 0;
2061         pSMB->Reserved = 0;
2062         pSMB->Flags = 0;
2063         pSMB->Timeout = 0;
2064         pSMB->Reserved2 = 0;
2065         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2066                                      InformationLevel) - 4;
2067         offset = param_offset + params;
2068         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2069         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2070
2071         /* convert to on the wire format for POSIX ACL */
2072         data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2073
2074         if(data_count == 0) {
2075                 rc = -EOPNOTSUPP;
2076                 goto setACLerrorExit;
2077         }
2078         pSMB->DataOffset = cpu_to_le16(offset);
2079         pSMB->SetupCount = 1;
2080         pSMB->Reserved3 = 0;
2081         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2082         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2083         byte_count = 3 /* pad */  + params + data_count;
2084         pSMB->DataCount = cpu_to_le16(data_count);
2085         pSMB->TotalDataCount = pSMB->DataCount;
2086         pSMB->ParameterCount = cpu_to_le16(params);
2087         pSMB->TotalParameterCount = pSMB->ParameterCount;
2088         pSMB->Reserved4 = 0;
2089         pSMB->hdr.smb_buf_length += byte_count;
2090         pSMB->ByteCount = cpu_to_le16(byte_count);
2091         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2092                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2093         if (rc) {
2094                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2095         }
2096
2097 setACLerrorExit:
2098         cifs_buf_release(pSMB);
2099         if (rc == -EAGAIN)
2100                 goto setAclRetry;
2101         return rc;
2102 }
2103
2104 /* BB fix tabs in this function FIXME BB */
2105 int
2106 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2107                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2108 {
2109         int rc = 0;
2110         struct smb_t2_qfi_req *pSMB = NULL;
2111         struct smb_t2_qfi_rsp *pSMBr = NULL;
2112         int bytes_returned;
2113         __u16 params, byte_count;
2114
2115         cFYI(1,("In GetExtAttr"));
2116         if(tcon == NULL)
2117                 return -ENODEV;
2118
2119 GetExtAttrRetry:
2120         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2121                       (void **) &pSMBr);
2122         if (rc)
2123                 return rc;
2124
2125         params = 2 /* level */ +2 /* fid */;
2126         pSMB->t2.TotalDataCount = 0;
2127         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2128         /* BB find exact max data count below from sess structure BB */
2129         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2130         pSMB->t2.MaxSetupCount = 0;
2131         pSMB->t2.Reserved = 0;
2132         pSMB->t2.Flags = 0;
2133         pSMB->t2.Timeout = 0;
2134         pSMB->t2.Reserved2 = 0;
2135         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2136                         Fid) - 4);
2137         pSMB->t2.DataCount = 0;
2138         pSMB->t2.DataOffset = 0;
2139         pSMB->t2.SetupCount = 1;
2140         pSMB->t2.Reserved3 = 0;
2141         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2142         byte_count = params + 1 /* pad */ ;
2143         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2144         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2145         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2146         pSMB->Pad = 0;
2147         pSMB->Fid = netfid;
2148         pSMB->hdr.smb_buf_length += byte_count;
2149         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2150
2151         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2152                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2153         if (rc) {
2154                 cFYI(1, ("error %d in GetExtAttr", rc));
2155         } else {
2156                 /* decode response */
2157                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2158                 if (rc || (pSMBr->ByteCount < 2))
2159                 /* BB also check enough total bytes returned */
2160                         /* If rc should we check for EOPNOSUPP and
2161                         disable the srvino flag? or in caller? */
2162                         rc = -EIO;      /* bad smb */
2163                 else {
2164                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2165                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2166                         struct file_chattr_info * pfinfo;
2167                         /* BB Do we need a cast or hash here ? */
2168                         if(count != 16) {
2169                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
2170                                 rc = -EIO;
2171                                 goto GetExtAttrOut;
2172                         }
2173                         pfinfo = (struct file_chattr_info *)
2174                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2175                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2176                         *pMask = le64_to_cpu(pfinfo->mask);
2177                 }
2178         }
2179 GetExtAttrOut:
2180         cifs_buf_release(pSMB);
2181         if (rc == -EAGAIN)
2182                 goto GetExtAttrRetry;
2183         return rc;
2184 }
2185
2186
2187 #endif /* CONFIG_POSIX */
2188
2189 int
2190 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2191                  const unsigned char *searchName,
2192                  FILE_ALL_INFO * pFindData,
2193                  const struct nls_table *nls_codepage, int remap)
2194 {
2195 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2196         TRANSACTION2_QPI_REQ *pSMB = NULL;
2197         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2198         int rc = 0;
2199         int bytes_returned;
2200         int name_len;
2201         __u16 params, byte_count;
2202
2203 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2204 QPathInfoRetry:
2205         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2206                       (void **) &pSMBr);
2207         if (rc)
2208                 return rc;
2209
2210         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2211                 name_len =
2212                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2213                                      PATH_MAX, nls_codepage, remap);
2214                 name_len++;     /* trailing null */
2215                 name_len *= 2;
2216         } else {                /* BB improve the check for buffer overruns BB */
2217                 name_len = strnlen(searchName, PATH_MAX);
2218                 name_len++;     /* trailing null */
2219                 strncpy(pSMB->FileName, searchName, name_len);
2220         }
2221
2222         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2223         pSMB->TotalDataCount = 0;
2224         pSMB->MaxParameterCount = cpu_to_le16(2);
2225         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2226         pSMB->MaxSetupCount = 0;
2227         pSMB->Reserved = 0;
2228         pSMB->Flags = 0;
2229         pSMB->Timeout = 0;
2230         pSMB->Reserved2 = 0;
2231         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2232         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2233         pSMB->DataCount = 0;
2234         pSMB->DataOffset = 0;
2235         pSMB->SetupCount = 1;
2236         pSMB->Reserved3 = 0;
2237         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2238         byte_count = params + 1 /* pad */ ;
2239         pSMB->TotalParameterCount = cpu_to_le16(params);
2240         pSMB->ParameterCount = pSMB->TotalParameterCount;
2241         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2242         pSMB->Reserved4 = 0;
2243         pSMB->hdr.smb_buf_length += byte_count;
2244         pSMB->ByteCount = cpu_to_le16(byte_count);
2245
2246         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2247                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2248         if (rc) {
2249                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2250         } else {                /* decode response */
2251                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2252
2253                 if (rc || (pSMBr->ByteCount < 40)) 
2254                         rc = -EIO;      /* bad smb */
2255                 else if (pFindData){
2256                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2257                         memcpy((char *) pFindData,
2258                                (char *) &pSMBr->hdr.Protocol +
2259                                data_offset, sizeof (FILE_ALL_INFO));
2260                 } else
2261                     rc = -ENOMEM;
2262         }
2263         cifs_buf_release(pSMB);
2264         if (rc == -EAGAIN)
2265                 goto QPathInfoRetry;
2266
2267         return rc;
2268 }
2269
2270 int
2271 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2272                      const unsigned char *searchName,
2273                      FILE_UNIX_BASIC_INFO * pFindData,
2274                      const struct nls_table *nls_codepage, int remap)
2275 {
2276 /* SMB_QUERY_FILE_UNIX_BASIC */
2277         TRANSACTION2_QPI_REQ *pSMB = NULL;
2278         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2279         int rc = 0;
2280         int bytes_returned = 0;
2281         int name_len;
2282         __u16 params, byte_count;
2283
2284         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2285 UnixQPathInfoRetry:
2286         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2287                       (void **) &pSMBr);
2288         if (rc)
2289                 return rc;
2290
2291         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2292                 name_len =
2293                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2294                                   PATH_MAX, nls_codepage, remap);
2295                 name_len++;     /* trailing null */
2296                 name_len *= 2;
2297         } else {                /* BB improve the check for buffer overruns BB */
2298                 name_len = strnlen(searchName, PATH_MAX);
2299                 name_len++;     /* trailing null */
2300                 strncpy(pSMB->FileName, searchName, name_len);
2301         }
2302
2303         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2304         pSMB->TotalDataCount = 0;
2305         pSMB->MaxParameterCount = cpu_to_le16(2);
2306         /* BB find exact max SMB PDU from sess structure BB */
2307         pSMB->MaxDataCount = cpu_to_le16(4000); 
2308         pSMB->MaxSetupCount = 0;
2309         pSMB->Reserved = 0;
2310         pSMB->Flags = 0;
2311         pSMB->Timeout = 0;
2312         pSMB->Reserved2 = 0;
2313         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2314         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2315         pSMB->DataCount = 0;
2316         pSMB->DataOffset = 0;
2317         pSMB->SetupCount = 1;
2318         pSMB->Reserved3 = 0;
2319         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2320         byte_count = params + 1 /* pad */ ;
2321         pSMB->TotalParameterCount = cpu_to_le16(params);
2322         pSMB->ParameterCount = pSMB->TotalParameterCount;
2323         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2324         pSMB->Reserved4 = 0;
2325         pSMB->hdr.smb_buf_length += byte_count;
2326         pSMB->ByteCount = cpu_to_le16(byte_count);
2327
2328         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2329                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2330         if (rc) {
2331                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2332         } else {                /* decode response */
2333                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2334
2335                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2336                         rc = -EIO;      /* bad smb */
2337                 } else {
2338                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2339                         memcpy((char *) pFindData,
2340                                (char *) &pSMBr->hdr.Protocol +
2341                                data_offset,
2342                                sizeof (FILE_UNIX_BASIC_INFO));
2343                 }
2344         }
2345         cifs_buf_release(pSMB);
2346         if (rc == -EAGAIN)
2347                 goto UnixQPathInfoRetry;
2348
2349         return rc;
2350 }
2351
2352 #if 0  /* function unused at present */
2353 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2354                const char *searchName, FILE_ALL_INFO * findData,
2355                const struct nls_table *nls_codepage)
2356 {
2357 /* level 257 SMB_ */
2358         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2359         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2360         int rc = 0;
2361         int bytes_returned;
2362         int name_len;
2363         __u16 params, byte_count;
2364
2365         cFYI(1, ("In FindUnique"));
2366 findUniqueRetry:
2367         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2368                       (void **) &pSMBr);
2369         if (rc)
2370                 return rc;
2371
2372         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2373                 name_len =
2374                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2375                                   /* find define for this maxpathcomponent */
2376                                   , nls_codepage);
2377                 name_len++;     /* trailing null */
2378                 name_len *= 2;
2379         } else {                /* BB improve the check for buffer overruns BB */
2380                 name_len = strnlen(searchName, PATH_MAX);
2381                 name_len++;     /* trailing null */
2382                 strncpy(pSMB->FileName, searchName, name_len);
2383         }
2384
2385         params = 12 + name_len /* includes null */ ;
2386         pSMB->TotalDataCount = 0;       /* no EAs */
2387         pSMB->MaxParameterCount = cpu_to_le16(2);
2388         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2389         pSMB->MaxSetupCount = 0;
2390         pSMB->Reserved = 0;
2391         pSMB->Flags = 0;
2392         pSMB->Timeout = 0;
2393         pSMB->Reserved2 = 0;
2394         pSMB->ParameterOffset = cpu_to_le16(
2395          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2396         pSMB->DataCount = 0;
2397         pSMB->DataOffset = 0;
2398         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
2399         pSMB->Reserved3 = 0;
2400         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2401         byte_count = params + 1 /* pad */ ;
2402         pSMB->TotalParameterCount = cpu_to_le16(params);
2403         pSMB->ParameterCount = pSMB->TotalParameterCount;
2404         pSMB->SearchAttributes =
2405             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2406                         ATTR_DIRECTORY);
2407         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
2408         pSMB->SearchFlags = cpu_to_le16(1);
2409         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2410         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
2411         pSMB->hdr.smb_buf_length += byte_count;
2412         pSMB->ByteCount = cpu_to_le16(byte_count);
2413
2414         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2415                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2416
2417         if (rc) {
2418                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2419         } else {                /* decode response */
2420 #ifdef CONFIG_CIFS_STATS
2421                 atomic_inc(&tcon->num_ffirst);
2422 #endif
2423                 /* BB fill in */
2424         }
2425
2426         cifs_buf_release(pSMB);
2427         if (rc == -EAGAIN)
2428                 goto findUniqueRetry;
2429
2430         return rc;
2431 }
2432 #endif /* end unused (temporarily) function */
2433
2434 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2435 int
2436 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2437               const char *searchName, 
2438               const struct nls_table *nls_codepage,
2439               __u16 *   pnetfid,
2440               struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2441 {
2442 /* level 257 SMB_ */
2443         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2444         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2445         T2_FFIRST_RSP_PARMS * parms;
2446         int rc = 0;
2447         int bytes_returned = 0;
2448         int name_len;
2449         __u16 params, byte_count;
2450
2451         cFYI(1, ("In FindFirst for %s",searchName));
2452
2453 findFirstRetry:
2454         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2455                       (void **) &pSMBr);
2456         if (rc)
2457                 return rc;
2458
2459         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2460                 name_len =
2461                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2462                                  PATH_MAX, nls_codepage, remap);
2463                 /* We can not add the asterik earlier in case
2464                 it got remapped to 0xF03A as if it were part of the
2465                 directory name instead of a wildcard */
2466                 name_len *= 2;
2467                 pSMB->FileName[name_len] = dirsep;
2468                 pSMB->FileName[name_len+1] = 0;
2469                 pSMB->FileName[name_len+2] = '*';
2470                 pSMB->FileName[name_len+3] = 0;
2471                 name_len += 4; /* now the trailing null */
2472                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2473                 pSMB->FileName[name_len+1] = 0;
2474                 name_len += 2;
2475         } else {        /* BB add check for overrun of SMB buf BB */
2476                 name_len = strnlen(searchName, PATH_MAX);
2477 /* BB fix here and in unicode clause above ie
2478                 if(name_len > buffersize-header)
2479                         free buffer exit; BB */
2480                 strncpy(pSMB->FileName, searchName, name_len);
2481                 pSMB->FileName[name_len] = dirsep;
2482                 pSMB->FileName[name_len+1] = '*';
2483                 pSMB->FileName[name_len+2] = 0;
2484                 name_len += 3;
2485         }
2486
2487         params = 12 + name_len /* includes null */ ;
2488         pSMB->TotalDataCount = 0;       /* no EAs */
2489         pSMB->MaxParameterCount = cpu_to_le16(10);
2490         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2491                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2492         pSMB->MaxSetupCount = 0;
2493         pSMB->Reserved = 0;
2494         pSMB->Flags = 0;
2495         pSMB->Timeout = 0;
2496         pSMB->Reserved2 = 0;
2497         byte_count = params + 1 /* pad */ ;
2498         pSMB->TotalParameterCount = cpu_to_le16(params);
2499         pSMB->ParameterCount = pSMB->TotalParameterCount;
2500         pSMB->ParameterOffset = cpu_to_le16(
2501           offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2502         pSMB->DataCount = 0;
2503         pSMB->DataOffset = 0;
2504         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
2505         pSMB->Reserved3 = 0;
2506         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2507         pSMB->SearchAttributes =
2508             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2509                         ATTR_DIRECTORY);
2510         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2511         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
2512                 CIFS_SEARCH_RETURN_RESUME);
2513         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2514
2515         /* BB what should we set StorageType to? Does it matter? BB */
2516         pSMB->SearchStorageType = 0;
2517         pSMB->hdr.smb_buf_length += byte_count;
2518         pSMB->ByteCount = cpu_to_le16(byte_count);
2519
2520         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2521                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2522
2523         if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2524                 /* BB Add code to handle unsupported level rc */
2525                 cFYI(1, ("Error in FindFirst = %d", rc));
2526
2527                 if (pSMB)
2528                         cifs_buf_release(pSMB);
2529
2530                 /* BB eventually could optimize out free and realloc of buf */
2531                 /*    for this case */
2532                 if (rc == -EAGAIN)
2533                         goto findFirstRetry;
2534         } else { /* decode response */
2535 #ifdef CONFIG_CIFS_STATS
2536                 atomic_inc(&tcon->num_ffirst);
2537 #endif
2538                 /* BB remember to free buffer if error BB */
2539                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2540                 if(rc == 0) {
2541                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2542                                 psrch_inf->unicode = TRUE;
2543                         else
2544                                 psrch_inf->unicode = FALSE;
2545
2546                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2547                         psrch_inf->srch_entries_start = 
2548                                 (char *) &pSMBr->hdr.Protocol + 
2549                                         le16_to_cpu(pSMBr->t2.DataOffset);
2550                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2551                                le16_to_cpu(pSMBr->t2.ParameterOffset));
2552
2553                         if(parms->EndofSearch)
2554                                 psrch_inf->endOfSearch = TRUE;
2555                         else
2556                                 psrch_inf->endOfSearch = FALSE;
2557
2558                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2559                         psrch_inf->index_of_last_entry = 
2560                                 psrch_inf->entries_in_buffer;
2561                         *pnetfid = parms->SearchHandle;
2562                 } else {
2563                         cifs_buf_release(pSMB);
2564                 }
2565         }
2566
2567         return rc;
2568 }
2569
2570 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2571             __u16 searchHandle, struct cifs_search_info * psrch_inf)
2572 {
2573         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2574         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2575         T2_FNEXT_RSP_PARMS * parms;
2576         char *response_data;
2577         int rc = 0;
2578         int bytes_returned, name_len;
2579         __u16 params, byte_count;
2580
2581         cFYI(1, ("In FindNext"));
2582
2583         if(psrch_inf->endOfSearch == TRUE)
2584                 return -ENOENT;
2585
2586         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2587                 (void **) &pSMBr);
2588         if (rc)
2589                 return rc;
2590
2591         params = 14;    /* includes 2 bytes of null string, converted to LE below */
2592         byte_count = 0;
2593         pSMB->TotalDataCount = 0;       /* no EAs */
2594         pSMB->MaxParameterCount = cpu_to_le16(8);
2595         pSMB->MaxDataCount =
2596             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2597         pSMB->MaxSetupCount = 0;
2598         pSMB->Reserved = 0;
2599         pSMB->Flags = 0;
2600         pSMB->Timeout = 0;
2601         pSMB->Reserved2 = 0;
2602         pSMB->ParameterOffset =  cpu_to_le16(
2603               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2604         pSMB->DataCount = 0;
2605         pSMB->DataOffset = 0;
2606         pSMB->SetupCount = 1;
2607         pSMB->Reserved3 = 0;
2608         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2609         pSMB->SearchHandle = searchHandle;      /* always kept as le */
2610         pSMB->SearchCount =
2611                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2612         /* test for Unix extensions */
2613 /*      if (tcon->ses->capabilities & CAP_UNIX) {
2614                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2615                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2616         } else {
2617                 pSMB->InformationLevel =
2618                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2619                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2620         } */
2621         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2622         pSMB->ResumeKey = psrch_inf->resume_key;
2623         pSMB->SearchFlags =
2624               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2625
2626         name_len = psrch_inf->resume_name_len;
2627         params += name_len;
2628         if(name_len < PATH_MAX) {
2629                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2630                 byte_count += name_len;
2631                 /* 14 byte parm len above enough for 2 byte null terminator */
2632                 pSMB->ResumeFileName[name_len] = 0;
2633                 pSMB->ResumeFileName[name_len+1] = 0;
2634         } else {
2635                 rc = -EINVAL;
2636                 goto FNext2_err_exit;
2637         }
2638         byte_count = params + 1 /* pad */ ;
2639         pSMB->TotalParameterCount = cpu_to_le16(params);
2640         pSMB->ParameterCount = pSMB->TotalParameterCount;
2641         pSMB->hdr.smb_buf_length += byte_count;
2642         pSMB->ByteCount = cpu_to_le16(byte_count);
2643                                                                                               
2644         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2645                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2646                                                                                               
2647         if (rc) {
2648                 if (rc == -EBADF) {
2649                         psrch_inf->endOfSearch = TRUE;
2650                         rc = 0; /* search probably was closed at end of search above */
2651                 } else
2652                         cFYI(1, ("FindNext returned = %d", rc));
2653         } else {                /* decode response */
2654 #ifdef CONFIG_CIFS_STATS
2655                 atomic_inc(&tcon->num_fnext);
2656 #endif
2657                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2658                 
2659                 if(rc == 0) {
2660                         /* BB fixme add lock for file (srch_info) struct here */
2661                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2662                                 psrch_inf->unicode = TRUE;
2663                         else
2664                                 psrch_inf->unicode = FALSE;
2665                         response_data = (char *) &pSMBr->hdr.Protocol +
2666                                le16_to_cpu(pSMBr->t2.ParameterOffset);
2667                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
2668                         response_data = (char *)&pSMBr->hdr.Protocol +
2669                                 le16_to_cpu(pSMBr->t2.DataOffset);
2670                         cifs_buf_release(psrch_inf->ntwrk_buf_start);
2671                         psrch_inf->srch_entries_start = response_data;
2672                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
2673                         if(parms->EndofSearch)
2674                                 psrch_inf->endOfSearch = TRUE;
2675                         else
2676                                 psrch_inf->endOfSearch = FALSE;
2677                                                                                               
2678                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2679                         psrch_inf->index_of_last_entry +=
2680                                 psrch_inf->entries_in_buffer;
2681 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2682
2683                         /* BB fixme add unlock here */
2684                 }
2685
2686         }
2687
2688         /* BB On error, should we leave previous search buf (and count and
2689         last entry fields) intact or free the previous one? */
2690
2691         /* Note: On -EAGAIN error only caller can retry on handle based calls
2692         since file handle passed in no longer valid */
2693 FNext2_err_exit:
2694         if (rc != 0)
2695                 cifs_buf_release(pSMB);
2696                                                                                               
2697         return rc;
2698 }
2699
2700 int
2701 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2702 {
2703         int rc = 0;
2704         FINDCLOSE_REQ *pSMB = NULL;
2705         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2706         int bytes_returned;
2707
2708         cFYI(1, ("In CIFSSMBFindClose"));
2709         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2710
2711         /* no sense returning error if session restarted
2712                 as file handle has been closed */
2713         if(rc == -EAGAIN)
2714                 return 0;
2715         if (rc)
2716                 return rc;
2717
2718         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
2719         pSMB->FileID = searchHandle;
2720         pSMB->ByteCount = 0;
2721         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2722                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2723         if (rc) {
2724                 cERROR(1, ("Send error in FindClose = %d", rc));
2725         }
2726 #ifdef CONFIG_CIFS_STATS
2727         atomic_inc(&tcon->num_fclose);
2728 #endif
2729         cifs_small_buf_release(pSMB);
2730
2731         /* Since session is dead, search handle closed on server already */
2732         if (rc == -EAGAIN)
2733                 rc = 0;
2734
2735         return rc;
2736 }
2737
2738 #ifdef CONFIG_CIFS_EXPERIMENTAL
2739 int
2740 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2741                 const unsigned char *searchName,
2742                 __u64 * inode_number,
2743                 const struct nls_table *nls_codepage, int remap)
2744 {
2745         int rc = 0;
2746         TRANSACTION2_QPI_REQ *pSMB = NULL;
2747         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2748         int name_len, bytes_returned;
2749         __u16 params, byte_count;
2750
2751         cFYI(1,("In GetSrvInodeNum for %s",searchName));
2752         if(tcon == NULL)
2753                 return -ENODEV; 
2754
2755 GetInodeNumberRetry:
2756         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2757                       (void **) &pSMBr);
2758         if (rc)
2759                 return rc;
2760
2761
2762         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2763                 name_len =
2764                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2765                                 PATH_MAX,nls_codepage, remap);
2766                 name_len++;     /* trailing null */
2767                 name_len *= 2;
2768         } else {                /* BB improve the check for buffer overruns BB */
2769                 name_len = strnlen(searchName, PATH_MAX);
2770                 name_len++;     /* trailing null */
2771                 strncpy(pSMB->FileName, searchName, name_len);
2772         }
2773
2774         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2775         pSMB->TotalDataCount = 0;
2776         pSMB->MaxParameterCount = cpu_to_le16(2);
2777         /* BB find exact max data count below from sess structure BB */
2778         pSMB->MaxDataCount = cpu_to_le16(4000);
2779         pSMB->MaxSetupCount = 0;
2780         pSMB->Reserved = 0;
2781         pSMB->Flags = 0;
2782         pSMB->Timeout = 0;
2783         pSMB->Reserved2 = 0;
2784         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2785                 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2786         pSMB->DataCount = 0;
2787         pSMB->DataOffset = 0;
2788         pSMB->SetupCount = 1;
2789         pSMB->Reserved3 = 0;
2790         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2791         byte_count = params + 1 /* pad */ ;
2792         pSMB->TotalParameterCount = cpu_to_le16(params);
2793         pSMB->ParameterCount = pSMB->TotalParameterCount;
2794         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
2795         pSMB->Reserved4 = 0;
2796         pSMB->hdr.smb_buf_length += byte_count;
2797         pSMB->ByteCount = cpu_to_le16(byte_count);
2798
2799         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2800                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2801         if (rc) {
2802                 cFYI(1, ("error %d in QueryInternalInfo", rc));
2803         } else {
2804                 /* decode response */
2805                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2806                 if (rc || (pSMBr->ByteCount < 2))
2807                 /* BB also check enough total bytes returned */
2808                         /* If rc should we check for EOPNOSUPP and
2809                         disable the srvino flag? or in caller? */
2810                         rc = -EIO;      /* bad smb */
2811                 else {
2812                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2813                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2814                         struct file_internal_info * pfinfo;
2815                         /* BB Do we need a cast or hash here ? */
2816                         if(count < 8) {
2817                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
2818                                 rc = -EIO;
2819                                 goto GetInodeNumOut;
2820                         }
2821                         pfinfo = (struct file_internal_info *)
2822                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2823                         *inode_number = pfinfo->UniqueId;
2824                 }
2825         }
2826 GetInodeNumOut:
2827         cifs_buf_release(pSMB);
2828         if (rc == -EAGAIN)
2829                 goto GetInodeNumberRetry;
2830         return rc;
2831 }
2832 #endif /* CIFS_EXPERIMENTAL */
2833
2834 int
2835 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2836                 const unsigned char *searchName,
2837                 unsigned char **targetUNCs,
2838                 unsigned int *number_of_UNC_in_array,
2839                 const struct nls_table *nls_codepage, int remap)
2840 {
2841 /* TRANS2_GET_DFS_REFERRAL */
2842         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2843         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2844         struct dfs_referral_level_3 * referrals = NULL;
2845         int rc = 0;
2846         int bytes_returned;
2847         int name_len;
2848         unsigned int i;
2849         char * temp;
2850         __u16 params, byte_count;
2851         *number_of_UNC_in_array = 0;
2852         *targetUNCs = NULL;
2853
2854         cFYI(1, ("In GetDFSRefer the path %s", searchName));
2855         if (ses == NULL)
2856                 return -ENODEV;
2857 getDFSRetry:
2858         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2859                       (void **) &pSMBr);
2860         if (rc)
2861                 return rc;
2862
2863         pSMB->hdr.Tid = ses->ipc_tid;
2864         pSMB->hdr.Uid = ses->Suid;
2865         if (ses->capabilities & CAP_STATUS32) {
2866                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2867         }
2868         if (ses->capabilities & CAP_DFS) {
2869                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2870         }
2871
2872         if (ses->capabilities & CAP_UNICODE) {
2873                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2874                 name_len =
2875                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
2876                                      searchName, PATH_MAX, nls_codepage, remap);
2877                 name_len++;     /* trailing null */
2878                 name_len *= 2;
2879         } else {                /* BB improve the check for buffer overruns BB */
2880                 name_len = strnlen(searchName, PATH_MAX);
2881                 name_len++;     /* trailing null */
2882                 strncpy(pSMB->RequestFileName, searchName, name_len);
2883         }
2884
2885         params = 2 /* level */  + name_len /*includes null */ ;
2886         pSMB->TotalDataCount = 0;
2887         pSMB->DataCount = 0;
2888         pSMB->DataOffset = 0;
2889         pSMB->MaxParameterCount = 0;
2890         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2891         pSMB->MaxSetupCount = 0;
2892         pSMB->Reserved = 0;
2893         pSMB->Flags = 0;
2894         pSMB->Timeout = 0;
2895         pSMB->Reserved2 = 0;
2896         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2897         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2898         pSMB->SetupCount = 1;
2899         pSMB->Reserved3 = 0;
2900         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2901         byte_count = params + 3 /* pad */ ;
2902         pSMB->ParameterCount = cpu_to_le16(params);
2903         pSMB->TotalParameterCount = pSMB->ParameterCount;
2904         pSMB->MaxReferralLevel = cpu_to_le16(3);
2905         pSMB->hdr.smb_buf_length += byte_count;
2906         pSMB->ByteCount = cpu_to_le16(byte_count);
2907
2908         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2909                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2910         if (rc) {
2911                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2912         } else {                /* decode response */
2913 /* BB Add logic to parse referrals here */
2914                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2915
2916                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
2917                         rc = -EIO;      /* bad smb */
2918                 else {
2919                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
2920                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2921
2922                         cFYI(1,
2923                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
2924                               pSMBr->ByteCount, data_offset));
2925                         referrals = 
2926                             (struct dfs_referral_level_3 *) 
2927                                         (8 /* sizeof start of data block */ +
2928                                         data_offset +
2929                                         (char *) &pSMBr->hdr.Protocol); 
2930                         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",
2931                                 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)));
2932                         /* BB This field is actually two bytes in from start of
2933                            data block so we could do safety check that DataBlock
2934                            begins at address of pSMBr->NumberOfReferrals */
2935                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2936
2937                         /* BB Fix below so can return more than one referral */
2938                         if(*number_of_UNC_in_array > 1)
2939                                 *number_of_UNC_in_array = 1;
2940
2941                         /* get the length of the strings describing refs */
2942                         name_len = 0;
2943                         for(i=0;i<*number_of_UNC_in_array;i++) {
2944                                 /* make sure that DfsPathOffset not past end */
2945                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2946                                 if (offset > data_count) {
2947                                         /* if invalid referral, stop here and do 
2948                                         not try to copy any more */
2949                                         *number_of_UNC_in_array = i;
2950                                         break;
2951                                 } 
2952                                 temp = ((char *)referrals) + offset;
2953
2954                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2955                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
2956                                 } else {
2957                                         name_len += strnlen(temp,data_count);
2958                                 }
2959                                 referrals++;
2960                                 /* BB add check that referral pointer does not fall off end PDU */
2961                                 
2962                         }
2963                         /* BB add check for name_len bigger than bcc */
2964                         *targetUNCs = 
2965                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2966                         if(*targetUNCs == NULL) {
2967                                 rc = -ENOMEM;
2968                                 goto GetDFSRefExit;
2969                         }
2970                         /* copy the ref strings */
2971                         referrals =  
2972                             (struct dfs_referral_level_3 *) 
2973                                         (8 /* sizeof data hdr */ +
2974                                         data_offset + 
2975                                         (char *) &pSMBr->hdr.Protocol);
2976
2977                         for(i=0;i<*number_of_UNC_in_array;i++) {
2978                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
2979                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2980                                         cifs_strfromUCS_le(*targetUNCs,
2981                                                 (wchar_t *) temp, name_len, nls_codepage);
2982                                 } else {
2983                                         strncpy(*targetUNCs,temp,name_len);
2984                                 }
2985                                 /*  BB update target_uncs pointers */
2986                                 referrals++;
2987                         }
2988                         temp = *targetUNCs;
2989                         temp[name_len] = 0;
2990                 }
2991
2992         }
2993 GetDFSRefExit:
2994         if (pSMB)
2995                 cifs_buf_release(pSMB);
2996
2997         if (rc == -EAGAIN)
2998                 goto getDFSRetry;
2999
3000         return rc;
3001 }
3002
3003 int
3004 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3005 {
3006 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3007         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3008         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3009         FILE_SYSTEM_INFO *response_data;
3010         int rc = 0;
3011         int bytes_returned = 0;
3012         __u16 params, byte_count;
3013
3014         cFYI(1, ("In QFSInfo"));
3015 QFSInfoRetry:
3016         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3017                       (void **) &pSMBr);
3018         if (rc)
3019                 return rc;
3020
3021         params = 2;     /* level */
3022         pSMB->TotalDataCount = 0;
3023         pSMB->MaxParameterCount = cpu_to_le16(2);
3024         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3025         pSMB->MaxSetupCount = 0;
3026         pSMB->Reserved = 0;
3027         pSMB->Flags = 0;
3028         pSMB->Timeout = 0;
3029         pSMB->Reserved2 = 0;
3030         byte_count = params + 1 /* pad */ ;
3031         pSMB->TotalParameterCount = cpu_to_le16(params);
3032         pSMB->ParameterCount = pSMB->TotalParameterCount;
3033         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3034         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3035         pSMB->DataCount = 0;
3036         pSMB->DataOffset = 0;
3037         pSMB->SetupCount = 1;
3038         pSMB->Reserved3 = 0;
3039         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3040         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3041         pSMB->hdr.smb_buf_length += byte_count;
3042         pSMB->ByteCount = cpu_to_le16(byte_count);
3043
3044         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3045                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3046         if (rc) {
3047                 cERROR(1, ("Send error in QFSInfo = %d", rc));
3048         } else {                /* decode response */
3049                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3050
3051                 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3052                         rc = -EIO;      /* bad smb */
3053                 else {
3054                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3055                         cFYI(1,
3056                                 ("Decoding qfsinfo response.  BCC: %d  Offset %d",
3057                                 pSMBr->ByteCount, data_offset));
3058
3059                         response_data =
3060                             (FILE_SYSTEM_INFO
3061                              *) (((char *) &pSMBr->hdr.Protocol) +
3062                                  data_offset);
3063                         FSData->f_bsize =
3064                             le32_to_cpu(response_data->BytesPerSector) *
3065                             le32_to_cpu(response_data->
3066                                         SectorsPerAllocationUnit);
3067                         FSData->f_blocks =
3068                             le64_to_cpu(response_data->TotalAllocationUnits);
3069                         FSData->f_bfree = FSData->f_bavail =
3070                             le64_to_cpu(response_data->FreeAllocationUnits);
3071                         cFYI(1,
3072                              ("Blocks: %lld  Free: %lld Block size %ld",
3073                               (unsigned long long)FSData->f_blocks,
3074                               (unsigned long long)FSData->f_bfree,
3075                               FSData->f_bsize));
3076                 }
3077         }
3078         cifs_buf_release(pSMB);
3079
3080         if (rc == -EAGAIN)
3081                 goto QFSInfoRetry;
3082
3083         return rc;
3084 }
3085
3086 int
3087 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3088 {
3089 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3090         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3091         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3092         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3093         int rc = 0;
3094         int bytes_returned = 0;
3095         __u16 params, byte_count;
3096
3097         cFYI(1, ("In QFSAttributeInfo"));
3098 QFSAttributeRetry:
3099         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3100                       (void **) &pSMBr);
3101         if (rc)
3102                 return rc;
3103
3104         params = 2;     /* level */
3105         pSMB->TotalDataCount = 0;
3106         pSMB->MaxParameterCount = cpu_to_le16(2);
3107         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3108         pSMB->MaxSetupCount = 0;
3109         pSMB->Reserved = 0;
3110         pSMB->Flags = 0;
3111         pSMB->Timeout = 0;
3112         pSMB->Reserved2 = 0;
3113         byte_count = params + 1 /* pad */ ;
3114         pSMB->TotalParameterCount = cpu_to_le16(params);
3115         pSMB->ParameterCount = pSMB->TotalParameterCount;
3116         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3117         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3118         pSMB->DataCount = 0;
3119         pSMB->DataOffset = 0;
3120         pSMB->SetupCount = 1;
3121         pSMB->Reserved3 = 0;
3122         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3123         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3124         pSMB->hdr.smb_buf_length += byte_count;
3125         pSMB->ByteCount = cpu_to_le16(byte_count);
3126
3127         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3128                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3129         if (rc) {
3130                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3131         } else {                /* decode response */
3132                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3133
3134                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3135                         rc = -EIO;      /* bad smb */
3136                 } else {
3137                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3138                         response_data =
3139                             (FILE_SYSTEM_ATTRIBUTE_INFO
3140                              *) (((char *) &pSMBr->hdr.Protocol) +
3141                                  data_offset);
3142                         memcpy(&tcon->fsAttrInfo, response_data,
3143                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3144                 }
3145         }
3146         cifs_buf_release(pSMB);
3147
3148         if (rc == -EAGAIN)
3149                 goto QFSAttributeRetry;
3150
3151         return rc;
3152 }
3153
3154 int
3155 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3156 {
3157 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3158         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3159         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3160         FILE_SYSTEM_DEVICE_INFO *response_data;
3161         int rc = 0;
3162         int bytes_returned = 0;
3163         __u16 params, byte_count;
3164
3165         cFYI(1, ("In QFSDeviceInfo"));
3166 QFSDeviceRetry:
3167         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3168                       (void **) &pSMBr);
3169         if (rc)
3170                 return rc;
3171
3172         params = 2;     /* level */
3173         pSMB->TotalDataCount = 0;
3174         pSMB->MaxParameterCount = cpu_to_le16(2);
3175         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3176         pSMB->MaxSetupCount = 0;
3177         pSMB->Reserved = 0;
3178         pSMB->Flags = 0;
3179         pSMB->Timeout = 0;
3180         pSMB->Reserved2 = 0;
3181         byte_count = params + 1 /* pad */ ;
3182         pSMB->TotalParameterCount = cpu_to_le16(params);
3183         pSMB->ParameterCount = pSMB->TotalParameterCount;
3184         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3185         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3186
3187         pSMB->DataCount = 0;
3188         pSMB->DataOffset = 0;
3189         pSMB->SetupCount = 1;
3190         pSMB->Reserved3 = 0;
3191         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3192         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3193         pSMB->hdr.smb_buf_length += byte_count;
3194         pSMB->ByteCount = cpu_to_le16(byte_count);
3195
3196         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3197                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3198         if (rc) {
3199                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3200         } else {                /* decode response */
3201                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3202
3203                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3204                         rc = -EIO;      /* bad smb */
3205                 else {
3206                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3207                         response_data =
3208                             (FILE_SYSTEM_DEVICE_INFO *)
3209                                 (((char *) &pSMBr->hdr.Protocol) +
3210                                  data_offset);
3211                         memcpy(&tcon->fsDevInfo, response_data,
3212                                sizeof (FILE_SYSTEM_DEVICE_INFO));
3213                 }
3214         }
3215         cifs_buf_release(pSMB);
3216
3217         if (rc == -EAGAIN)
3218                 goto QFSDeviceRetry;
3219
3220         return rc;
3221 }
3222
3223 int
3224 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3225 {
3226 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
3227         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3228         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3229         FILE_SYSTEM_UNIX_INFO *response_data;
3230         int rc = 0;
3231         int bytes_returned = 0;
3232         __u16 params, byte_count;
3233
3234         cFYI(1, ("In QFSUnixInfo"));
3235 QFSUnixRetry:
3236         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3237                       (void **) &pSMBr);
3238         if (rc)
3239                 return rc;
3240
3241         params = 2;     /* level */
3242         pSMB->TotalDataCount = 0;
3243         pSMB->DataCount = 0;
3244         pSMB->DataOffset = 0;
3245         pSMB->MaxParameterCount = cpu_to_le16(2);
3246         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3247         pSMB->MaxSetupCount = 0;
3248         pSMB->Reserved = 0;
3249         pSMB->Flags = 0;
3250         pSMB->Timeout = 0;
3251         pSMB->Reserved2 = 0;
3252         byte_count = params + 1 /* pad */ ;
3253         pSMB->ParameterCount = cpu_to_le16(params);
3254         pSMB->TotalParameterCount = pSMB->ParameterCount;
3255         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3256         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3257         pSMB->SetupCount = 1;
3258         pSMB->Reserved3 = 0;
3259         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3260         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3261         pSMB->hdr.smb_buf_length += byte_count;
3262         pSMB->ByteCount = cpu_to_le16(byte_count);
3263
3264         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3265                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3266         if (rc) {
3267                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3268         } else {                /* decode response */
3269                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3270
3271                 if (rc || (pSMBr->ByteCount < 13)) {
3272                         rc = -EIO;      /* bad smb */
3273                 } else {
3274                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3275                         response_data =
3276                             (FILE_SYSTEM_UNIX_INFO
3277                              *) (((char *) &pSMBr->hdr.Protocol) +
3278                                  data_offset);
3279                         memcpy(&tcon->fsUnixInfo, response_data,
3280                                sizeof (FILE_SYSTEM_UNIX_INFO));
3281                 }
3282         }
3283         cifs_buf_release(pSMB);
3284
3285         if (rc == -EAGAIN)
3286                 goto QFSUnixRetry;
3287
3288
3289         return rc;
3290 }
3291
3292 int
3293 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3294 {
3295 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
3296         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3297         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3298         int rc = 0;
3299         int bytes_returned = 0;
3300         __u16 params, param_offset, offset, byte_count;
3301
3302         cFYI(1, ("In SETFSUnixInfo"));
3303 SETFSUnixRetry:
3304         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3305                       (void **) &pSMBr);
3306         if (rc)
3307                 return rc;
3308
3309         params = 4;     /* 2 bytes zero followed by info level. */
3310         pSMB->MaxSetupCount = 0;
3311         pSMB->Reserved = 0;
3312         pSMB->Flags = 0;
3313         pSMB->Timeout = 0;
3314         pSMB->Reserved2 = 0;
3315         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3316         offset = param_offset + params;
3317
3318         pSMB->MaxParameterCount = cpu_to_le16(4);
3319         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3320         pSMB->SetupCount = 1;
3321         pSMB->Reserved3 = 0;
3322         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3323         byte_count = 1 /* pad */ + params + 12;
3324
3325         pSMB->DataCount = cpu_to_le16(12);
3326         pSMB->ParameterCount = cpu_to_le16(params);
3327         pSMB->TotalDataCount = pSMB->DataCount;
3328         pSMB->TotalParameterCount = pSMB->ParameterCount;
3329         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3330         pSMB->DataOffset = cpu_to_le16(offset);
3331
3332         /* Params. */
3333         pSMB->FileNum = 0;
3334         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3335
3336         /* Data. */
3337         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3338         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3339         pSMB->ClientUnixCap = cpu_to_le64(cap);
3340
3341         pSMB->hdr.smb_buf_length += byte_count;
3342         pSMB->ByteCount = cpu_to_le16(byte_count);
3343
3344         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3345                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3346         if (rc) {
3347                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3348         } else {                /* decode response */
3349                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3350                 if (rc) {
3351                         rc = -EIO;      /* bad smb */
3352                 }
3353         }
3354         cifs_buf_release(pSMB);
3355
3356         if (rc == -EAGAIN)
3357                 goto SETFSUnixRetry;
3358
3359         return rc;
3360 }
3361
3362
3363
3364 int
3365 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3366                    struct kstatfs *FSData)
3367 {
3368 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
3369         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3370         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3371         FILE_SYSTEM_POSIX_INFO *response_data;
3372         int rc = 0;
3373         int bytes_returned = 0;
3374         __u16 params, byte_count;
3375
3376         cFYI(1, ("In QFSPosixInfo"));
3377 QFSPosixRetry:
3378         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3379                       (void **) &pSMBr);
3380         if (rc)
3381                 return rc;
3382
3383         params = 2;     /* level */
3384         pSMB->TotalDataCount = 0;
3385         pSMB->DataCount = 0;
3386         pSMB->DataOffset = 0;
3387         pSMB->MaxParameterCount = cpu_to_le16(2);
3388         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3389         pSMB->MaxSetupCount = 0;
3390         pSMB->Reserved = 0;
3391         pSMB->Flags = 0;
3392         pSMB->Timeout = 0;
3393         pSMB->Reserved2 = 0;
3394         byte_count = params + 1 /* pad */ ;
3395         pSMB->ParameterCount = cpu_to_le16(params);
3396         pSMB->TotalParameterCount = pSMB->ParameterCount;
3397         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3398         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3399         pSMB->SetupCount = 1;
3400         pSMB->Reserved3 = 0;
3401         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3402         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3403         pSMB->hdr.smb_buf_length += byte_count;
3404         pSMB->ByteCount = cpu_to_le16(byte_count);
3405
3406         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3407                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3408         if (rc) {
3409                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3410         } else {                /* decode response */
3411                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3412
3413                 if (rc || (pSMBr->ByteCount < 13)) {
3414                         rc = -EIO;      /* bad smb */
3415                 } else {
3416                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3417                         response_data =
3418                             (FILE_SYSTEM_POSIX_INFO
3419                              *) (((char *) &pSMBr->hdr.Protocol) +
3420                                  data_offset);
3421                         FSData->f_bsize =
3422                                         le32_to_cpu(response_data->BlockSize);
3423                         FSData->f_blocks =
3424                                         le64_to_cpu(response_data->TotalBlocks);
3425                         FSData->f_bfree =
3426                             le64_to_cpu(response_data->BlocksAvail);
3427                         if(response_data->UserBlocksAvail == -1) {
3428                                 FSData->f_bavail = FSData->f_bfree;
3429                         } else {
3430                                 FSData->f_bavail =
3431                                         le64_to_cpu(response_data->UserBlocksAvail);
3432                         }
3433                         if(response_data->TotalFileNodes != -1)
3434                                 FSData->f_files =
3435                                         le64_to_cpu(response_data->TotalFileNodes);
3436                         if(response_data->FreeFileNodes != -1)
3437                                 FSData->f_ffree =
3438                                         le64_to_cpu(response_data->FreeFileNodes);
3439                 }
3440         }
3441         cifs_buf_release(pSMB);
3442
3443         if (rc == -EAGAIN)
3444                 goto QFSPosixRetry;
3445
3446         return rc;
3447 }
3448
3449
3450 /* We can not use write of zero bytes trick to 
3451    set file size due to need for large file support.  Also note that 
3452    this SetPathInfo is preferred to SetFileInfo based method in next 
3453    routine which is only needed to work around a sharing violation bug
3454    in Samba which this routine can run into */
3455
3456 int
3457 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3458               __u64 size, int SetAllocation, 
3459               const struct nls_table *nls_codepage, int remap)
3460 {
3461         struct smb_com_transaction2_spi_req *pSMB = NULL;
3462         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3463         struct file_end_of_file_info *parm_data;
3464         int name_len;
3465         int rc = 0;
3466         int bytes_returned = 0;
3467         __u16 params, byte_count, data_count, param_offset, offset;
3468
3469         cFYI(1, ("In SetEOF"));
3470 SetEOFRetry:
3471         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3472                       (void **) &pSMBr);
3473         if (rc)
3474                 return rc;
3475
3476         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3477                 name_len =
3478                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3479                                      PATH_MAX, nls_codepage, remap);
3480                 name_len++;     /* trailing null */
3481                 name_len *= 2;
3482         } else {                /* BB improve the check for buffer overruns BB */
3483                 name_len = strnlen(fileName, PATH_MAX);
3484                 name_len++;     /* trailing null */
3485                 strncpy(pSMB->FileName, fileName, name_len);
3486         }
3487         params = 6 + name_len;
3488         data_count = sizeof (struct file_end_of_file_info);
3489         pSMB->MaxParameterCount = cpu_to_le16(2);
3490         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3491         pSMB->MaxSetupCount = 0;
3492         pSMB->Reserved = 0;
3493         pSMB->Flags = 0;
3494         pSMB->Timeout = 0;
3495         pSMB->Reserved2 = 0;
3496         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3497                                      InformationLevel) - 4;
3498         offset = param_offset + params;
3499         if(SetAllocation) {
3500                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3501                     pSMB->InformationLevel =
3502                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3503                 else
3504                     pSMB->InformationLevel =
3505                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3506         } else /* Set File Size */  {    
3507             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3508                     pSMB->InformationLevel =
3509                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3510             else
3511                     pSMB->InformationLevel =
3512                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3513         }
3514
3515         parm_data =
3516             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3517                                        offset);
3518         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3519         pSMB->DataOffset = cpu_to_le16(offset);
3520         pSMB->SetupCount = 1;
3521         pSMB->Reserved3 = 0;
3522         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3523         byte_count = 3 /* pad */  + params + data_count;
3524         pSMB->DataCount = cpu_to_le16(data_count);
3525         pSMB->TotalDataCount = pSMB->DataCount;
3526         pSMB->ParameterCount = cpu_to_le16(params);
3527         pSMB->TotalParameterCount = pSMB->ParameterCount;
3528         pSMB->Reserved4 = 0;
3529         pSMB->hdr.smb_buf_length += byte_count;
3530         parm_data->FileSize = cpu_to_le64(size);
3531         pSMB->ByteCount = cpu_to_le16(byte_count);
3532         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3533                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3534         if (rc) {
3535                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3536         }
3537
3538         cifs_buf_release(pSMB);
3539
3540         if (rc == -EAGAIN)
3541                 goto SetEOFRetry;
3542
3543         return rc;
3544 }
3545
3546 int
3547 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
3548                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
3549 {
3550         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
3551         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3552         char *data_offset;
3553         struct file_end_of_file_info *parm_data;
3554         int rc = 0;
3555         int bytes_returned = 0;
3556         __u16 params, param_offset, offset, byte_count, count;
3557
3558         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3559                         (long long)size));
3560         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3561
3562         if (rc)
3563                 return rc;
3564
3565         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3566
3567         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3568         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3569     
3570         params = 6;
3571         pSMB->MaxSetupCount = 0;
3572         pSMB->Reserved = 0;
3573         pSMB->Flags = 0;
3574         pSMB->Timeout = 0;
3575         pSMB->Reserved2 = 0;
3576         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3577         offset = param_offset + params;
3578
3579         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
3580
3581         count = sizeof(struct file_end_of_file_info);
3582         pSMB->MaxParameterCount = cpu_to_le16(2);
3583         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3584         pSMB->SetupCount = 1;
3585         pSMB->Reserved3 = 0;
3586         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3587         byte_count = 3 /* pad */  + params + count;
3588         pSMB->DataCount = cpu_to_le16(count);
3589         pSMB->ParameterCount = cpu_to_le16(params);
3590         pSMB->TotalDataCount = pSMB->DataCount;
3591         pSMB->TotalParameterCount = pSMB->ParameterCount;
3592         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3593         parm_data =
3594                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3595                         offset);
3596         pSMB->DataOffset = cpu_to_le16(offset);
3597         parm_data->FileSize = cpu_to_le64(size);
3598         pSMB->Fid = fid;
3599         if(SetAllocation) {
3600                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3601                         pSMB->InformationLevel =
3602                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3603                 else
3604                         pSMB->InformationLevel =
3605                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3606         } else /* Set File Size */  {    
3607             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3608                     pSMB->InformationLevel =
3609                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3610             else
3611                     pSMB->InformationLevel =
3612                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3613         }
3614         pSMB->Reserved4 = 0;
3615         pSMB->hdr.smb_buf_length += byte_count;
3616         pSMB->ByteCount = cpu_to_le16(byte_count);
3617         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3618                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3619         if (rc) {
3620                 cFYI(1,
3621                      ("Send error in SetFileInfo (SetFileSize) = %d",
3622                       rc));
3623         }
3624
3625         if (pSMB)
3626                 cifs_small_buf_release(pSMB);
3627
3628         /* Note: On -EAGAIN error only caller can retry on handle based calls 
3629                 since file handle passed in no longer valid */
3630
3631         return rc;
3632 }
3633
3634 /* Some legacy servers such as NT4 require that the file times be set on 
3635    an open handle, rather than by pathname - this is awkward due to
3636    potential access conflicts on the open, but it is unavoidable for these
3637    old servers since the only other choice is to go from 100 nanosecond DCE
3638    time and resort to the original setpathinfo level which takes the ancient
3639    DOS time format with 2 second granularity */
3640 int
3641 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
3642                    __u16 fid)
3643 {
3644         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
3645         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3646         char *data_offset;
3647         int rc = 0;
3648         int bytes_returned = 0;
3649         __u16 params, param_offset, offset, byte_count, count;
3650
3651         cFYI(1, ("Set Times (via SetFileInfo)"));
3652         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3653
3654         if (rc)
3655                 return rc;
3656
3657         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3658
3659         /* At this point there is no need to override the current pid
3660         with the pid of the opener, but that could change if we someday
3661         use an existing handle (rather than opening one on the fly) */
3662         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3663         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3664     
3665         params = 6;
3666         pSMB->MaxSetupCount = 0;
3667         pSMB->Reserved = 0;
3668         pSMB->Flags = 0;
3669         pSMB->Timeout = 0;
3670         pSMB->Reserved2 = 0;
3671         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3672         offset = param_offset + params;
3673
3674         data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
3675
3676         count = sizeof (FILE_BASIC_INFO);
3677         pSMB->MaxParameterCount = cpu_to_le16(2);
3678         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3679         pSMB->SetupCount = 1;
3680         pSMB->Reserved3 = 0;
3681         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3682         byte_count = 3 /* pad */  + params + count;
3683         pSMB->DataCount = cpu_to_le16(count);
3684         pSMB->ParameterCount = cpu_to_le16(params);
3685         pSMB->TotalDataCount = pSMB->DataCount;
3686         pSMB->TotalParameterCount = pSMB->ParameterCount;
3687         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3688         pSMB->DataOffset = cpu_to_le16(offset);
3689         pSMB->Fid = fid;
3690         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3691                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3692         else
3693                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3694         pSMB->Reserved4 = 0;
3695         pSMB->hdr.smb_buf_length += byte_count;
3696         pSMB->ByteCount = cpu_to_le16(byte_count);
3697         memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3698         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3699                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3700         if (rc) {
3701                 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3702         }
3703
3704         cifs_small_buf_release(pSMB);
3705
3706         /* Note: On -EAGAIN error only caller can retry on handle based calls 
3707                 since file handle passed in no longer valid */
3708
3709         return rc;
3710 }
3711
3712
3713 int
3714 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3715                 const FILE_BASIC_INFO * data, 
3716                 const struct nls_table *nls_codepage, int remap)
3717 {
3718         TRANSACTION2_SPI_REQ *pSMB = NULL;
3719         TRANSACTION2_SPI_RSP *pSMBr = NULL;
3720         int name_len;
3721         int rc = 0;
3722         int bytes_returned = 0;
3723         char *data_offset;
3724         __u16 params, param_offset, offset, byte_count, count;
3725
3726         cFYI(1, ("In SetTimes"));
3727
3728 SetTimesRetry:
3729         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3730                       (void **) &pSMBr);
3731         if (rc)
3732                 return rc;
3733
3734         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3735                 name_len =
3736                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3737                                      PATH_MAX, nls_codepage, remap);
3738                 name_len++;     /* trailing null */
3739                 name_len *= 2;
3740         } else {                /* BB improve the check for buffer overruns BB */
3741                 name_len = strnlen(fileName, PATH_MAX);
3742                 name_len++;     /* trailing null */
3743                 strncpy(pSMB->FileName, fileName, name_len);
3744         }
3745
3746         params = 6 + name_len;
3747         count = sizeof (FILE_BASIC_INFO);
3748         pSMB->MaxParameterCount = cpu_to_le16(2);
3749         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3750         pSMB->MaxSetupCount = 0;
3751         pSMB->Reserved = 0;
3752         pSMB->Flags = 0;
3753         pSMB->Timeout = 0;
3754         pSMB->Reserved2 = 0;
3755         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3756                                      InformationLevel) - 4;
3757         offset = param_offset + params;
3758         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3759         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3760         pSMB->DataOffset = cpu_to_le16(offset);
3761         pSMB->SetupCount = 1;
3762         pSMB->Reserved3 = 0;
3763         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3764         byte_count = 3 /* pad */  + params + count;
3765
3766         pSMB->DataCount = cpu_to_le16(count);
3767         pSMB->ParameterCount = cpu_to_le16(params);
3768         pSMB->TotalDataCount = pSMB->DataCount;
3769         pSMB->TotalParameterCount = pSMB->ParameterCount;
3770         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3771                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3772         else
3773                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3774         pSMB->Reserved4 = 0;
3775         pSMB->hdr.smb_buf_length += byte_count;
3776         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3777         pSMB->ByteCount = cpu_to_le16(byte_count);
3778         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3779                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3780         if (rc) {
3781                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3782         }
3783
3784         cifs_buf_release(pSMB);
3785
3786         if (rc == -EAGAIN)
3787                 goto SetTimesRetry;
3788
3789         return rc;
3790 }
3791
3792 /* Can not be used to set time stamps yet (due to old DOS time format) */
3793 /* Can be used to set attributes */
3794 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
3795           handling it anyway and NT4 was what we thought it would be needed for
3796           Do not delete it until we prove whether needed for Win9x though */
3797 int
3798 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3799                 __u16 dos_attrs, const struct nls_table *nls_codepage)
3800 {
3801         SETATTR_REQ *pSMB = NULL;
3802         SETATTR_RSP *pSMBr = NULL;
3803         int rc = 0;
3804         int bytes_returned;
3805         int name_len;
3806
3807         cFYI(1, ("In SetAttrLegacy"));
3808
3809 SetAttrLgcyRetry:
3810         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
3811                       (void **) &pSMBr);
3812         if (rc)
3813                 return rc;
3814
3815         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3816                 name_len =
3817                         ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
3818                                 PATH_MAX, nls_codepage);
3819                 name_len++;     /* trailing null */
3820                 name_len *= 2;
3821         } else {                /* BB improve the check for buffer overruns BB */
3822                 name_len = strnlen(fileName, PATH_MAX);
3823                 name_len++;     /* trailing null */
3824                 strncpy(pSMB->fileName, fileName, name_len);
3825         }
3826         pSMB->attr = cpu_to_le16(dos_attrs);
3827         pSMB->BufferFormat = 0x04;
3828         pSMB->hdr.smb_buf_length += name_len + 1;
3829         pSMB->ByteCount = cpu_to_le16(name_len + 1);
3830         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3831                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3832         if (rc) {
3833                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
3834         }
3835
3836         cifs_buf_release(pSMB);
3837
3838         if (rc == -EAGAIN)
3839                 goto SetAttrLgcyRetry;
3840
3841         return rc;
3842 }
3843 #endif /* temporarily unneeded SetAttr legacy function */
3844
3845 int
3846 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
3847                     char *fileName, __u64 mode, __u64 uid, __u64 gid, 
3848                     dev_t device, const struct nls_table *nls_codepage, 
3849                     int remap)
3850 {
3851         TRANSACTION2_SPI_REQ *pSMB = NULL;
3852         TRANSACTION2_SPI_RSP *pSMBr = NULL;
3853         int name_len;
3854         int rc = 0;
3855         int bytes_returned = 0;
3856         FILE_UNIX_BASIC_INFO *data_offset;
3857         __u16 params, param_offset, offset, count, byte_count;
3858
3859         cFYI(1, ("In SetUID/GID/Mode"));
3860 setPermsRetry:
3861         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3862                       (void **) &pSMBr);
3863         if (rc)
3864                 return rc;
3865
3866         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3867                 name_len =
3868                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
3869                                      PATH_MAX, nls_codepage, remap);
3870                 name_len++;     /* trailing null */
3871                 name_len *= 2;
3872         } else {                /* BB improve the check for buffer overruns BB */
3873                 name_len = strnlen(fileName, PATH_MAX);
3874                 name_len++;     /* trailing null */
3875                 strncpy(pSMB->FileName, fileName, name_len);
3876         }
3877
3878         params = 6 + name_len;
3879         count = sizeof (FILE_UNIX_BASIC_INFO);
3880         pSMB->MaxParameterCount = cpu_to_le16(2);
3881         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3882         pSMB->MaxSetupCount = 0;
3883         pSMB->Reserved = 0;
3884         pSMB->Flags = 0;
3885         pSMB->Timeout = 0;
3886         pSMB->Reserved2 = 0;
3887         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3888                                      InformationLevel) - 4;
3889         offset = param_offset + params;
3890         data_offset =
3891             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3892                                       offset);
3893         memset(data_offset, 0, count);
3894         pSMB->DataOffset = cpu_to_le16(offset);
3895         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3896         pSMB->SetupCount = 1;
3897         pSMB->Reserved3 = 0;
3898         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3899         byte_count = 3 /* pad */  + params + count;
3900         pSMB->ParameterCount = cpu_to_le16(params);
3901         pSMB->DataCount = cpu_to_le16(count);
3902         pSMB->TotalParameterCount = pSMB->ParameterCount;
3903         pSMB->TotalDataCount = pSMB->DataCount;
3904         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3905         pSMB->Reserved4 = 0;
3906         pSMB->hdr.smb_buf_length += byte_count;
3907         data_offset->Uid = cpu_to_le64(uid);
3908         data_offset->Gid = cpu_to_le64(gid);
3909         /* better to leave device as zero when it is  */
3910         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3911         data_offset->DevMinor = cpu_to_le64(MINOR(device));
3912         data_offset->Permissions = cpu_to_le64(mode);
3913     
3914         if(S_ISREG(mode))
3915                 data_offset->Type = cpu_to_le32(UNIX_FILE);
3916         else if(S_ISDIR(mode))
3917                 data_offset->Type = cpu_to_le32(UNIX_DIR);
3918         else if(S_ISLNK(mode))
3919                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3920         else if(S_ISCHR(mode))
3921                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3922         else if(S_ISBLK(mode))
3923                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3924         else if(S_ISFIFO(mode))
3925                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
3926         else if(S_ISSOCK(mode))
3927                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3928
3929
3930         pSMB->ByteCount = cpu_to_le16(byte_count);
3931         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3932                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3933         if (rc) {
3934                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3935         }
3936
3937         if (pSMB)
3938                 cifs_buf_release(pSMB);
3939         if (rc == -EAGAIN)
3940                 goto setPermsRetry;
3941         return rc;
3942 }
3943
3944 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
3945                         const int notify_subdirs, const __u16 netfid,
3946                         __u32 filter, const struct nls_table *nls_codepage)
3947 {
3948         int rc = 0;
3949         struct smb_com_transaction_change_notify_req * pSMB = NULL;
3950         struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
3951         int bytes_returned;
3952
3953         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3954         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3955                       (void **) &pSMBr);
3956         if (rc)
3957                 return rc;
3958
3959         pSMB->TotalParameterCount = 0 ;
3960         pSMB->TotalDataCount = 0;
3961         pSMB->MaxParameterCount = cpu_to_le32(2);
3962         /* BB find exact data count max from sess structure BB */
3963         pSMB->MaxDataCount = 0; /* same in little endian or be */
3964         pSMB->MaxSetupCount = 4;
3965         pSMB->Reserved = 0;
3966         pSMB->ParameterOffset = 0;
3967         pSMB->DataCount = 0;
3968         pSMB->DataOffset = 0;
3969         pSMB->SetupCount = 4; /* single byte does not need le conversion */
3970         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
3971         pSMB->ParameterCount = pSMB->TotalParameterCount;
3972         if(notify_subdirs)
3973                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
3974         pSMB->Reserved2 = 0;
3975         pSMB->CompletionFilter = cpu_to_le32(filter);
3976         pSMB->Fid = netfid; /* file handle always le */
3977         pSMB->ByteCount = 0;
3978
3979         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3980                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
3981         if (rc) {
3982                 cFYI(1, ("Error in Notify = %d", rc));
3983         }
3984         cifs_buf_release(pSMB);
3985         return rc;      
3986 }
3987 #ifdef CONFIG_CIFS_XATTR
3988 ssize_t
3989 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3990                  const unsigned char *searchName,
3991                  char * EAData, size_t buf_size,
3992                  const struct nls_table *nls_codepage, int remap)
3993 {
3994                 /* BB assumes one setup word */
3995         TRANSACTION2_QPI_REQ *pSMB = NULL;
3996         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3997         int rc = 0;
3998         int bytes_returned;
3999         int name_len;
4000         struct fea * temp_fea;
4001         char * temp_ptr;
4002         __u16 params, byte_count;
4003
4004         cFYI(1, ("In Query All EAs path %s", searchName));
4005 QAllEAsRetry:
4006         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4007                       (void **) &pSMBr);
4008         if (rc)
4009                 return rc;
4010
4011         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4012                 name_len =
4013                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4014                                      PATH_MAX, nls_codepage, remap);
4015                 name_len++;     /* trailing null */
4016                 name_len *= 2;
4017         } else {        /* BB improve the check for buffer overruns BB */
4018                 name_len = strnlen(searchName, PATH_MAX);
4019                 name_len++;     /* trailing null */
4020                 strncpy(pSMB->FileName, searchName, name_len);
4021         }
4022
4023         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4024         pSMB->TotalDataCount = 0;
4025         pSMB->MaxParameterCount = cpu_to_le16(2);
4026         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4027         pSMB->MaxSetupCount = 0;
4028         pSMB->Reserved = 0;
4029         pSMB->Flags = 0;
4030         pSMB->Timeout = 0;
4031         pSMB->Reserved2 = 0;
4032         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4033         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4034         pSMB->DataCount = 0;
4035         pSMB->DataOffset = 0;
4036         pSMB->SetupCount = 1;
4037         pSMB->Reserved3 = 0;
4038         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4039         byte_count = params + 1 /* pad */ ;
4040         pSMB->TotalParameterCount = cpu_to_le16(params);
4041         pSMB->ParameterCount = pSMB->TotalParameterCount;
4042         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4043         pSMB->Reserved4 = 0;
4044         pSMB->hdr.smb_buf_length += byte_count;
4045         pSMB->ByteCount = cpu_to_le16(byte_count);
4046
4047         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4048                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4049         if (rc) {
4050                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4051         } else {                /* decode response */
4052                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4053
4054                 /* BB also check enough total bytes returned */
4055                 /* BB we need to improve the validity checking
4056                 of these trans2 responses */
4057                 if (rc || (pSMBr->ByteCount < 4)) 
4058                         rc = -EIO;      /* bad smb */
4059            /* else if (pFindData){
4060                         memcpy((char *) pFindData,
4061                                (char *) &pSMBr->hdr.Protocol +
4062                                data_offset, kl);
4063                 }*/ else {
4064                         /* check that length of list is not more than bcc */
4065                         /* check that each entry does not go beyond length
4066                            of list */
4067                         /* check that each element of each entry does not
4068                            go beyond end of list */
4069                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4070                         struct fealist * ea_response_data;
4071                         rc = 0;
4072                         /* validate_trans2_offsets() */
4073                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4074                         ea_response_data = (struct fealist *)
4075                                 (((char *) &pSMBr->hdr.Protocol) +
4076                                 data_offset);
4077                         name_len = le32_to_cpu(ea_response_data->list_len);
4078                         cFYI(1,("ea length %d", name_len));
4079                         if(name_len <= 8) {
4080                         /* returned EA size zeroed at top of function */
4081                                 cFYI(1,("empty EA list returned from server"));
4082                         } else {
4083                                 /* account for ea list len */
4084                                 name_len -= 4;
4085                                 temp_fea = ea_response_data->list;
4086                                 temp_ptr = (char *)temp_fea;
4087                                 while(name_len > 0) {
4088                                         __u16 value_len;
4089                                         name_len -= 4;
4090                                         temp_ptr += 4;
4091                                         rc += temp_fea->name_len;
4092                                 /* account for prefix user. and trailing null */
4093                                         rc = rc + 5 + 1; 
4094                                         if(rc<(int)buf_size) {
4095                                                 memcpy(EAData,"user.",5);
4096                                                 EAData+=5;
4097                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
4098                                                 EAData+=temp_fea->name_len;
4099                                                 /* null terminate name */
4100                                                 *EAData = 0;
4101                                                 EAData = EAData + 1;
4102                                         } else if(buf_size == 0) {
4103                                                 /* skip copy - calc size only */
4104                                         } else {
4105                                                 /* stop before overrun buffer */
4106                                                 rc = -ERANGE;
4107                                                 break;
4108                                         }
4109                                         name_len -= temp_fea->name_len;
4110                                         temp_ptr += temp_fea->name_len;
4111                                         /* account for trailing null */
4112                                         name_len--;
4113                                         temp_ptr++;
4114                                         value_len = le16_to_cpu(temp_fea->value_len);
4115                                         name_len -= value_len;
4116                                         temp_ptr += value_len;
4117                                         /* BB check that temp_ptr is still within smb BB*/
4118                                 /* no trailing null to account for in value len */
4119                                         /* go on to next EA */
4120                                         temp_fea = (struct fea *)temp_ptr;
4121                                 }
4122                         }
4123                 }
4124         }
4125         if (pSMB)
4126                 cifs_buf_release(pSMB);
4127         if (rc == -EAGAIN)
4128                 goto QAllEAsRetry;
4129
4130         return (ssize_t)rc;
4131 }
4132
4133 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4134                 const unsigned char * searchName,const unsigned char * ea_name,
4135                 unsigned char * ea_value, size_t buf_size, 
4136                 const struct nls_table *nls_codepage, int remap)
4137 {
4138         TRANSACTION2_QPI_REQ *pSMB = NULL;
4139         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4140         int rc = 0;
4141         int bytes_returned;
4142         int name_len;
4143         struct fea * temp_fea;
4144         char * temp_ptr;
4145         __u16 params, byte_count;
4146
4147         cFYI(1, ("In Query EA path %s", searchName));
4148 QEARetry:
4149         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4150                       (void **) &pSMBr);
4151         if (rc)
4152                 return rc;
4153
4154         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4155                 name_len =
4156                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4157                                      PATH_MAX, nls_codepage, remap);
4158                 name_len++;     /* trailing null */
4159                 name_len *= 2;
4160         } else {        /* BB improve the check for buffer overruns BB */
4161                 name_len = strnlen(searchName, PATH_MAX);
4162                 name_len++;     /* trailing null */
4163                 strncpy(pSMB->FileName, searchName, name_len);
4164         }
4165
4166         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4167         pSMB->TotalDataCount = 0;
4168         pSMB->MaxParameterCount = cpu_to_le16(2);
4169         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4170         pSMB->MaxSetupCount = 0;
4171         pSMB->Reserved = 0;
4172         pSMB->Flags = 0;
4173         pSMB->Timeout = 0;
4174         pSMB->Reserved2 = 0;
4175         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4176         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4177         pSMB->DataCount = 0;
4178         pSMB->DataOffset = 0;
4179         pSMB->SetupCount = 1;
4180         pSMB->Reserved3 = 0;
4181         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4182         byte_count = params + 1 /* pad */ ;
4183         pSMB->TotalParameterCount = cpu_to_le16(params);
4184         pSMB->ParameterCount = pSMB->TotalParameterCount;
4185         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4186         pSMB->Reserved4 = 0;
4187         pSMB->hdr.smb_buf_length += byte_count;
4188         pSMB->ByteCount = cpu_to_le16(byte_count);
4189
4190         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4191                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4192         if (rc) {
4193                 cFYI(1, ("Send error in Query EA = %d", rc));
4194         } else {                /* decode response */
4195                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4196
4197                 /* BB also check enough total bytes returned */
4198                 /* BB we need to improve the validity checking
4199                 of these trans2 responses */
4200                 if (rc || (pSMBr->ByteCount < 4)) 
4201                         rc = -EIO;      /* bad smb */
4202            /* else if (pFindData){
4203                         memcpy((char *) pFindData,
4204                                (char *) &pSMBr->hdr.Protocol +
4205                                data_offset, kl);
4206                 }*/ else {
4207                         /* check that length of list is not more than bcc */
4208                         /* check that each entry does not go beyond length
4209                            of list */
4210                         /* check that each element of each entry does not
4211                            go beyond end of list */
4212                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4213                         struct fealist * ea_response_data;
4214                         rc = -ENODATA;
4215                         /* validate_trans2_offsets() */
4216                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4217                         ea_response_data = (struct fealist *)
4218                                 (((char *) &pSMBr->hdr.Protocol) +
4219                                 data_offset);
4220                         name_len = le32_to_cpu(ea_response_data->list_len);
4221                         cFYI(1,("ea length %d", name_len));
4222                         if(name_len <= 8) {
4223                         /* returned EA size zeroed at top of function */
4224                                 cFYI(1,("empty EA list returned from server"));
4225                         } else {
4226                                 /* account for ea list len */
4227                                 name_len -= 4;
4228                                 temp_fea = ea_response_data->list;
4229                                 temp_ptr = (char *)temp_fea;
4230                                 /* loop through checking if we have a matching
4231                                 name and then return the associated value */
4232                                 while(name_len > 0) {
4233                                         __u16 value_len;
4234                                         name_len -= 4;
4235                                         temp_ptr += 4;
4236                                         value_len = le16_to_cpu(temp_fea->value_len);
4237                                 /* BB validate that value_len falls within SMB, 
4238                                 even though maximum for name_len is 255 */ 
4239                                         if(memcmp(temp_fea->name,ea_name,
4240                                                   temp_fea->name_len) == 0) {
4241                                                 /* found a match */
4242                                                 rc = value_len;
4243                                 /* account for prefix user. and trailing null */
4244                                                 if(rc<=(int)buf_size) {
4245                                                         memcpy(ea_value,
4246                                                                 temp_fea->name+temp_fea->name_len+1,
4247                                                                 rc);
4248                                                         /* ea values, unlike ea names,
4249                                                         are not null terminated */
4250                                                 } else if(buf_size == 0) {
4251                                                 /* skip copy - calc size only */
4252                                                 } else {
4253                                                         /* stop before overrun buffer */
4254                                                         rc = -ERANGE;
4255                                                 }
4256                                                 break;
4257                                         }
4258                                         name_len -= temp_fea->name_len;
4259                                         temp_ptr += temp_fea->name_len;
4260                                         /* account for trailing null */
4261                                         name_len--;
4262                                         temp_ptr++;
4263                                         name_len -= value_len;
4264                                         temp_ptr += value_len;
4265                                 /* no trailing null to account for in value len */
4266                                         /* go on to next EA */
4267                                         temp_fea = (struct fea *)temp_ptr;
4268                                 }
4269                         } 
4270                 }
4271         }
4272         if (pSMB)
4273                 cifs_buf_release(pSMB);
4274         if (rc == -EAGAIN)
4275                 goto QEARetry;
4276
4277         return (ssize_t)rc;
4278 }
4279
4280 int
4281 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4282                 const char * ea_name, const void * ea_value, 
4283                 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4284                 int remap)
4285 {
4286         struct smb_com_transaction2_spi_req *pSMB = NULL;
4287         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4288         struct fealist *parm_data;
4289         int name_len;
4290         int rc = 0;
4291         int bytes_returned = 0;
4292         __u16 params, param_offset, byte_count, offset, count;
4293
4294         cFYI(1, ("In SetEA"));
4295 SetEARetry:
4296         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4297                       (void **) &pSMBr);
4298         if (rc)
4299                 return rc;
4300
4301         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4302                 name_len =
4303                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4304                                      PATH_MAX, nls_codepage, remap);
4305                 name_len++;     /* trailing null */
4306                 name_len *= 2;
4307         } else {                /* BB improve the check for buffer overruns BB */
4308                 name_len = strnlen(fileName, PATH_MAX);
4309                 name_len++;     /* trailing null */
4310                 strncpy(pSMB->FileName, fileName, name_len);
4311         }
4312
4313         params = 6 + name_len;
4314
4315         /* done calculating parms using name_len of file name,
4316         now use name_len to calculate length of ea name
4317         we are going to create in the inode xattrs */
4318         if(ea_name == NULL)
4319                 name_len = 0;
4320         else
4321                 name_len = strnlen(ea_name,255);
4322
4323         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4324         pSMB->MaxParameterCount = cpu_to_le16(2);
4325         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4326         pSMB->MaxSetupCount = 0;
4327         pSMB->Reserved = 0;
4328         pSMB->Flags = 0;
4329         pSMB->Timeout = 0;
4330         pSMB->Reserved2 = 0;
4331         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4332                                      InformationLevel) - 4;
4333         offset = param_offset + params;
4334         pSMB->InformationLevel =
4335                 cpu_to_le16(SMB_SET_FILE_EA);
4336
4337         parm_data =
4338                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4339                                        offset);
4340         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4341         pSMB->DataOffset = cpu_to_le16(offset);
4342         pSMB->SetupCount = 1;
4343         pSMB->Reserved3 = 0;
4344         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4345         byte_count = 3 /* pad */  + params + count;
4346         pSMB->DataCount = cpu_to_le16(count);
4347         parm_data->list_len = cpu_to_le32(count);
4348         parm_data->list[0].EA_flags = 0;
4349         /* we checked above that name len is less than 255 */
4350         parm_data->list[0].name_len = (__u8)name_len;;
4351         /* EA names are always ASCII */
4352         if(ea_name)
4353                 strncpy(parm_data->list[0].name,ea_name,name_len);
4354         parm_data->list[0].name[name_len] = 0;
4355         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4356         /* caller ensures that ea_value_len is less than 64K but
4357         we need to ensure that it fits within the smb */
4358
4359         /*BB add length check that it would fit in negotiated SMB buffer size BB */
4360         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4361         if(ea_value_len)
4362                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4363
4364         pSMB->TotalDataCount = pSMB->DataCount;
4365         pSMB->ParameterCount = cpu_to_le16(params);
4366         pSMB->TotalParameterCount = pSMB->ParameterCount;
4367         pSMB->Reserved4 = 0;
4368         pSMB->hdr.smb_buf_length += byte_count;
4369         pSMB->ByteCount = cpu_to_le16(byte_count);
4370         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4371                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4372         if (rc) {
4373                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4374         }
4375
4376         cifs_buf_release(pSMB);
4377
4378         if (rc == -EAGAIN)
4379                 goto SetEARetry;
4380
4381         return rc;
4382 }
4383
4384 #endif