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