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