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