[CIFS] Avoid extra large buffer allocation (and memcpy) in cifs_readpages
[sfrench/cifs-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->tidStatus == CifsExiting) {
94                         /* only tree disconnect, open, and write,
95                         (and ulogoff which does not have tcon)
96                         are allowed as we start force umount */
97                         if((smb_command != SMB_COM_WRITE_ANDX) && 
98                            (smb_command != SMB_COM_OPEN_ANDX) && 
99                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
100                                 cFYI(1,("can not send cmd %d while umounting",
101                                         smb_command));
102                                 return -ENODEV;
103                         }
104                 }
105                 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
106                                   (tcon->ses->server)){
107                         struct nls_table *nls_codepage;
108                                 /* Give Demultiplex thread up to 10 seconds to 
109                                    reconnect, should be greater than cifs socket
110                                    timeout which is 7 seconds */
111                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
112                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
113                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
114                                 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
115                                         /* on "soft" mounts we wait once */
116                                         if((tcon->retry == FALSE) || 
117                                            (tcon->ses->status == CifsExiting)) {
118                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
119                                                 return -EHOSTDOWN;
120                                         } /* else "hard" mount - keep retrying
121                                              until process is killed or server
122                                              comes back on-line */
123                                 } else /* TCP session is reestablished now */
124                                         break;
125                                  
126                         }
127                         
128                         nls_codepage = load_nls_default();
129                 /* need to prevent multiple threads trying to
130                 simultaneously reconnect the same SMB session */
131                         down(&tcon->ses->sesSem);
132                         if(tcon->ses->status == CifsNeedReconnect)
133                                 rc = cifs_setup_session(0, tcon->ses, 
134                                                         nls_codepage);
135                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
136                                 mark_open_files_invalid(tcon);
137                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
138                                         , nls_codepage);
139                                 up(&tcon->ses->sesSem);
140                                 /* BB FIXME add code to check if wsize needs
141                                    update due to negotiated smb buffer size
142                                    shrinking */
143                                 if(rc == 0)
144                                         atomic_inc(&tconInfoReconnectCount);
145
146                                 cFYI(1, ("reconnect tcon rc = %d", rc));
147                                 /* Removed call to reopen open files here - 
148                                    it is safer (and faster) to reopen files
149                                    one at a time as needed in read and write */
150
151                                 /* Check if handle based operation so we 
152                                    know whether we can continue or not without
153                                    returning to caller to reset file handle */
154                                 switch(smb_command) {
155                                         case SMB_COM_READ_ANDX:
156                                         case SMB_COM_WRITE_ANDX:
157                                         case SMB_COM_CLOSE:
158                                         case SMB_COM_FIND_CLOSE2:
159                                         case SMB_COM_LOCKING_ANDX: {
160                                                 unload_nls(nls_codepage);
161                                                 return -EAGAIN;
162                                         }
163                                 }
164                         } else {
165                                 up(&tcon->ses->sesSem);
166                         }
167                         unload_nls(nls_codepage);
168
169                 } else {
170                         return -EIO;
171                 }
172         }
173         if(rc)
174                 return rc;
175
176         *request_buf = cifs_small_buf_get();
177         if (*request_buf == NULL) {
178                 /* BB should we add a retry in here if not a writepage? */
179                 return -ENOMEM;
180         }
181
182         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
183
184         if(tcon != NULL)
185                 cifs_stats_inc(&tcon->num_smbs_sent);
186
187         return rc;
188 }  
189
190 /* If the return code is zero, this function must fill in request_buf pointer */
191 static int
192 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
193          void **request_buf /* returned */ ,
194          void **response_buf /* returned */ )
195 {
196         int rc = 0;
197
198         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
199            check for tcp and smb session status done differently
200            for those three - in the calling routine */
201         if(tcon) {
202                 if(tcon->tidStatus == CifsExiting) {
203                         /* only tree disconnect, open, and write,
204                           (and ulogoff which does not have tcon)
205                           are allowed as we start force umount */
206                         if((smb_command != SMB_COM_WRITE_ANDX) &&
207                            (smb_command != SMB_COM_OPEN_ANDX) &&
208                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
209                                 cFYI(1,("can not send cmd %d while umounting",
210                                         smb_command));
211                                 return -ENODEV;
212                         }
213                 }
214
215                 if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
216                                   (tcon->ses->server)){
217                         struct nls_table *nls_codepage;
218                                 /* Give Demultiplex thread up to 10 seconds to
219                                    reconnect, should be greater than cifs socket
220                                    timeout which is 7 seconds */
221                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
222                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
223                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
224                                 if(tcon->ses->server->tcpStatus == 
225                                                 CifsNeedReconnect) {
226                                         /* on "soft" mounts we wait once */
227                                         if((tcon->retry == FALSE) || 
228                                            (tcon->ses->status == CifsExiting)) {
229                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
230                                                 return -EHOSTDOWN;
231                                         } /* else "hard" mount - keep retrying
232                                              until process is killed or server
233                                              comes on-line */
234                                 } else /* TCP session is reestablished now */
235                                         break;
236                                  
237                         }
238                         
239                         nls_codepage = load_nls_default();
240                 /* need to prevent multiple threads trying to
241                 simultaneously reconnect the same SMB session */
242                         down(&tcon->ses->sesSem);
243                         if(tcon->ses->status == CifsNeedReconnect)
244                                 rc = cifs_setup_session(0, tcon->ses, 
245                                                         nls_codepage);
246                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
247                                 mark_open_files_invalid(tcon);
248                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
249                                               tcon, nls_codepage);
250                                 up(&tcon->ses->sesSem);
251                                 /* BB FIXME add code to check if wsize needs
252                                 update due to negotiated smb buffer size
253                                 shrinking */
254                                 if(rc == 0)
255                                         atomic_inc(&tconInfoReconnectCount);
256
257                                 cFYI(1, ("reconnect tcon rc = %d", rc));
258                                 /* Removed call to reopen open files here - 
259                                    it is safer (and faster) to reopen files
260                                    one at a time as needed in read and write */
261
262                                 /* Check if handle based operation so we 
263                                    know whether we can continue or not without
264                                    returning to caller to reset file handle */
265                                 switch(smb_command) {
266                                         case SMB_COM_READ_ANDX:
267                                         case SMB_COM_WRITE_ANDX:
268                                         case SMB_COM_CLOSE:
269                                         case SMB_COM_FIND_CLOSE2:
270                                         case SMB_COM_LOCKING_ANDX: {
271                                                 unload_nls(nls_codepage);
272                                                 return -EAGAIN;
273                                         }
274                                 }
275                         } else {
276                                 up(&tcon->ses->sesSem);
277                         }
278                         unload_nls(nls_codepage);
279
280                 } else {
281                         return -EIO;
282                 }
283         }
284         if(rc)
285                 return rc;
286
287         *request_buf = cifs_buf_get();
288         if (*request_buf == NULL) {
289                 /* BB should we add a retry in here if not a writepage? */
290                 return -ENOMEM;
291         }
292     /* Although the original thought was we needed the response buf for  */
293     /* potential retries of smb operations it turns out we can determine */
294     /* from the mid flags when the request buffer can be resent without  */
295     /* having to use a second distinct buffer for the response */
296         *response_buf = *request_buf; 
297
298         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
299                         wct /*wct */ );
300
301         if(tcon != NULL)
302                 cifs_stats_inc(&tcon->num_smbs_sent);
303
304         return rc;
305 }
306
307 static int validate_t2(struct smb_t2_rsp * pSMB) 
308 {
309         int rc = -EINVAL;
310         int total_size;
311         char * pBCC;
312
313         /* check for plausible wct, bcc and t2 data and parm sizes */
314         /* check for parm and data offset going beyond end of smb */
315         if(pSMB->hdr.WordCount >= 10) {
316                 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
317                    (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
318                         /* check that bcc is at least as big as parms + data */
319                         /* check that bcc is less than negotiated smb buffer */
320                         total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
321                         if(total_size < 512) {
322                                 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
323                                 /* BCC le converted in SendReceive */
324                                 pBCC = (pSMB->hdr.WordCount * 2) + 
325                                         sizeof(struct smb_hdr) +
326                                         (char *)pSMB;
327                                 if((total_size <= (*(u16 *)pBCC)) && 
328                                    (total_size < 
329                                         CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
330                                         return 0;
331                                 }
332                                 
333                         }
334                 }
335         }
336         cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
337                 sizeof(struct smb_t2_rsp) + 16);
338         return rc;
339 }
340 int
341 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
342 {
343         NEGOTIATE_REQ *pSMB;
344         NEGOTIATE_RSP *pSMBr;
345         int rc = 0;
346         int bytes_returned;
347         struct TCP_Server_Info * server;
348         u16 count;
349
350         if(ses->server)
351                 server = ses->server;
352         else {
353                 rc = -EIO;
354                 return rc;
355         }
356         rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
357                       (void **) &pSMB, (void **) &pSMBr);
358         if (rc)
359                 return rc;
360         pSMB->hdr.Mid = GetNextMid(server);
361         pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
362         if (extended_security)
363                 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
364
365         count = strlen(protocols[0].name) + 1;
366         strncpy(pSMB->DialectsArray, protocols[0].name, 30);    
367     /* null guaranteed to be at end of source and target buffers anyway */
368
369         pSMB->hdr.smb_buf_length += count;
370         pSMB->ByteCount = cpu_to_le16(count);
371
372         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
373                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
374         if (rc == 0) {
375                 server->secMode = pSMBr->SecurityMode;  
376                 server->secType = NTLM; /* BB override default for 
377                                            NTLMv2 or kerberos v5 */
378                 /* one byte - no need to convert this or EncryptionKeyLen
379                    from little endian */
380                 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
381                 /* probably no need to store and check maxvcs */
382                 server->maxBuf =
383                         min(le32_to_cpu(pSMBr->MaxBufferSize),
384                         (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
385                 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
386                 cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
387                 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
388                 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
389                 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
390         /* BB with UTC do we ever need to be using srvr timezone? */
391                 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
392                         memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
393                                CIFS_CRYPTO_KEY_SIZE);
394                 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
395                            && (pSMBr->EncryptionKeyLength == 0)) {
396                         /* decode security blob */
397                 } else
398                         rc = -EIO;
399
400                 /* BB might be helpful to save off the domain of server here */
401
402                 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
403                         (server->capabilities & CAP_EXTENDED_SECURITY)) {
404                         count = pSMBr->ByteCount;
405                         if (count < 16)
406                                 rc = -EIO;
407                         else if (count == 16) {
408                                 server->secType = RawNTLMSSP;
409                                 if (server->socketUseCount.counter > 1) {
410                                         if (memcmp
411                                                 (server->server_GUID,
412                                                 pSMBr->u.extended_response.
413                                                 GUID, 16) != 0) {
414                                                 cFYI(1,
415                                                      ("UID of server does not match previous connection to same ip address"));
416                                                 memcpy(server->
417                                                         server_GUID,
418                                                         pSMBr->u.
419                                                         extended_response.
420                                                         GUID, 16);
421                                         }
422                                 } else
423                                         memcpy(server->server_GUID,
424                                                pSMBr->u.extended_response.
425                                                GUID, 16);
426                         } else {
427                                 rc = decode_negTokenInit(pSMBr->u.
428                                                          extended_response.
429                                                          SecurityBlob,
430                                                          count - 16,
431                                                          &server->secType);
432                                 if(rc == 1) {
433                                 /* BB Need to fill struct for sessetup here */
434                                         rc = -EOPNOTSUPP;
435                                 } else {
436                                         rc = -EINVAL;
437                                 }
438                         }
439                 } else
440                         server->capabilities &= ~CAP_EXTENDED_SECURITY;
441                 if(sign_CIFS_PDUs == FALSE) {        
442                         if(server->secMode & SECMODE_SIGN_REQUIRED)
443                                 cERROR(1,
444                                  ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
445                         server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
446                 } else if(sign_CIFS_PDUs == 1) {
447                         if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
448                                 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
449                 }
450                                 
451         }
452         
453         cifs_buf_release(pSMB);
454         return rc;
455 }
456
457 int
458 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
459 {
460         struct smb_hdr *smb_buffer;
461         struct smb_hdr *smb_buffer_response; /* BB removeme BB */
462         int rc = 0;
463         int length;
464
465         cFYI(1, ("In tree disconnect"));
466         /*
467          *  If last user of the connection and
468          *  connection alive - disconnect it
469          *  If this is the last connection on the server session disconnect it
470          *  (and inside session disconnect we should check if tcp socket needs 
471          *  to be freed and kernel thread woken up).
472          */
473         if (tcon)
474                 down(&tcon->tconSem);
475         else
476                 return -EIO;
477
478         atomic_dec(&tcon->useCount);
479         if (atomic_read(&tcon->useCount) > 0) {
480                 up(&tcon->tconSem);
481                 return -EBUSY;
482         }
483
484         /* No need to return error on this operation if tid invalidated and 
485         closed on server already e.g. due to tcp session crashing */
486         if(tcon->tidStatus == CifsNeedReconnect) {
487                 up(&tcon->tconSem);
488                 return 0;  
489         }
490
491         if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {    
492                 up(&tcon->tconSem);
493                 return -EIO;
494         }
495         rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 
496                             (void **)&smb_buffer);
497         if (rc) {
498                 up(&tcon->tconSem);
499                 return rc;
500         } else {
501                 smb_buffer_response = smb_buffer; /* BB removeme BB */
502         }
503         rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
504                          &length, 0);
505         if (rc)
506                 cFYI(1, ("Tree disconnect failed %d", rc));
507
508         if (smb_buffer)
509                 cifs_small_buf_release(smb_buffer);
510         up(&tcon->tconSem);
511
512         /* No need to return error on this operation if tid invalidated and 
513         closed on server already e.g. due to tcp session crashing */
514         if (rc == -EAGAIN)
515                 rc = 0;
516
517         return rc;
518 }
519
520 int
521 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
522 {
523         struct smb_hdr *smb_buffer_response;
524         LOGOFF_ANDX_REQ *pSMB;
525         int rc = 0;
526         int length;
527
528         cFYI(1, ("In SMBLogoff for session disconnect"));
529         if (ses)
530                 down(&ses->sesSem);
531         else
532                 return -EIO;
533
534         atomic_dec(&ses->inUse);
535         if (atomic_read(&ses->inUse) > 0) {
536                 up(&ses->sesSem);
537                 return -EBUSY;
538         }
539         rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
540         if (rc) {
541                 up(&ses->sesSem);
542                 return rc;
543         }
544
545         smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
546         
547         if(ses->server) {
548                 pSMB->hdr.Mid = GetNextMid(ses->server);
549
550                 if(ses->server->secMode & 
551                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
552                         pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
553         }
554
555         pSMB->hdr.Uid = ses->Suid;
556
557         pSMB->AndXCommand = 0xFF;
558         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
559                          smb_buffer_response, &length, 0);
560         if (ses->server) {
561                 atomic_dec(&ses->server->socketUseCount);
562                 if (atomic_read(&ses->server->socketUseCount) == 0) {
563                         spin_lock(&GlobalMid_Lock);
564                         ses->server->tcpStatus = CifsExiting;
565                         spin_unlock(&GlobalMid_Lock);
566                         rc = -ESHUTDOWN;
567                 }
568         }
569         up(&ses->sesSem);
570         cifs_small_buf_release(pSMB);
571
572         /* if session dead then we do not need to do ulogoff,
573                 since server closed smb session, no sense reporting 
574                 error */
575         if (rc == -EAGAIN)
576                 rc = 0;
577         return rc;
578 }
579
580 int
581 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
582                const struct nls_table *nls_codepage, int remap)
583 {
584         DELETE_FILE_REQ *pSMB = NULL;
585         DELETE_FILE_RSP *pSMBr = NULL;
586         int rc = 0;
587         int bytes_returned;
588         int name_len;
589
590 DelFileRetry:
591         rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
592                       (void **) &pSMBr);
593         if (rc)
594                 return rc;
595
596         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
597                 name_len =
598                     cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, 
599                                      PATH_MAX, nls_codepage, remap);
600                 name_len++;     /* trailing null */
601                 name_len *= 2;
602         } else {                /* BB improve check for buffer overruns BB */
603                 name_len = strnlen(fileName, PATH_MAX);
604                 name_len++;     /* trailing null */
605                 strncpy(pSMB->fileName, fileName, name_len);
606         }
607         pSMB->SearchAttributes =
608             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
609         pSMB->BufferFormat = 0x04;
610         pSMB->hdr.smb_buf_length += name_len + 1;
611         pSMB->ByteCount = cpu_to_le16(name_len + 1);
612         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
613                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
614         cifs_stats_inc(&tcon->num_deletes);
615         if (rc) {
616                 cFYI(1, ("Error in RMFile = %d", rc));
617         } 
618
619         cifs_buf_release(pSMB);
620         if (rc == -EAGAIN)
621                 goto DelFileRetry;
622
623         return rc;
624 }
625
626 int
627 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, 
628              const struct nls_table *nls_codepage, int remap)
629 {
630         DELETE_DIRECTORY_REQ *pSMB = NULL;
631         DELETE_DIRECTORY_RSP *pSMBr = NULL;
632         int rc = 0;
633         int bytes_returned;
634         int name_len;
635
636         cFYI(1, ("In CIFSSMBRmDir"));
637 RmDirRetry:
638         rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
639                       (void **) &pSMBr);
640         if (rc)
641                 return rc;
642
643         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
644                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
645                                          PATH_MAX, nls_codepage, remap);
646                 name_len++;     /* trailing null */
647                 name_len *= 2;
648         } else {                /* BB improve check for buffer overruns BB */
649                 name_len = strnlen(dirName, PATH_MAX);
650                 name_len++;     /* trailing null */
651                 strncpy(pSMB->DirName, dirName, name_len);
652         }
653
654         pSMB->BufferFormat = 0x04;
655         pSMB->hdr.smb_buf_length += name_len + 1;
656         pSMB->ByteCount = cpu_to_le16(name_len + 1);
657         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
658                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
659         cifs_stats_inc(&tcon->num_rmdirs);
660         if (rc) {
661                 cFYI(1, ("Error in RMDir = %d", rc));
662         }
663
664         cifs_buf_release(pSMB);
665         if (rc == -EAGAIN)
666                 goto RmDirRetry;
667         return rc;
668 }
669
670 int
671 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
672              const char *name, const struct nls_table *nls_codepage, int remap)
673 {
674         int rc = 0;
675         CREATE_DIRECTORY_REQ *pSMB = NULL;
676         CREATE_DIRECTORY_RSP *pSMBr = NULL;
677         int bytes_returned;
678         int name_len;
679
680         cFYI(1, ("In CIFSSMBMkDir"));
681 MkDirRetry:
682         rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
683                       (void **) &pSMBr);
684         if (rc)
685                 return rc;
686
687         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
688                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, 
689                                             PATH_MAX, nls_codepage, remap);
690                 name_len++;     /* trailing null */
691                 name_len *= 2;
692         } else {                /* BB improve check for buffer overruns BB */
693                 name_len = strnlen(name, PATH_MAX);
694                 name_len++;     /* trailing null */
695                 strncpy(pSMB->DirName, name, name_len);
696         }
697
698         pSMB->BufferFormat = 0x04;
699         pSMB->hdr.smb_buf_length += name_len + 1;
700         pSMB->ByteCount = cpu_to_le16(name_len + 1);
701         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
702                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
703         cifs_stats_inc(&tcon->num_mkdirs);
704         if (rc) {
705                 cFYI(1, ("Error in Mkdir = %d", rc));
706         }
707
708         cifs_buf_release(pSMB);
709         if (rc == -EAGAIN)
710                 goto MkDirRetry;
711         return rc;
712 }
713
714 static __u16 convert_disposition(int disposition)
715 {
716         __u16 ofun = 0;
717
718         switch (disposition) {
719                 case FILE_SUPERSEDE:
720                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
721                         break;
722                 case FILE_OPEN:
723                         ofun = SMBOPEN_OAPPEND;
724                         break;
725                 case FILE_CREATE:
726                         ofun = SMBOPEN_OCREATE;
727                         break;
728                 case FILE_OPEN_IF:
729                         ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
730                         break;
731                 case FILE_OVERWRITE:
732                         ofun = SMBOPEN_OTRUNC;
733                         break;
734                 case FILE_OVERWRITE_IF:
735                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
736                         break;
737                 default:
738                         cFYI(1,("unknown disposition %d",disposition));
739                         ofun =  SMBOPEN_OAPPEND; /* regular open */
740         }
741         return ofun;
742 }
743
744 int
745 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
746             const char *fileName, const int openDisposition,
747             const int access_flags, const int create_options, __u16 * netfid,
748             int *pOplock, FILE_ALL_INFO * pfile_info,
749             const struct nls_table *nls_codepage, int remap)
750 {
751         int rc = -EACCES;
752         OPENX_REQ *pSMB = NULL;
753         OPENX_RSP *pSMBr = NULL;
754         int bytes_returned;
755         int name_len;
756         __u16 count;
757
758 OldOpenRetry:
759         rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
760                       (void **) &pSMBr);
761         if (rc)
762                 return rc;
763
764         pSMB->AndXCommand = 0xFF;       /* none */
765
766         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
767                 count = 1;      /* account for one byte pad to word boundary */
768                 name_len =
769                    cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
770                                     fileName, PATH_MAX, nls_codepage, remap);
771                 name_len++;     /* trailing null */
772                 name_len *= 2;
773         } else {                /* BB improve check for buffer overruns BB */
774                 count = 0;      /* no pad */
775                 name_len = strnlen(fileName, PATH_MAX);
776                 name_len++;     /* trailing null */
777                 strncpy(pSMB->fileName, fileName, name_len);
778         }
779         if (*pOplock & REQ_OPLOCK)
780                 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
781         else if (*pOplock & REQ_BATCHOPLOCK) {
782                 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
783         }
784         pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
785         /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
786         /* 0 = read
787            1 = write
788            2 = rw
789            3 = execute
790         */
791         pSMB->Mode = cpu_to_le16(2);
792         pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
793         /* set file as system file if special file such
794            as fifo and server expecting SFU style and
795            no Unix extensions */
796
797         if(create_options & CREATE_OPTION_SPECIAL)
798                 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
799         else
800                 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
801
802         /* if ((omode & S_IWUGO) == 0)
803                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
804         /*  Above line causes problems due to vfs splitting create into two
805             pieces - need to set mode after file created not while it is
806             being created */
807
808         /* BB FIXME BB */
809 /*      pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
810         /* BB FIXME END BB */
811
812         pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
813         pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
814         count += name_len;
815         pSMB->hdr.smb_buf_length += count;
816
817         pSMB->ByteCount = cpu_to_le16(count);
818         /* long_op set to 1 to allow for oplock break timeouts */
819         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
820                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
821         cifs_stats_inc(&tcon->num_opens);
822         if (rc) {
823                 cFYI(1, ("Error in Open = %d", rc));
824         } else {
825         /* BB verify if wct == 15 */
826
827 /*              *pOplock = pSMBr->OplockLevel; */  /* BB take from action field BB */
828
829                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
830                 /* Let caller know file was created so we can set the mode. */
831                 /* Do we care about the CreateAction in any other cases? */
832         /* BB FIXME BB */
833 /*              if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
834                         *pOplock |= CIFS_CREATE_ACTION; */
835         /* BB FIXME END */
836
837                 if(pfile_info) {
838                         pfile_info->CreationTime = 0; /* BB convert CreateTime*/
839                         pfile_info->LastAccessTime = 0; /* BB fixme */
840                         pfile_info->LastWriteTime = 0; /* BB fixme */
841                         pfile_info->ChangeTime = 0;  /* BB fixme */
842                         pfile_info->Attributes =
843                                 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 
844                         /* the file_info buf is endian converted by caller */
845                         pfile_info->AllocationSize =
846                                 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
847                         pfile_info->EndOfFile = pfile_info->AllocationSize;
848                         pfile_info->NumberOfLinks = cpu_to_le32(1);
849                 }
850         }
851
852         cifs_buf_release(pSMB);
853         if (rc == -EAGAIN)
854                 goto OldOpenRetry;
855         return rc;
856 }
857
858 int
859 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
860             const char *fileName, const int openDisposition,
861             const int access_flags, const int create_options, __u16 * netfid,
862             int *pOplock, FILE_ALL_INFO * pfile_info, 
863             const struct nls_table *nls_codepage, int remap)
864 {
865         int rc = -EACCES;
866         OPEN_REQ *pSMB = NULL;
867         OPEN_RSP *pSMBr = NULL;
868         int bytes_returned;
869         int name_len;
870         __u16 count;
871
872 openRetry:
873         rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
874                       (void **) &pSMBr);
875         if (rc)
876                 return rc;
877
878         pSMB->AndXCommand = 0xFF;       /* none */
879
880         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
881                 count = 1;      /* account for one byte pad to word boundary */
882                 name_len =
883                     cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
884                                      fileName, PATH_MAX, nls_codepage, remap);
885                 name_len++;     /* trailing null */
886                 name_len *= 2;
887                 pSMB->NameLength = cpu_to_le16(name_len);
888         } else {                /* BB improve check for buffer overruns BB */
889                 count = 0;      /* no pad */
890                 name_len = strnlen(fileName, PATH_MAX);
891                 name_len++;     /* trailing null */
892                 pSMB->NameLength = cpu_to_le16(name_len);
893                 strncpy(pSMB->fileName, fileName, name_len);
894         }
895         if (*pOplock & REQ_OPLOCK)
896                 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
897         else if (*pOplock & REQ_BATCHOPLOCK) {
898                 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
899         }
900         pSMB->DesiredAccess = cpu_to_le32(access_flags);
901         pSMB->AllocationSize = 0;
902         /* set file as system file if special file such
903            as fifo and server expecting SFU style and
904            no Unix extensions */
905         if(create_options & CREATE_OPTION_SPECIAL)
906                 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
907         else
908                 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
909         /* XP does not handle ATTR_POSIX_SEMANTICS */
910         /* but it helps speed up case sensitive checks for other
911         servers such as Samba */
912         if (tcon->ses->capabilities & CAP_UNIX)
913                 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
914
915         /* if ((omode & S_IWUGO) == 0)
916                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
917         /*  Above line causes problems due to vfs splitting create into two
918                 pieces - need to set mode after file created not while it is
919                 being created */
920         pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
921         pSMB->CreateDisposition = cpu_to_le32(openDisposition);
922         pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
923         /* BB Expirement with various impersonation levels and verify */
924         pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
925         pSMB->SecurityFlags =
926             SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
927
928         count += name_len;
929         pSMB->hdr.smb_buf_length += count;
930
931         pSMB->ByteCount = cpu_to_le16(count);
932         /* long_op set to 1 to allow for oplock break timeouts */
933         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
934                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
935         cifs_stats_inc(&tcon->num_opens);
936         if (rc) {
937                 cFYI(1, ("Error in Open = %d", rc));
938         } else {
939                 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
940                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
941                 /* Let caller know file was created so we can set the mode. */
942                 /* Do we care about the CreateAction in any other cases? */
943                 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
944                         *pOplock |= CIFS_CREATE_ACTION; 
945                 if(pfile_info) {
946                     memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
947                         36 /* CreationTime to Attributes */);
948                     /* the file_info buf is endian converted by caller */
949                     pfile_info->AllocationSize = pSMBr->AllocationSize;
950                     pfile_info->EndOfFile = pSMBr->EndOfFile;
951                     pfile_info->NumberOfLinks = cpu_to_le32(1);
952                 }
953         }
954
955         cifs_buf_release(pSMB);
956         if (rc == -EAGAIN)
957                 goto openRetry;
958         return rc;
959 }
960
961 int
962 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
963             const int netfid, const unsigned int count,
964             const __u64 lseek, unsigned int *nbytes, char **buf,
965             int * pbuf_type)
966 {
967         int rc = -EACCES;
968         READ_REQ *pSMB = NULL;
969         READ_RSP *pSMBr = NULL;
970         char *pReadData = NULL;
971         int wct;
972         int resp_buf_type = 0;
973         struct kvec iov[1];
974
975         cFYI(1,("Reading %d bytes on fid %d",count,netfid));
976         if(tcon->ses->capabilities & CAP_LARGE_FILES)
977                 wct = 12;
978         else
979                 wct = 10; /* old style read */
980
981         *nbytes = 0;
982         rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
983         if (rc)
984                 return rc;
985
986         /* tcon and ses pointer are checked in smb_init */
987         if (tcon->ses->server == NULL)
988                 return -ECONNABORTED;
989
990         pSMB->AndXCommand = 0xFF;       /* none */
991         pSMB->Fid = netfid;
992         pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
993         if(wct == 12)
994                 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
995         else if((lseek >> 32) > 0) /* can not handle this big offset for old */
996                 return -EIO;
997
998         pSMB->Remaining = 0;
999         pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1000         pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1001         if(wct == 12)
1002                 pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
1003         else {
1004                 /* old style read */
1005                 struct smb_com_readx_req * pSMBW =
1006                         (struct smb_com_readx_req *)pSMB;
1007                 pSMBW->ByteCount = 0;
1008         }
1009
1010         iov[0].iov_base = (char *)pSMB;
1011         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1012         rc = SendReceive2(xid, tcon->ses, iov, 
1013                           1 /* num iovecs */,
1014                           &resp_buf_type, 0); 
1015         cifs_stats_inc(&tcon->num_reads);
1016         pSMBr = (READ_RSP *)iov[0].iov_base;
1017         if (rc) {
1018                 cERROR(1, ("Send error in read = %d", rc));
1019         } else {
1020                 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1021                 data_length = data_length << 16;
1022                 data_length += le16_to_cpu(pSMBr->DataLength);
1023                 *nbytes = data_length;
1024
1025                 /*check that DataLength would not go beyond end of SMB */
1026                 if ((data_length > CIFSMaxBufSize)
1027                                 || (data_length > count)) {
1028                         cFYI(1,("bad length %d for count %d",data_length,count));
1029                         rc = -EIO;
1030                         *nbytes = 0;
1031                 } else {
1032                         pReadData = (char *) (&pSMBr->hdr.Protocol) +
1033                             le16_to_cpu(pSMBr->DataOffset);
1034 /*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
1035                                 cERROR(1,("Faulting on read rc = %d",rc));
1036                                 rc = -EFAULT;
1037                         }*/ /* can not use copy_to_user when using page cache*/
1038                         if(*buf)
1039                                 memcpy(*buf,pReadData,data_length);
1040                 }
1041         }
1042
1043         cifs_small_buf_release(pSMB);
1044         if(*buf) {
1045                 if(resp_buf_type == CIFS_SMALL_BUFFER)
1046                         cifs_small_buf_release(iov[0].iov_base);
1047                 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1048                         cifs_buf_release(iov[0].iov_base);
1049         } else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ {
1050                 *buf = iov[0].iov_base;
1051                 if(resp_buf_type == CIFS_SMALL_BUFFER)
1052                         *pbuf_type = CIFS_SMALL_BUFFER;
1053                 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1054                         *pbuf_type = CIFS_LARGE_BUFFER;
1055         }
1056
1057         /* Note: On -EAGAIN error only caller can retry on handle based calls
1058                 since file handle passed in no longer valid */
1059         return rc;
1060 }
1061
1062
1063 int
1064 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1065              const int netfid, const unsigned int count,
1066              const __u64 offset, unsigned int *nbytes, const char *buf,
1067              const char __user * ubuf, const int long_op)
1068 {
1069         int rc = -EACCES;
1070         WRITE_REQ *pSMB = NULL;
1071         WRITE_RSP *pSMBr = NULL;
1072         int bytes_returned, wct;
1073         __u32 bytes_sent;
1074         __u16 byte_count;
1075
1076         /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1077         if(tcon->ses == NULL)
1078                 return -ECONNABORTED;
1079
1080         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1081                 wct = 14;
1082         else
1083                 wct = 12;
1084
1085         rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1086                       (void **) &pSMBr);
1087         if (rc)
1088                 return rc;
1089         /* tcon and ses pointer are checked in smb_init */
1090         if (tcon->ses->server == NULL)
1091                 return -ECONNABORTED;
1092
1093         pSMB->AndXCommand = 0xFF;       /* none */
1094         pSMB->Fid = netfid;
1095         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1096         if(wct == 14) 
1097                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1098         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1099                 return -EIO;
1100         
1101         pSMB->Reserved = 0xFFFFFFFF;
1102         pSMB->WriteMode = 0;
1103         pSMB->Remaining = 0;
1104
1105         /* Can increase buffer size if buffer is big enough in some cases - ie we 
1106         can send more if LARGE_WRITE_X capability returned by the server and if
1107         our buffer is big enough or if we convert to iovecs on socket writes
1108         and eliminate the copy to the CIFS buffer */
1109         if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1110                 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1111         } else {
1112                 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1113                          & ~0xFF;
1114         }
1115
1116         if (bytes_sent > count)
1117                 bytes_sent = count;
1118         pSMB->DataOffset =
1119                 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1120         if(buf)
1121             memcpy(pSMB->Data,buf,bytes_sent);
1122         else if(ubuf) {
1123                 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1124                         cifs_buf_release(pSMB);
1125                         return -EFAULT;
1126                 }
1127         } else if (count != 0) {
1128                 /* No buffer */
1129                 cifs_buf_release(pSMB);
1130                 return -EINVAL;
1131         } /* else setting file size with write of zero bytes */
1132         if(wct == 14)
1133                 byte_count = bytes_sent + 1; /* pad */
1134         else /* wct == 12 */ {
1135                 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1136         }
1137         pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1138         pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1139         pSMB->hdr.smb_buf_length += byte_count;
1140
1141         if(wct == 14)
1142                 pSMB->ByteCount = cpu_to_le16(byte_count);
1143         else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
1144                 struct smb_com_writex_req * pSMBW = 
1145                         (struct smb_com_writex_req *)pSMB;
1146                 pSMBW->ByteCount = cpu_to_le16(byte_count);
1147         }
1148
1149         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1150                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1151         cifs_stats_inc(&tcon->num_writes);
1152         if (rc) {
1153                 cFYI(1, ("Send error in write = %d", rc));
1154                 *nbytes = 0;
1155         } else {
1156                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1157                 *nbytes = (*nbytes) << 16;
1158                 *nbytes += le16_to_cpu(pSMBr->Count);
1159         }
1160
1161         cifs_buf_release(pSMB);
1162
1163         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1164                 since file handle passed in no longer valid */
1165
1166         return rc;
1167 }
1168
1169 int
1170 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1171              const int netfid, const unsigned int count,
1172              const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1173              int n_vec, const int long_op)
1174 {
1175         int rc = -EACCES;
1176         WRITE_REQ *pSMB = NULL;
1177         int wct;
1178         int smb_hdr_len;
1179         int resp_buf_type = 0;
1180
1181         cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1182
1183         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1184                 wct = 14;
1185         else
1186                 wct = 12;
1187         rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1188         if (rc)
1189                 return rc;
1190         /* tcon and ses pointer are checked in smb_init */
1191         if (tcon->ses->server == NULL)
1192                 return -ECONNABORTED;
1193
1194         pSMB->AndXCommand = 0xFF;       /* none */
1195         pSMB->Fid = netfid;
1196         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1197         if(wct == 14)
1198                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1199         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1200                 return -EIO;
1201         pSMB->Reserved = 0xFFFFFFFF;
1202         pSMB->WriteMode = 0;
1203         pSMB->Remaining = 0;
1204
1205         pSMB->DataOffset =
1206             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1207
1208         pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1209         pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1210         smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1211         if(wct == 14)
1212                 pSMB->hdr.smb_buf_length += count+1;
1213         else /* wct == 12 */
1214                 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ 
1215         if(wct == 14)
1216                 pSMB->ByteCount = cpu_to_le16(count + 1);
1217         else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1218                 struct smb_com_writex_req * pSMBW =
1219                                 (struct smb_com_writex_req *)pSMB;
1220                 pSMBW->ByteCount = cpu_to_le16(count + 5);
1221         }
1222         iov[0].iov_base = pSMB;
1223         if(wct == 14)
1224                 iov[0].iov_len = smb_hdr_len + 4;
1225         else /* wct == 12 pad bigger by four bytes */
1226                 iov[0].iov_len = smb_hdr_len + 8;
1227         
1228
1229         rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1230                           long_op);
1231         cifs_stats_inc(&tcon->num_writes);
1232         if (rc) {
1233                 cFYI(1, ("Send error Write2 = %d", rc));
1234                 *nbytes = 0;
1235         } else if(resp_buf_type == 0) {
1236                 /* presumably this can not happen, but best to be safe */
1237                 rc = -EIO;
1238                 *nbytes = 0;
1239         } else {
1240                 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1241                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1242                 *nbytes = (*nbytes) << 16;
1243                 *nbytes += le16_to_cpu(pSMBr->Count);
1244         } 
1245
1246         cifs_small_buf_release(pSMB);
1247         if(resp_buf_type == CIFS_SMALL_BUFFER)
1248                 cifs_small_buf_release(iov[0].iov_base);
1249         else if(resp_buf_type == CIFS_LARGE_BUFFER)
1250                 cifs_buf_release(iov[0].iov_base);
1251
1252         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1253                 since file handle passed in no longer valid */
1254
1255         return rc;
1256 }
1257
1258
1259 int
1260 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1261             const __u16 smb_file_id, const __u64 len,
1262             const __u64 offset, const __u32 numUnlock,
1263             const __u32 numLock, const __u8 lockType, const int waitFlag)
1264 {
1265         int rc = 0;
1266         LOCK_REQ *pSMB = NULL;
1267         LOCK_RSP *pSMBr = NULL;
1268         int bytes_returned;
1269         int timeout = 0;
1270         __u16 count;
1271
1272         cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1273         rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1274
1275         if (rc)
1276                 return rc;
1277
1278         pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1279
1280         if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1281                 timeout = -1; /* no response expected */
1282                 pSMB->Timeout = 0;
1283         } else if (waitFlag == TRUE) {
1284                 timeout = 3;  /* blocking operation, no timeout */
1285                 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1286         } else {
1287                 pSMB->Timeout = 0;
1288         }
1289
1290         pSMB->NumberOfLocks = cpu_to_le16(numLock);
1291         pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1292         pSMB->LockType = lockType;
1293         pSMB->AndXCommand = 0xFF;       /* none */
1294         pSMB->Fid = smb_file_id; /* netfid stays le */
1295
1296         if((numLock != 0) || (numUnlock != 0)) {
1297                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1298                 /* BB where to store pid high? */
1299                 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1300                 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1301                 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1302                 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1303                 count = sizeof(LOCKING_ANDX_RANGE);
1304         } else {
1305                 /* oplock break */
1306                 count = 0;
1307         }
1308         pSMB->hdr.smb_buf_length += count;
1309         pSMB->ByteCount = cpu_to_le16(count);
1310
1311         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1312                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1313         cifs_stats_inc(&tcon->num_locks);
1314         if (rc) {
1315                 cFYI(1, ("Send error in Lock = %d", rc));
1316         }
1317         cifs_small_buf_release(pSMB);
1318
1319         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1320         since file handle passed in no longer valid */
1321         return rc;
1322 }
1323
1324 int
1325 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1326 {
1327         int rc = 0;
1328         CLOSE_REQ *pSMB = NULL;
1329         CLOSE_RSP *pSMBr = NULL;
1330         int bytes_returned;
1331         cFYI(1, ("In CIFSSMBClose"));
1332
1333 /* do not retry on dead session on close */
1334         rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1335         if(rc == -EAGAIN)
1336                 return 0;
1337         if (rc)
1338                 return rc;
1339
1340         pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1341
1342         pSMB->FileID = (__u16) smb_file_id;
1343         pSMB->LastWriteTime = 0;
1344         pSMB->ByteCount = 0;
1345         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1346                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1347         cifs_stats_inc(&tcon->num_closes);
1348         if (rc) {
1349                 if(rc!=-EINTR) {
1350                         /* EINTR is expected when user ctl-c to kill app */
1351                         cERROR(1, ("Send error in Close = %d", rc));
1352                 }
1353         }
1354
1355         cifs_small_buf_release(pSMB);
1356
1357         /* Since session is dead, file will be closed on server already */
1358         if(rc == -EAGAIN)
1359                 rc = 0;
1360
1361         return rc;
1362 }
1363
1364 int
1365 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1366               const char *fromName, const char *toName,
1367               const struct nls_table *nls_codepage, int remap)
1368 {
1369         int rc = 0;
1370         RENAME_REQ *pSMB = NULL;
1371         RENAME_RSP *pSMBr = NULL;
1372         int bytes_returned;
1373         int name_len, name_len2;
1374         __u16 count;
1375
1376         cFYI(1, ("In CIFSSMBRename"));
1377 renameRetry:
1378         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1379                       (void **) &pSMBr);
1380         if (rc)
1381                 return rc;
1382
1383         pSMB->BufferFormat = 0x04;
1384         pSMB->SearchAttributes =
1385             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1386                         ATTR_DIRECTORY);
1387
1388         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1389                 name_len =
1390                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, 
1391                                      PATH_MAX, nls_codepage, remap);
1392                 name_len++;     /* trailing null */
1393                 name_len *= 2;
1394                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1395         /* protocol requires ASCII signature byte on Unicode string */
1396                 pSMB->OldFileName[name_len + 1] = 0x00;
1397                 name_len2 =
1398                     cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1399                                      toName, PATH_MAX, nls_codepage, remap);
1400                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1401                 name_len2 *= 2; /* convert to bytes */
1402         } else {                /* BB improve the check for buffer overruns BB */
1403                 name_len = strnlen(fromName, PATH_MAX);
1404                 name_len++;     /* trailing null */
1405                 strncpy(pSMB->OldFileName, fromName, name_len);
1406                 name_len2 = strnlen(toName, PATH_MAX);
1407                 name_len2++;    /* trailing null */
1408                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1409                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1410                 name_len2++;    /* trailing null */
1411                 name_len2++;    /* signature byte */
1412         }
1413
1414         count = 1 /* 1st signature byte */  + name_len + name_len2;
1415         pSMB->hdr.smb_buf_length += count;
1416         pSMB->ByteCount = cpu_to_le16(count);
1417
1418         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1419                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1420         cifs_stats_inc(&tcon->num_renames);
1421         if (rc) {
1422                 cFYI(1, ("Send error in rename = %d", rc));
1423         } 
1424
1425         cifs_buf_release(pSMB);
1426
1427         if (rc == -EAGAIN)
1428                 goto renameRetry;
1429
1430         return rc;
1431 }
1432
1433 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
1434                 int netfid, char * target_name, 
1435                 const struct nls_table * nls_codepage, int remap)
1436 {
1437         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1438         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1439         struct set_file_rename * rename_info;
1440         char *data_offset;
1441         char dummy_string[30];
1442         int rc = 0;
1443         int bytes_returned = 0;
1444         int len_of_str;
1445         __u16 params, param_offset, offset, count, byte_count;
1446
1447         cFYI(1, ("Rename to File by handle"));
1448         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1449                         (void **) &pSMBr);
1450         if (rc)
1451                 return rc;
1452
1453         params = 6;
1454         pSMB->MaxSetupCount = 0;
1455         pSMB->Reserved = 0;
1456         pSMB->Flags = 0;
1457         pSMB->Timeout = 0;
1458         pSMB->Reserved2 = 0;
1459         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1460         offset = param_offset + params;
1461
1462         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1463         rename_info = (struct set_file_rename *) data_offset;
1464         pSMB->MaxParameterCount = cpu_to_le16(2);
1465         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1466         pSMB->SetupCount = 1;
1467         pSMB->Reserved3 = 0;
1468         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1469         byte_count = 3 /* pad */  + params;
1470         pSMB->ParameterCount = cpu_to_le16(params);
1471         pSMB->TotalParameterCount = pSMB->ParameterCount;
1472         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1473         pSMB->DataOffset = cpu_to_le16(offset);
1474         /* construct random name ".cifs_tmp<inodenum><mid>" */
1475         rename_info->overwrite = cpu_to_le32(1);
1476         rename_info->root_fid  = 0;
1477         /* unicode only call */
1478         if(target_name == NULL) {
1479                 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1480                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1481                                         dummy_string, 24, nls_codepage, remap);
1482         } else {
1483                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1484                                         target_name, PATH_MAX, nls_codepage, remap);
1485         }
1486         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1487         count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1488         byte_count += count;
1489         pSMB->DataCount = cpu_to_le16(count);
1490         pSMB->TotalDataCount = pSMB->DataCount;
1491         pSMB->Fid = netfid;
1492         pSMB->InformationLevel =
1493                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1494         pSMB->Reserved4 = 0;
1495         pSMB->hdr.smb_buf_length += byte_count;
1496         pSMB->ByteCount = cpu_to_le16(byte_count);
1497         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1498                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1499         cifs_stats_inc(&pTcon->num_t2renames);
1500         if (rc) {
1501                 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1502         }
1503
1504         cifs_buf_release(pSMB);
1505
1506         /* Note: On -EAGAIN error only caller can retry on handle based calls
1507                 since file handle passed in no longer valid */
1508
1509         return rc;
1510 }
1511
1512 int
1513 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
1514             const __u16 target_tid, const char *toName, const int flags,
1515             const struct nls_table *nls_codepage, int remap)
1516 {
1517         int rc = 0;
1518         COPY_REQ *pSMB = NULL;
1519         COPY_RSP *pSMBr = NULL;
1520         int bytes_returned;
1521         int name_len, name_len2;
1522         __u16 count;
1523
1524         cFYI(1, ("In CIFSSMBCopy"));
1525 copyRetry:
1526         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1527                         (void **) &pSMBr);
1528         if (rc)
1529                 return rc;
1530
1531         pSMB->BufferFormat = 0x04;
1532         pSMB->Tid2 = target_tid;
1533
1534         pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1535
1536         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1537                 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, 
1538                                             fromName, PATH_MAX, nls_codepage,
1539                                             remap);
1540                 name_len++;     /* trailing null */
1541                 name_len *= 2;
1542                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1543                 /* protocol requires ASCII signature byte on Unicode string */
1544                 pSMB->OldFileName[name_len + 1] = 0x00;
1545                 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1546                                 toName, PATH_MAX, nls_codepage, remap);
1547                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1548                 name_len2 *= 2; /* convert to bytes */
1549         } else {                /* BB improve the check for buffer overruns BB */
1550                 name_len = strnlen(fromName, PATH_MAX);
1551                 name_len++;     /* trailing null */
1552                 strncpy(pSMB->OldFileName, fromName, name_len);
1553                 name_len2 = strnlen(toName, PATH_MAX);
1554                 name_len2++;    /* trailing null */
1555                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1556                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1557                 name_len2++;    /* trailing null */
1558                 name_len2++;    /* signature byte */
1559         }
1560
1561         count = 1 /* 1st signature byte */  + name_len + name_len2;
1562         pSMB->hdr.smb_buf_length += count;
1563         pSMB->ByteCount = cpu_to_le16(count);
1564
1565         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1566                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1567         if (rc) {
1568                 cFYI(1, ("Send error in copy = %d with %d files copied",
1569                         rc, le16_to_cpu(pSMBr->CopyCount)));
1570         }
1571         if (pSMB)
1572                 cifs_buf_release(pSMB);
1573
1574         if (rc == -EAGAIN)
1575                 goto copyRetry;
1576
1577         return rc;
1578 }
1579
1580 int
1581 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1582                       const char *fromName, const char *toName,
1583                       const struct nls_table *nls_codepage)
1584 {
1585         TRANSACTION2_SPI_REQ *pSMB = NULL;
1586         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1587         char *data_offset;
1588         int name_len;
1589         int name_len_target;
1590         int rc = 0;
1591         int bytes_returned = 0;
1592         __u16 params, param_offset, offset, byte_count;
1593
1594         cFYI(1, ("In Symlink Unix style"));
1595 createSymLinkRetry:
1596         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1597                       (void **) &pSMBr);
1598         if (rc)
1599                 return rc;
1600
1601         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1602                 name_len =
1603                     cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1604                                   /* find define for this maxpathcomponent */
1605                                   , nls_codepage);
1606                 name_len++;     /* trailing null */
1607                 name_len *= 2;
1608
1609         } else {                /* BB improve the check for buffer overruns BB */
1610                 name_len = strnlen(fromName, PATH_MAX);
1611                 name_len++;     /* trailing null */
1612                 strncpy(pSMB->FileName, fromName, name_len);
1613         }
1614         params = 6 + name_len;
1615         pSMB->MaxSetupCount = 0;
1616         pSMB->Reserved = 0;
1617         pSMB->Flags = 0;
1618         pSMB->Timeout = 0;
1619         pSMB->Reserved2 = 0;
1620         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1621                                      InformationLevel) - 4;
1622         offset = param_offset + params;
1623
1624         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1625         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1626                 name_len_target =
1627                     cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1628                                   /* find define for this maxpathcomponent */
1629                                   , nls_codepage);
1630                 name_len_target++;      /* trailing null */
1631                 name_len_target *= 2;
1632         } else {                /* BB improve the check for buffer overruns BB */
1633                 name_len_target = strnlen(toName, PATH_MAX);
1634                 name_len_target++;      /* trailing null */
1635                 strncpy(data_offset, toName, name_len_target);
1636         }
1637
1638         pSMB->MaxParameterCount = cpu_to_le16(2);
1639         /* BB find exact max on data count below from sess */
1640         pSMB->MaxDataCount = cpu_to_le16(1000);
1641         pSMB->SetupCount = 1;
1642         pSMB->Reserved3 = 0;
1643         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1644         byte_count = 3 /* pad */  + params + name_len_target;
1645         pSMB->DataCount = cpu_to_le16(name_len_target);
1646         pSMB->ParameterCount = cpu_to_le16(params);
1647         pSMB->TotalDataCount = pSMB->DataCount;
1648         pSMB->TotalParameterCount = pSMB->ParameterCount;
1649         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1650         pSMB->DataOffset = cpu_to_le16(offset);
1651         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1652         pSMB->Reserved4 = 0;
1653         pSMB->hdr.smb_buf_length += byte_count;
1654         pSMB->ByteCount = cpu_to_le16(byte_count);
1655         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1656                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1657         cifs_stats_inc(&tcon->num_symlinks);
1658         if (rc) {
1659                 cFYI(1,
1660                      ("Send error in SetPathInfo (create symlink) = %d",
1661                       rc));
1662         }
1663
1664         if (pSMB)
1665                 cifs_buf_release(pSMB);
1666
1667         if (rc == -EAGAIN)
1668                 goto createSymLinkRetry;
1669
1670         return rc;
1671 }
1672
1673 int
1674 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1675                        const char *fromName, const char *toName,
1676                        const struct nls_table *nls_codepage, int remap)
1677 {
1678         TRANSACTION2_SPI_REQ *pSMB = NULL;
1679         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1680         char *data_offset;
1681         int name_len;
1682         int name_len_target;
1683         int rc = 0;
1684         int bytes_returned = 0;
1685         __u16 params, param_offset, offset, byte_count;
1686
1687         cFYI(1, ("In Create Hard link Unix style"));
1688 createHardLinkRetry:
1689         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1690                       (void **) &pSMBr);
1691         if (rc)
1692                 return rc;
1693
1694         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1695                 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1696                                             PATH_MAX, nls_codepage, remap);
1697                 name_len++;     /* trailing null */
1698                 name_len *= 2;
1699
1700         } else {                /* BB improve the check for buffer overruns BB */
1701                 name_len = strnlen(toName, PATH_MAX);
1702                 name_len++;     /* trailing null */
1703                 strncpy(pSMB->FileName, toName, name_len);
1704         }
1705         params = 6 + name_len;
1706         pSMB->MaxSetupCount = 0;
1707         pSMB->Reserved = 0;
1708         pSMB->Flags = 0;
1709         pSMB->Timeout = 0;
1710         pSMB->Reserved2 = 0;
1711         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1712                                      InformationLevel) - 4;
1713         offset = param_offset + params;
1714
1715         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1716         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1717                 name_len_target =
1718                     cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1719                                      nls_codepage, remap);
1720                 name_len_target++;      /* trailing null */
1721                 name_len_target *= 2;
1722         } else {                /* BB improve the check for buffer overruns BB */
1723                 name_len_target = strnlen(fromName, PATH_MAX);
1724                 name_len_target++;      /* trailing null */
1725                 strncpy(data_offset, fromName, name_len_target);
1726         }
1727
1728         pSMB->MaxParameterCount = cpu_to_le16(2);
1729         /* BB find exact max on data count below from sess*/
1730         pSMB->MaxDataCount = cpu_to_le16(1000);
1731         pSMB->SetupCount = 1;
1732         pSMB->Reserved3 = 0;
1733         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1734         byte_count = 3 /* pad */  + params + name_len_target;
1735         pSMB->ParameterCount = cpu_to_le16(params);
1736         pSMB->TotalParameterCount = pSMB->ParameterCount;
1737         pSMB->DataCount = cpu_to_le16(name_len_target);
1738         pSMB->TotalDataCount = pSMB->DataCount;
1739         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1740         pSMB->DataOffset = cpu_to_le16(offset);
1741         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1742         pSMB->Reserved4 = 0;
1743         pSMB->hdr.smb_buf_length += byte_count;
1744         pSMB->ByteCount = cpu_to_le16(byte_count);
1745         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1746                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1747         cifs_stats_inc(&tcon->num_hardlinks);
1748         if (rc) {
1749                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1750         }
1751
1752         cifs_buf_release(pSMB);
1753         if (rc == -EAGAIN)
1754                 goto createHardLinkRetry;
1755
1756         return rc;
1757 }
1758
1759 int
1760 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1761                    const char *fromName, const char *toName,
1762                    const struct nls_table *nls_codepage, int remap)
1763 {
1764         int rc = 0;
1765         NT_RENAME_REQ *pSMB = NULL;
1766         RENAME_RSP *pSMBr = NULL;
1767         int bytes_returned;
1768         int name_len, name_len2;
1769         __u16 count;
1770
1771         cFYI(1, ("In CIFSCreateHardLink"));
1772 winCreateHardLinkRetry:
1773
1774         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1775                       (void **) &pSMBr);
1776         if (rc)
1777                 return rc;
1778
1779         pSMB->SearchAttributes =
1780             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1781                         ATTR_DIRECTORY);
1782         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1783         pSMB->ClusterCount = 0;
1784
1785         pSMB->BufferFormat = 0x04;
1786
1787         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1788                 name_len =
1789                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1790                                      PATH_MAX, nls_codepage, remap);
1791                 name_len++;     /* trailing null */
1792                 name_len *= 2;
1793                 pSMB->OldFileName[name_len] = 0;        /* pad */
1794                 pSMB->OldFileName[name_len + 1] = 0x04; 
1795                 name_len2 =
1796                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1797                                      toName, PATH_MAX, nls_codepage, remap);
1798                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1799                 name_len2 *= 2; /* convert to bytes */
1800         } else {                /* BB improve the check for buffer overruns BB */
1801                 name_len = strnlen(fromName, PATH_MAX);
1802                 name_len++;     /* trailing null */
1803                 strncpy(pSMB->OldFileName, fromName, name_len);
1804                 name_len2 = strnlen(toName, PATH_MAX);
1805                 name_len2++;    /* trailing null */
1806                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
1807                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1808                 name_len2++;    /* trailing null */
1809                 name_len2++;    /* signature byte */
1810         }
1811
1812         count = 1 /* string type byte */  + name_len + name_len2;
1813         pSMB->hdr.smb_buf_length += count;
1814         pSMB->ByteCount = cpu_to_le16(count);
1815
1816         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1817                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1818         cifs_stats_inc(&tcon->num_hardlinks);
1819         if (rc) {
1820                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1821         }
1822         cifs_buf_release(pSMB);
1823         if (rc == -EAGAIN)
1824                 goto winCreateHardLinkRetry;
1825
1826         return rc;
1827 }
1828
1829 int
1830 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1831                         const unsigned char *searchName,
1832                         char *symlinkinfo, const int buflen,
1833                         const struct nls_table *nls_codepage)
1834 {
1835 /* SMB_QUERY_FILE_UNIX_LINK */
1836         TRANSACTION2_QPI_REQ *pSMB = NULL;
1837         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1838         int rc = 0;
1839         int bytes_returned;
1840         int name_len;
1841         __u16 params, byte_count;
1842
1843         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1844
1845 querySymLinkRetry:
1846         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1847                       (void **) &pSMBr);
1848         if (rc)
1849                 return rc;
1850
1851         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1852                 name_len =
1853                     cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
1854                                   /* find define for this maxpathcomponent */
1855                                   , nls_codepage);
1856                 name_len++;     /* trailing null */
1857                 name_len *= 2;
1858         } else {                /* BB improve the check for buffer overruns BB */
1859                 name_len = strnlen(searchName, PATH_MAX);
1860                 name_len++;     /* trailing null */
1861                 strncpy(pSMB->FileName, searchName, name_len);
1862         }
1863
1864         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1865         pSMB->TotalDataCount = 0;
1866         pSMB->MaxParameterCount = cpu_to_le16(2);
1867         /* BB find exact max data count below from sess structure BB */
1868         pSMB->MaxDataCount = cpu_to_le16(4000);
1869         pSMB->MaxSetupCount = 0;
1870         pSMB->Reserved = 0;
1871         pSMB->Flags = 0;
1872         pSMB->Timeout = 0;
1873         pSMB->Reserved2 = 0;
1874         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1875         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1876         pSMB->DataCount = 0;
1877         pSMB->DataOffset = 0;
1878         pSMB->SetupCount = 1;
1879         pSMB->Reserved3 = 0;
1880         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1881         byte_count = params + 1 /* pad */ ;
1882         pSMB->TotalParameterCount = cpu_to_le16(params);
1883         pSMB->ParameterCount = pSMB->TotalParameterCount;
1884         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1885         pSMB->Reserved4 = 0;
1886         pSMB->hdr.smb_buf_length += byte_count;
1887         pSMB->ByteCount = cpu_to_le16(byte_count);
1888
1889         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1890                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1891         if (rc) {
1892                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1893         } else {
1894                 /* decode response */
1895
1896                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1897                 if (rc || (pSMBr->ByteCount < 2))
1898                 /* BB also check enough total bytes returned */
1899                         rc = -EIO;      /* bad smb */
1900                 else {
1901                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1902                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1903
1904                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1905                                 name_len = UniStrnlen((wchar_t *) ((char *)
1906                                         &pSMBr->hdr.Protocol +data_offset),
1907                                         min_t(const int, buflen,count) / 2);
1908                         /* BB FIXME investigate remapping reserved chars here */
1909                                 cifs_strfromUCS_le(symlinkinfo,
1910                                         (__le16 *) ((char *)&pSMBr->hdr.Protocol +
1911                                                 data_offset),
1912                                         name_len, nls_codepage);
1913                         } else {
1914                                 strncpy(symlinkinfo,
1915                                         (char *) &pSMBr->hdr.Protocol + 
1916                                                 data_offset,
1917                                         min_t(const int, buflen, count));
1918                         }
1919                         symlinkinfo[buflen] = 0;
1920         /* just in case so calling code does not go off the end of buffer */
1921                 }
1922         }
1923         cifs_buf_release(pSMB);
1924         if (rc == -EAGAIN)
1925                 goto querySymLinkRetry;
1926         return rc;
1927 }
1928
1929 int
1930 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1931                         const unsigned char *searchName,
1932                         char *symlinkinfo, const int buflen,__u16 fid,
1933                         const struct nls_table *nls_codepage)
1934 {
1935         int rc = 0;
1936         int bytes_returned;
1937         int name_len;
1938         struct smb_com_transaction_ioctl_req * pSMB;
1939         struct smb_com_transaction_ioctl_rsp * pSMBr;
1940
1941         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1942         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1943                       (void **) &pSMBr);
1944         if (rc)
1945                 return rc;
1946
1947         pSMB->TotalParameterCount = 0 ;
1948         pSMB->TotalDataCount = 0;
1949         pSMB->MaxParameterCount = cpu_to_le32(2);
1950         /* BB find exact data count max from sess structure BB */
1951         pSMB->MaxDataCount = cpu_to_le32(4000);
1952         pSMB->MaxSetupCount = 4;
1953         pSMB->Reserved = 0;
1954         pSMB->ParameterOffset = 0;
1955         pSMB->DataCount = 0;
1956         pSMB->DataOffset = 0;
1957         pSMB->SetupCount = 4;
1958         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1959         pSMB->ParameterCount = pSMB->TotalParameterCount;
1960         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1961         pSMB->IsFsctl = 1; /* FSCTL */
1962         pSMB->IsRootFlag = 0;
1963         pSMB->Fid = fid; /* file handle always le */
1964         pSMB->ByteCount = 0;
1965
1966         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1967                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1968         if (rc) {
1969                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1970         } else {                /* decode response */
1971                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1972                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1973                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1974                 /* BB also check enough total bytes returned */
1975                         rc = -EIO;      /* bad smb */
1976                 else {
1977                         if(data_count && (data_count < 2048)) {
1978                                 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1979
1980                                 struct reparse_data * reparse_buf = (struct reparse_data *)
1981                                         ((char *)&pSMBr->hdr.Protocol + data_offset);
1982                                 if((char*)reparse_buf >= end_of_smb) {
1983                                         rc = -EIO;
1984                                         goto qreparse_out;
1985                                 }
1986                                 if((reparse_buf->LinkNamesBuf + 
1987                                         reparse_buf->TargetNameOffset +
1988                                         reparse_buf->TargetNameLen) >
1989                                                 end_of_smb) {
1990                                         cFYI(1,("reparse buf extended beyond SMB"));
1991                                         rc = -EIO;
1992                                         goto qreparse_out;
1993                                 }
1994                                 
1995                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1996                                         name_len = UniStrnlen((wchar_t *)
1997                                                         (reparse_buf->LinkNamesBuf + 
1998                                                         reparse_buf->TargetNameOffset),
1999                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
2000                                         cifs_strfromUCS_le(symlinkinfo,
2001                                                 (__le16 *) (reparse_buf->LinkNamesBuf + 
2002                                                 reparse_buf->TargetNameOffset),
2003                                                 name_len, nls_codepage);
2004                                 } else { /* ASCII names */
2005                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
2006                                                 reparse_buf->TargetNameOffset, 
2007                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
2008                                 }
2009                         } else {
2010                                 rc = -EIO;
2011                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2012                         }
2013                         symlinkinfo[buflen] = 0; /* just in case so the caller
2014                                         does not go off the end of the buffer */
2015                         cFYI(1,("readlink result - %s ",symlinkinfo));
2016                 }
2017         }
2018 qreparse_out:
2019         cifs_buf_release(pSMB);
2020
2021         /* Note: On -EAGAIN error only caller can retry on handle based calls
2022                 since file handle passed in no longer valid */
2023
2024         return rc;
2025 }
2026
2027 #ifdef CONFIG_CIFS_POSIX
2028
2029 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2030 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2031 {
2032         /* u8 cifs fields do not need le conversion */
2033         ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2034         ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
2035         ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2036         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2037
2038         return;
2039 }
2040
2041 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2042 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2043                                 const int acl_type,const int size_of_data_area)
2044 {
2045         int size =  0;
2046         int i;
2047         __u16 count;
2048         struct cifs_posix_ace * pACE;
2049         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2050         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2051
2052         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2053                 return -EOPNOTSUPP;
2054
2055         if(acl_type & ACL_TYPE_ACCESS) {
2056                 count = le16_to_cpu(cifs_acl->access_entry_count);
2057                 pACE = &cifs_acl->ace_array[0];
2058                 size = sizeof(struct cifs_posix_acl);
2059                 size += sizeof(struct cifs_posix_ace) * count;
2060                 /* check if we would go beyond end of SMB */
2061                 if(size_of_data_area < size) {
2062                         cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2063                         return -EINVAL;
2064                 }
2065         } else if(acl_type & ACL_TYPE_DEFAULT) {
2066                 count = le16_to_cpu(cifs_acl->access_entry_count);
2067                 size = sizeof(struct cifs_posix_acl);
2068                 size += sizeof(struct cifs_posix_ace) * count;
2069 /* skip past access ACEs to get to default ACEs */
2070                 pACE = &cifs_acl->ace_array[count];
2071                 count = le16_to_cpu(cifs_acl->default_entry_count);
2072                 size += sizeof(struct cifs_posix_ace) * count;
2073                 /* check if we would go beyond end of SMB */
2074                 if(size_of_data_area < size)
2075                         return -EINVAL;
2076         } else {
2077                 /* illegal type */
2078                 return -EINVAL;
2079         }
2080
2081         size = posix_acl_xattr_size(count);
2082         if((buflen == 0) || (local_acl == NULL)) {
2083                 /* used to query ACL EA size */                         
2084         } else if(size > buflen) {
2085                 return -ERANGE;
2086         } else /* buffer big enough */ {
2087                 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2088                 for(i = 0;i < count ;i++) {
2089                         cifs_convert_ace(&local_acl->a_entries[i],pACE);
2090                         pACE ++;
2091                 }
2092         }
2093         return size;
2094 }
2095
2096 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2097                         const posix_acl_xattr_entry * local_ace)
2098 {
2099         __u16 rc = 0; /* 0 = ACL converted ok */
2100
2101         cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2102         cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
2103         /* BB is there a better way to handle the large uid? */
2104         if(local_ace->e_id == cpu_to_le32(-1)) {
2105         /* Probably no need to le convert -1 on any arch but can not hurt */
2106                 cifs_ace->cifs_uid = cpu_to_le64(-1);
2107         } else 
2108                 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2109         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2110         return rc;
2111 }
2112
2113 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2114 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2115                 const int acl_type)
2116 {
2117         __u16 rc = 0;
2118         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2119         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2120         int count;
2121         int i;
2122
2123         if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2124                 return 0;
2125
2126         count = posix_acl_xattr_count((size_t)buflen);
2127         cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2128                 count, buflen, le32_to_cpu(local_acl->a_version)));
2129         if(le32_to_cpu(local_acl->a_version) != 2) {
2130                 cFYI(1,("unknown POSIX ACL version %d",
2131                      le32_to_cpu(local_acl->a_version)));
2132                 return 0;
2133         }
2134         cifs_acl->version = cpu_to_le16(1);
2135         if(acl_type == ACL_TYPE_ACCESS) 
2136                 cifs_acl->access_entry_count = cpu_to_le16(count);
2137         else if(acl_type == ACL_TYPE_DEFAULT)
2138                 cifs_acl->default_entry_count = cpu_to_le16(count);
2139         else {
2140                 cFYI(1,("unknown ACL type %d",acl_type));
2141                 return 0;
2142         }
2143         for(i=0;i<count;i++) {
2144                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2145                                         &local_acl->a_entries[i]);
2146                 if(rc != 0) {
2147                         /* ACE not converted */
2148                         break;
2149                 }
2150         }
2151         if(rc == 0) {
2152                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2153                 rc += sizeof(struct cifs_posix_acl);
2154                 /* BB add check to make sure ACL does not overflow SMB */
2155         }
2156         return rc;
2157 }
2158
2159 int
2160 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2161                         const unsigned char *searchName,
2162                         char *acl_inf, const int buflen, const int acl_type,
2163                         const struct nls_table *nls_codepage, int remap)
2164 {
2165 /* SMB_QUERY_POSIX_ACL */
2166         TRANSACTION2_QPI_REQ *pSMB = NULL;
2167         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2168         int rc = 0;
2169         int bytes_returned;
2170         int name_len;
2171         __u16 params, byte_count;
2172                                                                                                                                              
2173         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2174
2175 queryAclRetry:
2176         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2177                 (void **) &pSMBr);
2178         if (rc)
2179                 return rc;
2180                                                                                                                                              
2181         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2182                 name_len =
2183                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2184                                          PATH_MAX, nls_codepage, remap);
2185                 name_len++;     /* trailing null */
2186                 name_len *= 2;
2187                 pSMB->FileName[name_len] = 0;
2188                 pSMB->FileName[name_len+1] = 0;
2189         } else {                /* BB improve the check for buffer overruns BB */
2190                 name_len = strnlen(searchName, PATH_MAX);
2191                 name_len++;     /* trailing null */
2192                 strncpy(pSMB->FileName, searchName, name_len);
2193         }
2194
2195         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2196         pSMB->TotalDataCount = 0;
2197         pSMB->MaxParameterCount = cpu_to_le16(2);
2198         /* BB find exact max data count below from sess structure BB */
2199         pSMB->MaxDataCount = cpu_to_le16(4000);
2200         pSMB->MaxSetupCount = 0;
2201         pSMB->Reserved = 0;
2202         pSMB->Flags = 0;
2203         pSMB->Timeout = 0;
2204         pSMB->Reserved2 = 0;
2205         pSMB->ParameterOffset = cpu_to_le16(
2206                 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2207         pSMB->DataCount = 0;
2208         pSMB->DataOffset = 0;
2209         pSMB->SetupCount = 1;
2210         pSMB->Reserved3 = 0;
2211         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2212         byte_count = params + 1 /* pad */ ;
2213         pSMB->TotalParameterCount = cpu_to_le16(params);
2214         pSMB->ParameterCount = pSMB->TotalParameterCount;
2215         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2216         pSMB->Reserved4 = 0;
2217         pSMB->hdr.smb_buf_length += byte_count;
2218         pSMB->ByteCount = cpu_to_le16(byte_count);
2219
2220         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2221                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2222         if (rc) {
2223                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2224         } else {
2225                 /* decode response */
2226  
2227                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2228                 if (rc || (pSMBr->ByteCount < 2))
2229                 /* BB also check enough total bytes returned */
2230                         rc = -EIO;      /* bad smb */
2231                 else {
2232                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2233                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2234                         rc = cifs_copy_posix_acl(acl_inf,
2235                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2236                                 buflen,acl_type,count);
2237                 }
2238         }
2239         cifs_buf_release(pSMB);
2240         if (rc == -EAGAIN)
2241                 goto queryAclRetry;
2242         return rc;
2243 }
2244
2245 int
2246 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2247                         const unsigned char *fileName,
2248                         const char *local_acl, const int buflen, 
2249                         const int acl_type,
2250                         const struct nls_table *nls_codepage, int remap)
2251 {
2252         struct smb_com_transaction2_spi_req *pSMB = NULL;
2253         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2254         char *parm_data;
2255         int name_len;
2256         int rc = 0;
2257         int bytes_returned = 0;
2258         __u16 params, byte_count, data_count, param_offset, offset;
2259
2260         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2261 setAclRetry:
2262         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2263                       (void **) &pSMBr);
2264         if (rc)
2265                 return rc;
2266         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2267                 name_len =
2268                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
2269                                       PATH_MAX, nls_codepage, remap);
2270                 name_len++;     /* trailing null */
2271                 name_len *= 2;
2272         } else {                /* BB improve the check for buffer overruns BB */
2273                 name_len = strnlen(fileName, PATH_MAX);
2274                 name_len++;     /* trailing null */
2275                 strncpy(pSMB->FileName, fileName, name_len);
2276         }
2277         params = 6 + name_len;
2278         pSMB->MaxParameterCount = cpu_to_le16(2);
2279         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2280         pSMB->MaxSetupCount = 0;
2281         pSMB->Reserved = 0;
2282         pSMB->Flags = 0;
2283         pSMB->Timeout = 0;
2284         pSMB->Reserved2 = 0;
2285         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2286                                      InformationLevel) - 4;
2287         offset = param_offset + params;
2288         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2289         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2290
2291         /* convert to on the wire format for POSIX ACL */
2292         data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2293
2294         if(data_count == 0) {
2295                 rc = -EOPNOTSUPP;
2296                 goto setACLerrorExit;
2297         }
2298         pSMB->DataOffset = cpu_to_le16(offset);
2299         pSMB->SetupCount = 1;
2300         pSMB->Reserved3 = 0;
2301         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2302         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2303         byte_count = 3 /* pad */  + params + data_count;
2304         pSMB->DataCount = cpu_to_le16(data_count);
2305         pSMB->TotalDataCount = pSMB->DataCount;
2306         pSMB->ParameterCount = cpu_to_le16(params);
2307         pSMB->TotalParameterCount = pSMB->ParameterCount;
2308         pSMB->Reserved4 = 0;
2309         pSMB->hdr.smb_buf_length += byte_count;
2310         pSMB->ByteCount = cpu_to_le16(byte_count);
2311         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2312                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2313         if (rc) {
2314                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2315         }
2316
2317 setACLerrorExit:
2318         cifs_buf_release(pSMB);
2319         if (rc == -EAGAIN)
2320                 goto setAclRetry;
2321         return rc;
2322 }
2323
2324 /* BB fix tabs in this function FIXME BB */
2325 int
2326 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2327                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2328 {
2329         int rc = 0;
2330         struct smb_t2_qfi_req *pSMB = NULL;
2331         struct smb_t2_qfi_rsp *pSMBr = NULL;
2332         int bytes_returned;
2333         __u16 params, byte_count;
2334
2335         cFYI(1,("In GetExtAttr"));
2336         if(tcon == NULL)
2337                 return -ENODEV;
2338
2339 GetExtAttrRetry:
2340         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2341                       (void **) &pSMBr);
2342         if (rc)
2343                 return rc;
2344
2345         params = 2 /* level */ +2 /* fid */;
2346         pSMB->t2.TotalDataCount = 0;
2347         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2348         /* BB find exact max data count below from sess structure BB */
2349         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2350         pSMB->t2.MaxSetupCount = 0;
2351         pSMB->t2.Reserved = 0;
2352         pSMB->t2.Flags = 0;
2353         pSMB->t2.Timeout = 0;
2354         pSMB->t2.Reserved2 = 0;
2355         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2356                         Fid) - 4);
2357         pSMB->t2.DataCount = 0;
2358         pSMB->t2.DataOffset = 0;
2359         pSMB->t2.SetupCount = 1;
2360         pSMB->t2.Reserved3 = 0;
2361         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2362         byte_count = params + 1 /* pad */ ;
2363         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2364         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2365         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2366         pSMB->Pad = 0;
2367         pSMB->Fid = netfid;
2368         pSMB->hdr.smb_buf_length += byte_count;
2369         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2370
2371         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2372                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2373         if (rc) {
2374                 cFYI(1, ("error %d in GetExtAttr", rc));
2375         } else {
2376                 /* decode response */
2377                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2378                 if (rc || (pSMBr->ByteCount < 2))
2379                 /* BB also check enough total bytes returned */
2380                         /* If rc should we check for EOPNOSUPP and
2381                         disable the srvino flag? or in caller? */
2382                         rc = -EIO;      /* bad smb */
2383                 else {
2384                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2385                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2386                         struct file_chattr_info * pfinfo;
2387                         /* BB Do we need a cast or hash here ? */
2388                         if(count != 16) {
2389                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
2390                                 rc = -EIO;
2391                                 goto GetExtAttrOut;
2392                         }
2393                         pfinfo = (struct file_chattr_info *)
2394                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2395                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2396                         *pMask = le64_to_cpu(pfinfo->mask);
2397                 }
2398         }
2399 GetExtAttrOut:
2400         cifs_buf_release(pSMB);
2401         if (rc == -EAGAIN)
2402                 goto GetExtAttrRetry;
2403         return rc;
2404 }
2405
2406
2407 #endif /* CONFIG_POSIX */
2408
2409 /* Legacy Query Path Information call for lookup to old servers such
2410    as Win9x/WinME */
2411 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2412                  const unsigned char *searchName,
2413                  FILE_ALL_INFO * pFinfo,
2414                  const struct nls_table *nls_codepage, int remap)
2415 {
2416         QUERY_INFORMATION_REQ * pSMB;
2417         QUERY_INFORMATION_RSP * pSMBr;
2418         int rc = 0;
2419         int bytes_returned;
2420         int name_len;
2421
2422         cFYI(1, ("In SMBQPath path %s", searchName)); 
2423 QInfRetry:
2424         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2425                       (void **) &pSMBr);
2426         if (rc)
2427                 return rc;
2428
2429         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2430                 name_len =
2431                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2432                                      PATH_MAX, nls_codepage, remap);
2433                 name_len++;     /* trailing null */
2434                 name_len *= 2;
2435         } else {               
2436                 name_len = strnlen(searchName, PATH_MAX);
2437                 name_len++;     /* trailing null */
2438                 strncpy(pSMB->FileName, searchName, name_len);
2439         }
2440         pSMB->BufferFormat = 0x04;
2441         name_len++; /* account for buffer type byte */  
2442         pSMB->hdr.smb_buf_length += (__u16) name_len;
2443         pSMB->ByteCount = cpu_to_le16(name_len);
2444
2445         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2446                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2447         if (rc) {
2448                 cFYI(1, ("Send error in QueryInfo = %d", rc));
2449         } else if (pFinfo) {            /* decode response */
2450                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2451                 pFinfo->AllocationSize =
2452                         cpu_to_le64(le32_to_cpu(pSMBr->size));
2453                 pFinfo->EndOfFile = pFinfo->AllocationSize;
2454                 pFinfo->Attributes =
2455                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
2456         } else
2457                 rc = -EIO; /* bad buffer passed in */
2458
2459         cifs_buf_release(pSMB);
2460
2461         if (rc == -EAGAIN)
2462                 goto QInfRetry;
2463
2464         return rc;
2465 }
2466
2467
2468
2469
2470 int
2471 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2472                  const unsigned char *searchName,
2473                  FILE_ALL_INFO * pFindData,
2474                  const struct nls_table *nls_codepage, int remap)
2475 {
2476 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2477         TRANSACTION2_QPI_REQ *pSMB = NULL;
2478         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2479         int rc = 0;
2480         int bytes_returned;
2481         int name_len;
2482         __u16 params, byte_count;
2483
2484 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2485 QPathInfoRetry:
2486         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2487                       (void **) &pSMBr);
2488         if (rc)
2489                 return rc;
2490
2491         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2492                 name_len =
2493                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2494                                      PATH_MAX, nls_codepage, remap);
2495                 name_len++;     /* trailing null */
2496                 name_len *= 2;
2497         } else {                /* BB improve the check for buffer overruns BB */
2498                 name_len = strnlen(searchName, PATH_MAX);
2499                 name_len++;     /* trailing null */
2500                 strncpy(pSMB->FileName, searchName, name_len);
2501         }
2502
2503         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2504         pSMB->TotalDataCount = 0;
2505         pSMB->MaxParameterCount = cpu_to_le16(2);
2506         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2507         pSMB->MaxSetupCount = 0;
2508         pSMB->Reserved = 0;
2509         pSMB->Flags = 0;
2510         pSMB->Timeout = 0;
2511         pSMB->Reserved2 = 0;
2512         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2513         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2514         pSMB->DataCount = 0;
2515         pSMB->DataOffset = 0;
2516         pSMB->SetupCount = 1;
2517         pSMB->Reserved3 = 0;
2518         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2519         byte_count = params + 1 /* pad */ ;
2520         pSMB->TotalParameterCount = cpu_to_le16(params);
2521         pSMB->ParameterCount = pSMB->TotalParameterCount;
2522         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2523         pSMB->Reserved4 = 0;
2524         pSMB->hdr.smb_buf_length += byte_count;
2525         pSMB->ByteCount = cpu_to_le16(byte_count);
2526
2527         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2528                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2529         if (rc) {
2530                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2531         } else {                /* decode response */
2532                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2533
2534                 if (rc || (pSMBr->ByteCount < 40)) 
2535                         rc = -EIO;      /* bad smb */
2536                 else if (pFindData){
2537                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2538                         memcpy((char *) pFindData,
2539                                (char *) &pSMBr->hdr.Protocol +
2540                                data_offset, sizeof (FILE_ALL_INFO));
2541                 } else
2542                     rc = -ENOMEM;
2543         }
2544         cifs_buf_release(pSMB);
2545         if (rc == -EAGAIN)
2546                 goto QPathInfoRetry;
2547
2548         return rc;
2549 }
2550
2551 int
2552 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2553                      const unsigned char *searchName,
2554                      FILE_UNIX_BASIC_INFO * pFindData,
2555                      const struct nls_table *nls_codepage, int remap)
2556 {
2557 /* SMB_QUERY_FILE_UNIX_BASIC */
2558         TRANSACTION2_QPI_REQ *pSMB = NULL;
2559         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2560         int rc = 0;
2561         int bytes_returned = 0;
2562         int name_len;
2563         __u16 params, byte_count;
2564
2565         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2566 UnixQPathInfoRetry:
2567         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2568                       (void **) &pSMBr);
2569         if (rc)
2570                 return rc;
2571
2572         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2573                 name_len =
2574                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2575                                   PATH_MAX, nls_codepage, remap);
2576                 name_len++;     /* trailing null */
2577                 name_len *= 2;
2578         } else {                /* BB improve the check for buffer overruns BB */
2579                 name_len = strnlen(searchName, PATH_MAX);
2580                 name_len++;     /* trailing null */
2581                 strncpy(pSMB->FileName, searchName, name_len);
2582         }
2583
2584         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2585         pSMB->TotalDataCount = 0;
2586         pSMB->MaxParameterCount = cpu_to_le16(2);
2587         /* BB find exact max SMB PDU from sess structure BB */
2588         pSMB->MaxDataCount = cpu_to_le16(4000); 
2589         pSMB->MaxSetupCount = 0;
2590         pSMB->Reserved = 0;
2591         pSMB->Flags = 0;
2592         pSMB->Timeout = 0;
2593         pSMB->Reserved2 = 0;
2594         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2595         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2596         pSMB->DataCount = 0;
2597         pSMB->DataOffset = 0;
2598         pSMB->SetupCount = 1;
2599         pSMB->Reserved3 = 0;
2600         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2601         byte_count = params + 1 /* pad */ ;
2602         pSMB->TotalParameterCount = cpu_to_le16(params);
2603         pSMB->ParameterCount = pSMB->TotalParameterCount;
2604         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2605         pSMB->Reserved4 = 0;
2606         pSMB->hdr.smb_buf_length += byte_count;
2607         pSMB->ByteCount = cpu_to_le16(byte_count);
2608
2609         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2610                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2611         if (rc) {
2612                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2613         } else {                /* decode response */
2614                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2615
2616                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2617                         rc = -EIO;      /* bad smb */
2618                 } else {
2619                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2620                         memcpy((char *) pFindData,
2621                                (char *) &pSMBr->hdr.Protocol +
2622                                data_offset,
2623                                sizeof (FILE_UNIX_BASIC_INFO));
2624                 }
2625         }
2626         cifs_buf_release(pSMB);
2627         if (rc == -EAGAIN)
2628                 goto UnixQPathInfoRetry;
2629
2630         return rc;
2631 }
2632
2633 #if 0  /* function unused at present */
2634 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2635                const char *searchName, FILE_ALL_INFO * findData,
2636                const struct nls_table *nls_codepage)
2637 {
2638 /* level 257 SMB_ */
2639         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2640         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2641         int rc = 0;
2642         int bytes_returned;
2643         int name_len;
2644         __u16 params, byte_count;
2645
2646         cFYI(1, ("In FindUnique"));
2647 findUniqueRetry:
2648         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2649                       (void **) &pSMBr);
2650         if (rc)
2651                 return rc;
2652
2653         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2654                 name_len =
2655                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2656                                   /* find define for this maxpathcomponent */
2657                                   , nls_codepage);
2658                 name_len++;     /* trailing null */
2659                 name_len *= 2;
2660         } else {                /* BB improve the check for buffer overruns BB */
2661                 name_len = strnlen(searchName, PATH_MAX);
2662                 name_len++;     /* trailing null */
2663                 strncpy(pSMB->FileName, searchName, name_len);
2664         }
2665
2666         params = 12 + name_len /* includes null */ ;
2667         pSMB->TotalDataCount = 0;       /* no EAs */
2668         pSMB->MaxParameterCount = cpu_to_le16(2);
2669         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2670         pSMB->MaxSetupCount = 0;
2671         pSMB->Reserved = 0;
2672         pSMB->Flags = 0;
2673         pSMB->Timeout = 0;
2674         pSMB->Reserved2 = 0;
2675         pSMB->ParameterOffset = cpu_to_le16(
2676          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2677         pSMB->DataCount = 0;
2678         pSMB->DataOffset = 0;
2679         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
2680         pSMB->Reserved3 = 0;
2681         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2682         byte_count = params + 1 /* pad */ ;
2683         pSMB->TotalParameterCount = cpu_to_le16(params);
2684         pSMB->ParameterCount = pSMB->TotalParameterCount;
2685         pSMB->SearchAttributes =
2686             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2687                         ATTR_DIRECTORY);
2688         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
2689         pSMB->SearchFlags = cpu_to_le16(1);
2690         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2691         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
2692         pSMB->hdr.smb_buf_length += byte_count;
2693         pSMB->ByteCount = cpu_to_le16(byte_count);
2694
2695         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2696                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2697
2698         if (rc) {
2699                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2700         } else {                /* decode response */
2701                 cifs_stats_inc(&tcon->num_ffirst);
2702                 /* BB fill in */
2703         }
2704
2705         cifs_buf_release(pSMB);
2706         if (rc == -EAGAIN)
2707                 goto findUniqueRetry;
2708
2709         return rc;
2710 }
2711 #endif /* end unused (temporarily) function */
2712
2713 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2714 int
2715 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2716               const char *searchName, 
2717               const struct nls_table *nls_codepage,
2718               __u16 *   pnetfid,
2719               struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2720 {
2721 /* level 257 SMB_ */
2722         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2723         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2724         T2_FFIRST_RSP_PARMS * parms;
2725         int rc = 0;
2726         int bytes_returned = 0;
2727         int name_len;
2728         __u16 params, byte_count;
2729
2730         cFYI(1, ("In FindFirst for %s",searchName));
2731
2732 findFirstRetry:
2733         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2734                       (void **) &pSMBr);
2735         if (rc)
2736                 return rc;
2737
2738         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2739                 name_len =
2740                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2741                                  PATH_MAX, nls_codepage, remap);
2742                 /* We can not add the asterik earlier in case
2743                 it got remapped to 0xF03A as if it were part of the
2744                 directory name instead of a wildcard */
2745                 name_len *= 2;
2746                 pSMB->FileName[name_len] = dirsep;
2747                 pSMB->FileName[name_len+1] = 0;
2748                 pSMB->FileName[name_len+2] = '*';
2749                 pSMB->FileName[name_len+3] = 0;
2750                 name_len += 4; /* now the trailing null */
2751                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2752                 pSMB->FileName[name_len+1] = 0;
2753                 name_len += 2;
2754         } else {        /* BB add check for overrun of SMB buf BB */
2755                 name_len = strnlen(searchName, PATH_MAX);
2756 /* BB fix here and in unicode clause above ie
2757                 if(name_len > buffersize-header)
2758                         free buffer exit; BB */
2759                 strncpy(pSMB->FileName, searchName, name_len);
2760                 pSMB->FileName[name_len] = dirsep;
2761                 pSMB->FileName[name_len+1] = '*';
2762                 pSMB->FileName[name_len+2] = 0;
2763                 name_len += 3;
2764         }
2765
2766         params = 12 + name_len /* includes null */ ;
2767         pSMB->TotalDataCount = 0;       /* no EAs */
2768         pSMB->MaxParameterCount = cpu_to_le16(10);
2769         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2770                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2771         pSMB->MaxSetupCount = 0;
2772         pSMB->Reserved = 0;
2773         pSMB->Flags = 0;
2774         pSMB->Timeout = 0;
2775         pSMB->Reserved2 = 0;
2776         byte_count = params + 1 /* pad */ ;
2777         pSMB->TotalParameterCount = cpu_to_le16(params);
2778         pSMB->ParameterCount = pSMB->TotalParameterCount;
2779         pSMB->ParameterOffset = cpu_to_le16(
2780           offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2781         pSMB->DataCount = 0;
2782         pSMB->DataOffset = 0;
2783         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
2784         pSMB->Reserved3 = 0;
2785         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2786         pSMB->SearchAttributes =
2787             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2788                         ATTR_DIRECTORY);
2789         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2790         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
2791                 CIFS_SEARCH_RETURN_RESUME);
2792         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2793
2794         /* BB what should we set StorageType to? Does it matter? BB */
2795         pSMB->SearchStorageType = 0;
2796         pSMB->hdr.smb_buf_length += byte_count;
2797         pSMB->ByteCount = cpu_to_le16(byte_count);
2798
2799         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2800                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2801         cifs_stats_inc(&tcon->num_ffirst);
2802
2803         if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2804                 /* BB Add code to handle unsupported level rc */
2805                 cFYI(1, ("Error in FindFirst = %d", rc));
2806
2807                 if (pSMB)
2808                         cifs_buf_release(pSMB);
2809
2810                 /* BB eventually could optimize out free and realloc of buf */
2811                 /*    for this case */
2812                 if (rc == -EAGAIN)
2813                         goto findFirstRetry;
2814         } else { /* decode response */
2815                 /* BB remember to free buffer if error BB */
2816                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2817                 if(rc == 0) {
2818                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2819                                 psrch_inf->unicode = TRUE;
2820                         else
2821                                 psrch_inf->unicode = FALSE;
2822
2823                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2824                         psrch_inf->srch_entries_start = 
2825                                 (char *) &pSMBr->hdr.Protocol + 
2826                                         le16_to_cpu(pSMBr->t2.DataOffset);
2827                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2828                                le16_to_cpu(pSMBr->t2.ParameterOffset));
2829
2830                         if(parms->EndofSearch)
2831                                 psrch_inf->endOfSearch = TRUE;
2832                         else
2833                                 psrch_inf->endOfSearch = FALSE;
2834
2835                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2836                         psrch_inf->index_of_last_entry = 
2837                                 psrch_inf->entries_in_buffer;
2838                         *pnetfid = parms->SearchHandle;
2839                 } else {
2840                         cifs_buf_release(pSMB);
2841                 }
2842         }
2843
2844         return rc;
2845 }
2846
2847 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2848             __u16 searchHandle, struct cifs_search_info * psrch_inf)
2849 {
2850         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2851         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2852         T2_FNEXT_RSP_PARMS * parms;
2853         char *response_data;
2854         int rc = 0;
2855         int bytes_returned, name_len;
2856         __u16 params, byte_count;
2857
2858         cFYI(1, ("In FindNext"));
2859
2860         if(psrch_inf->endOfSearch == TRUE)
2861                 return -ENOENT;
2862
2863         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2864                 (void **) &pSMBr);
2865         if (rc)
2866                 return rc;
2867
2868         params = 14;    /* includes 2 bytes of null string, converted to LE below */
2869         byte_count = 0;
2870         pSMB->TotalDataCount = 0;       /* no EAs */
2871         pSMB->MaxParameterCount = cpu_to_le16(8);
2872         pSMB->MaxDataCount =
2873             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2874         pSMB->MaxSetupCount = 0;
2875         pSMB->Reserved = 0;
2876         pSMB->Flags = 0;
2877         pSMB->Timeout = 0;
2878         pSMB->Reserved2 = 0;
2879         pSMB->ParameterOffset =  cpu_to_le16(
2880               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2881         pSMB->DataCount = 0;
2882         pSMB->DataOffset = 0;
2883         pSMB->SetupCount = 1;
2884         pSMB->Reserved3 = 0;
2885         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2886         pSMB->SearchHandle = searchHandle;      /* always kept as le */
2887         pSMB->SearchCount =
2888                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2889         /* test for Unix extensions */
2890 /*      if (tcon->ses->capabilities & CAP_UNIX) {
2891                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2892                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2893         } else {
2894                 pSMB->InformationLevel =
2895                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2896                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2897         } */
2898         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2899         pSMB->ResumeKey = psrch_inf->resume_key;
2900         pSMB->SearchFlags =
2901               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2902
2903         name_len = psrch_inf->resume_name_len;
2904         params += name_len;
2905         if(name_len < PATH_MAX) {
2906                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2907                 byte_count += name_len;
2908                 /* 14 byte parm len above enough for 2 byte null terminator */
2909                 pSMB->ResumeFileName[name_len] = 0;
2910                 pSMB->ResumeFileName[name_len+1] = 0;
2911         } else {
2912                 rc = -EINVAL;
2913                 goto FNext2_err_exit;
2914         }
2915         byte_count = params + 1 /* pad */ ;
2916         pSMB->TotalParameterCount = cpu_to_le16(params);
2917         pSMB->ParameterCount = pSMB->TotalParameterCount;
2918         pSMB->hdr.smb_buf_length += byte_count;
2919         pSMB->ByteCount = cpu_to_le16(byte_count);
2920                                                                                               
2921         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2922                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2923         cifs_stats_inc(&tcon->num_fnext);
2924         if (rc) {
2925                 if (rc == -EBADF) {
2926                         psrch_inf->endOfSearch = TRUE;
2927                         rc = 0; /* search probably was closed at end of search above */
2928                 } else
2929                         cFYI(1, ("FindNext returned = %d", rc));
2930         } else {                /* decode response */
2931                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2932                 
2933                 if(rc == 0) {
2934                         /* BB fixme add lock for file (srch_info) struct here */
2935                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2936                                 psrch_inf->unicode = TRUE;
2937                         else
2938                                 psrch_inf->unicode = FALSE;
2939                         response_data = (char *) &pSMBr->hdr.Protocol +
2940                                le16_to_cpu(pSMBr->t2.ParameterOffset);
2941                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
2942                         response_data = (char *)&pSMBr->hdr.Protocol +
2943                                 le16_to_cpu(pSMBr->t2.DataOffset);
2944                         cifs_buf_release(psrch_inf->ntwrk_buf_start);
2945                         psrch_inf->srch_entries_start = response_data;
2946                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
2947                         if(parms->EndofSearch)
2948                                 psrch_inf->endOfSearch = TRUE;
2949                         else
2950                                 psrch_inf->endOfSearch = FALSE;
2951                                                                                               
2952                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2953                         psrch_inf->index_of_last_entry +=
2954                                 psrch_inf->entries_in_buffer;
2955 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2956
2957                         /* BB fixme add unlock here */
2958                 }
2959
2960         }
2961
2962         /* BB On error, should we leave previous search buf (and count and
2963         last entry fields) intact or free the previous one? */
2964
2965         /* Note: On -EAGAIN error only caller can retry on handle based calls
2966         since file handle passed in no longer valid */
2967 FNext2_err_exit:
2968         if (rc != 0)
2969                 cifs_buf_release(pSMB);
2970                                                                                               
2971         return rc;
2972 }
2973
2974 int
2975 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2976 {
2977         int rc = 0;
2978         FINDCLOSE_REQ *pSMB = NULL;
2979         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2980         int bytes_returned;
2981
2982         cFYI(1, ("In CIFSSMBFindClose"));
2983         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2984
2985         /* no sense returning error if session restarted
2986                 as file handle has been closed */
2987         if(rc == -EAGAIN)
2988                 return 0;
2989         if (rc)
2990                 return rc;
2991
2992         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
2993         pSMB->FileID = searchHandle;
2994         pSMB->ByteCount = 0;
2995         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2996                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2997         if (rc) {
2998                 cERROR(1, ("Send error in FindClose = %d", rc));
2999         }
3000         cifs_stats_inc(&tcon->num_fclose);
3001         cifs_small_buf_release(pSMB);
3002
3003         /* Since session is dead, search handle closed on server already */
3004         if (rc == -EAGAIN)
3005                 rc = 0;
3006
3007         return rc;
3008 }
3009
3010 int
3011 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3012                 const unsigned char *searchName,
3013                 __u64 * inode_number,
3014                 const struct nls_table *nls_codepage, int remap)
3015 {
3016         int rc = 0;
3017         TRANSACTION2_QPI_REQ *pSMB = NULL;
3018         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3019         int name_len, bytes_returned;
3020         __u16 params, byte_count;
3021
3022         cFYI(1,("In GetSrvInodeNum for %s",searchName));
3023         if(tcon == NULL)
3024                 return -ENODEV; 
3025
3026 GetInodeNumberRetry:
3027         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3028                       (void **) &pSMBr);
3029         if (rc)
3030                 return rc;
3031
3032
3033         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3034                 name_len =
3035                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3036                                 PATH_MAX,nls_codepage, remap);
3037                 name_len++;     /* trailing null */