[CIFS] Convert remaining places in fs/cifs from
[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);
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 /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ {
1080                 *buf = iov[0].iov_base;
1081                 if(resp_buf_type == CIFS_SMALL_BUFFER)
1082                         *pbuf_type = CIFS_SMALL_BUFFER;
1083                 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1084                         *pbuf_type = CIFS_LARGE_BUFFER;
1085         }
1086
1087         /* Note: On -EAGAIN error only caller can retry on handle based calls
1088                 since file handle passed in no longer valid */
1089         return rc;
1090 }
1091
1092
1093 int
1094 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1095              const int netfid, const unsigned int count,
1096              const __u64 offset, unsigned int *nbytes, const char *buf,
1097              const char __user * ubuf, const int long_op)
1098 {
1099         int rc = -EACCES;
1100         WRITE_REQ *pSMB = NULL;
1101         WRITE_RSP *pSMBr = NULL;
1102         int bytes_returned, wct;
1103         __u32 bytes_sent;
1104         __u16 byte_count;
1105
1106         /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1107         if(tcon->ses == NULL)
1108                 return -ECONNABORTED;
1109
1110         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1111                 wct = 14;
1112         else
1113                 wct = 12;
1114
1115         rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1116                       (void **) &pSMBr);
1117         if (rc)
1118                 return rc;
1119         /* tcon and ses pointer are checked in smb_init */
1120         if (tcon->ses->server == NULL)
1121                 return -ECONNABORTED;
1122
1123         pSMB->AndXCommand = 0xFF;       /* none */
1124         pSMB->Fid = netfid;
1125         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1126         if(wct == 14) 
1127                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1128         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1129                 return -EIO;
1130         
1131         pSMB->Reserved = 0xFFFFFFFF;
1132         pSMB->WriteMode = 0;
1133         pSMB->Remaining = 0;
1134
1135         /* Can increase buffer size if buffer is big enough in some cases - ie we 
1136         can send more if LARGE_WRITE_X capability returned by the server and if
1137         our buffer is big enough or if we convert to iovecs on socket writes
1138         and eliminate the copy to the CIFS buffer */
1139         if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1140                 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1141         } else {
1142                 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1143                          & ~0xFF;
1144         }
1145
1146         if (bytes_sent > count)
1147                 bytes_sent = count;
1148         pSMB->DataOffset =
1149                 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1150         if(buf)
1151             memcpy(pSMB->Data,buf,bytes_sent);
1152         else if(ubuf) {
1153                 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1154                         cifs_buf_release(pSMB);
1155                         return -EFAULT;
1156                 }
1157         } else if (count != 0) {
1158                 /* No buffer */
1159                 cifs_buf_release(pSMB);
1160                 return -EINVAL;
1161         } /* else setting file size with write of zero bytes */
1162         if(wct == 14)
1163                 byte_count = bytes_sent + 1; /* pad */
1164         else /* wct == 12 */ {
1165                 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1166         }
1167         pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1168         pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1169         pSMB->hdr.smb_buf_length += byte_count;
1170
1171         if(wct == 14)
1172                 pSMB->ByteCount = cpu_to_le16(byte_count);
1173         else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
1174                 struct smb_com_writex_req * pSMBW = 
1175                         (struct smb_com_writex_req *)pSMB;
1176                 pSMBW->ByteCount = cpu_to_le16(byte_count);
1177         }
1178
1179         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1180                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1181         cifs_stats_inc(&tcon->num_writes);
1182         if (rc) {
1183                 cFYI(1, ("Send error in write = %d", rc));
1184                 *nbytes = 0;
1185         } else {
1186                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1187                 *nbytes = (*nbytes) << 16;
1188                 *nbytes += le16_to_cpu(pSMBr->Count);
1189         }
1190
1191         cifs_buf_release(pSMB);
1192
1193         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1194                 since file handle passed in no longer valid */
1195
1196         return rc;
1197 }
1198
1199 int
1200 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1201              const int netfid, const unsigned int count,
1202              const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1203              int n_vec, const int long_op)
1204 {
1205         int rc = -EACCES;
1206         WRITE_REQ *pSMB = NULL;
1207         int wct;
1208         int smb_hdr_len;
1209         int resp_buf_type = 0;
1210
1211         cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1212
1213         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1214                 wct = 14;
1215         else
1216                 wct = 12;
1217         rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1218         if (rc)
1219                 return rc;
1220         /* tcon and ses pointer are checked in smb_init */
1221         if (tcon->ses->server == NULL)
1222                 return -ECONNABORTED;
1223
1224         pSMB->AndXCommand = 0xFF;       /* none */
1225         pSMB->Fid = netfid;
1226         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1227         if(wct == 14)
1228                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1229         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1230                 return -EIO;
1231         pSMB->Reserved = 0xFFFFFFFF;
1232         pSMB->WriteMode = 0;
1233         pSMB->Remaining = 0;
1234
1235         pSMB->DataOffset =
1236             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1237
1238         pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1239         pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1240         smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1241         if(wct == 14)
1242                 pSMB->hdr.smb_buf_length += count+1;
1243         else /* wct == 12 */
1244                 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ 
1245         if(wct == 14)
1246                 pSMB->ByteCount = cpu_to_le16(count + 1);
1247         else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1248                 struct smb_com_writex_req * pSMBW =
1249                                 (struct smb_com_writex_req *)pSMB;
1250                 pSMBW->ByteCount = cpu_to_le16(count + 5);
1251         }
1252         iov[0].iov_base = pSMB;
1253         if(wct == 14)
1254                 iov[0].iov_len = smb_hdr_len + 4;
1255         else /* wct == 12 pad bigger by four bytes */
1256                 iov[0].iov_len = smb_hdr_len + 8;
1257         
1258
1259         rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1260                           long_op);
1261         cifs_stats_inc(&tcon->num_writes);
1262         if (rc) {
1263                 cFYI(1, ("Send error Write2 = %d", rc));
1264                 *nbytes = 0;
1265         } else if(resp_buf_type == 0) {
1266                 /* presumably this can not happen, but best to be safe */
1267                 rc = -EIO;
1268                 *nbytes = 0;
1269         } else {
1270                 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1271                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1272                 *nbytes = (*nbytes) << 16;
1273                 *nbytes += le16_to_cpu(pSMBr->Count);
1274         } 
1275
1276         cifs_small_buf_release(pSMB);
1277         if(resp_buf_type == CIFS_SMALL_BUFFER)
1278                 cifs_small_buf_release(iov[0].iov_base);
1279         else if(resp_buf_type == CIFS_LARGE_BUFFER)
1280                 cifs_buf_release(iov[0].iov_base);
1281
1282         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1283                 since file handle passed in no longer valid */
1284
1285         return rc;
1286 }
1287
1288
1289 int
1290 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1291             const __u16 smb_file_id, const __u64 len,
1292             const __u64 offset, const __u32 numUnlock,
1293             const __u32 numLock, const __u8 lockType, const int waitFlag)
1294 {
1295         int rc = 0;
1296         LOCK_REQ *pSMB = NULL;
1297         LOCK_RSP *pSMBr = NULL;
1298         int bytes_returned;
1299         int timeout = 0;
1300         __u16 count;
1301
1302         cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1303         rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1304
1305         if (rc)
1306                 return rc;
1307
1308         pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1309
1310         if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1311                 timeout = -1; /* no response expected */
1312                 pSMB->Timeout = 0;
1313         } else if (waitFlag == TRUE) {
1314                 timeout = 3;  /* blocking operation, no timeout */
1315                 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1316         } else {
1317                 pSMB->Timeout = 0;
1318         }
1319
1320         pSMB->NumberOfLocks = cpu_to_le16(numLock);
1321         pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1322         pSMB->LockType = lockType;
1323         pSMB->AndXCommand = 0xFF;       /* none */
1324         pSMB->Fid = smb_file_id; /* netfid stays le */
1325
1326         if((numLock != 0) || (numUnlock != 0)) {
1327                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1328                 /* BB where to store pid high? */
1329                 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1330                 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1331                 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1332                 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1333                 count = sizeof(LOCKING_ANDX_RANGE);
1334         } else {
1335                 /* oplock break */
1336                 count = 0;
1337         }
1338         pSMB->hdr.smb_buf_length += count;
1339         pSMB->ByteCount = cpu_to_le16(count);
1340
1341         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1342                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1343         cifs_stats_inc(&tcon->num_locks);
1344         if (rc) {
1345                 cFYI(1, ("Send error in Lock = %d", rc));
1346         }
1347         cifs_small_buf_release(pSMB);
1348
1349         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1350         since file handle passed in no longer valid */
1351         return rc;
1352 }
1353
1354 int
1355 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1356 {
1357         int rc = 0;
1358         CLOSE_REQ *pSMB = NULL;
1359         CLOSE_RSP *pSMBr = NULL;
1360         int bytes_returned;
1361         cFYI(1, ("In CIFSSMBClose"));
1362
1363 /* do not retry on dead session on close */
1364         rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1365         if(rc == -EAGAIN)
1366                 return 0;
1367         if (rc)
1368                 return rc;
1369
1370         pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1371
1372         pSMB->FileID = (__u16) smb_file_id;
1373         pSMB->LastWriteTime = 0;
1374         pSMB->ByteCount = 0;
1375         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1376                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1377         cifs_stats_inc(&tcon->num_closes);
1378         if (rc) {
1379                 if(rc!=-EINTR) {
1380                         /* EINTR is expected when user ctl-c to kill app */
1381                         cERROR(1, ("Send error in Close = %d", rc));
1382                 }
1383         }
1384
1385         cifs_small_buf_release(pSMB);
1386
1387         /* Since session is dead, file will be closed on server already */
1388         if(rc == -EAGAIN)
1389                 rc = 0;
1390
1391         return rc;
1392 }
1393
1394 int
1395 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1396               const char *fromName, const char *toName,
1397               const struct nls_table *nls_codepage, int remap)
1398 {
1399         int rc = 0;
1400         RENAME_REQ *pSMB = NULL;
1401         RENAME_RSP *pSMBr = NULL;
1402         int bytes_returned;
1403         int name_len, name_len2;
1404         __u16 count;
1405
1406         cFYI(1, ("In CIFSSMBRename"));
1407 renameRetry:
1408         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1409                       (void **) &pSMBr);
1410         if (rc)
1411                 return rc;
1412
1413         pSMB->BufferFormat = 0x04;
1414         pSMB->SearchAttributes =
1415             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1416                         ATTR_DIRECTORY);
1417
1418         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1419                 name_len =
1420                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, 
1421                                      PATH_MAX, nls_codepage, remap);
1422                 name_len++;     /* trailing null */
1423                 name_len *= 2;
1424                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1425         /* protocol requires ASCII signature byte on Unicode string */
1426                 pSMB->OldFileName[name_len + 1] = 0x00;
1427                 name_len2 =
1428                     cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1429                                      toName, PATH_MAX, nls_codepage, remap);
1430                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1431                 name_len2 *= 2; /* convert to bytes */
1432         } else {                /* BB improve the check for buffer overruns BB */
1433                 name_len = strnlen(fromName, PATH_MAX);
1434                 name_len++;     /* trailing null */
1435                 strncpy(pSMB->OldFileName, fromName, name_len);
1436                 name_len2 = strnlen(toName, PATH_MAX);
1437                 name_len2++;    /* trailing null */
1438                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1439                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1440                 name_len2++;    /* trailing null */
1441                 name_len2++;    /* signature byte */
1442         }
1443
1444         count = 1 /* 1st signature byte */  + name_len + name_len2;
1445         pSMB->hdr.smb_buf_length += count;
1446         pSMB->ByteCount = cpu_to_le16(count);
1447
1448         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1449                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1450         cifs_stats_inc(&tcon->num_renames);
1451         if (rc) {
1452                 cFYI(1, ("Send error in rename = %d", rc));
1453         } 
1454
1455         cifs_buf_release(pSMB);
1456
1457         if (rc == -EAGAIN)
1458                 goto renameRetry;
1459
1460         return rc;
1461 }
1462
1463 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
1464                 int netfid, char * target_name, 
1465                 const struct nls_table * nls_codepage, int remap)
1466 {
1467         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1468         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1469         struct set_file_rename * rename_info;
1470         char *data_offset;
1471         char dummy_string[30];
1472         int rc = 0;
1473         int bytes_returned = 0;
1474         int len_of_str;
1475         __u16 params, param_offset, offset, count, byte_count;
1476
1477         cFYI(1, ("Rename to File by handle"));
1478         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1479                         (void **) &pSMBr);
1480         if (rc)
1481                 return rc;
1482
1483         params = 6;
1484         pSMB->MaxSetupCount = 0;
1485         pSMB->Reserved = 0;
1486         pSMB->Flags = 0;
1487         pSMB->Timeout = 0;
1488         pSMB->Reserved2 = 0;
1489         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1490         offset = param_offset + params;
1491
1492         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1493         rename_info = (struct set_file_rename *) data_offset;
1494         pSMB->MaxParameterCount = cpu_to_le16(2);
1495         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1496         pSMB->SetupCount = 1;
1497         pSMB->Reserved3 = 0;
1498         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1499         byte_count = 3 /* pad */  + params;
1500         pSMB->ParameterCount = cpu_to_le16(params);
1501         pSMB->TotalParameterCount = pSMB->ParameterCount;
1502         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1503         pSMB->DataOffset = cpu_to_le16(offset);
1504         /* construct random name ".cifs_tmp<inodenum><mid>" */
1505         rename_info->overwrite = cpu_to_le32(1);
1506         rename_info->root_fid  = 0;
1507         /* unicode only call */
1508         if(target_name == NULL) {
1509                 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1510                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1511                                         dummy_string, 24, nls_codepage, remap);
1512         } else {
1513                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1514                                         target_name, PATH_MAX, nls_codepage, remap);
1515         }
1516         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1517         count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1518         byte_count += count;
1519         pSMB->DataCount = cpu_to_le16(count);
1520         pSMB->TotalDataCount = pSMB->DataCount;
1521         pSMB->Fid = netfid;
1522         pSMB->InformationLevel =
1523                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1524         pSMB->Reserved4 = 0;
1525         pSMB->hdr.smb_buf_length += byte_count;
1526         pSMB->ByteCount = cpu_to_le16(byte_count);
1527         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1528                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1529         cifs_stats_inc(&pTcon->num_t2renames);
1530         if (rc) {
1531                 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1532         }
1533
1534         cifs_buf_release(pSMB);
1535
1536         /* Note: On -EAGAIN error only caller can retry on handle based calls
1537                 since file handle passed in no longer valid */
1538
1539         return rc;
1540 }
1541
1542 int
1543 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
1544             const __u16 target_tid, const char *toName, const int flags,
1545             const struct nls_table *nls_codepage, int remap)
1546 {
1547         int rc = 0;
1548         COPY_REQ *pSMB = NULL;
1549         COPY_RSP *pSMBr = NULL;
1550         int bytes_returned;
1551         int name_len, name_len2;
1552         __u16 count;
1553
1554         cFYI(1, ("In CIFSSMBCopy"));
1555 copyRetry:
1556         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1557                         (void **) &pSMBr);
1558         if (rc)
1559                 return rc;
1560
1561         pSMB->BufferFormat = 0x04;
1562         pSMB->Tid2 = target_tid;
1563
1564         pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1565
1566         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1567                 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, 
1568                                             fromName, PATH_MAX, nls_codepage,
1569                                             remap);
1570                 name_len++;     /* trailing null */
1571                 name_len *= 2;
1572                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1573                 /* protocol requires ASCII signature byte on Unicode string */
1574                 pSMB->OldFileName[name_len + 1] = 0x00;
1575                 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1576                                 toName, PATH_MAX, nls_codepage, remap);
1577                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1578                 name_len2 *= 2; /* convert to bytes */
1579         } else {                /* BB improve the check for buffer overruns BB */
1580                 name_len = strnlen(fromName, PATH_MAX);
1581                 name_len++;     /* trailing null */
1582                 strncpy(pSMB->OldFileName, fromName, name_len);
1583                 name_len2 = strnlen(toName, PATH_MAX);
1584                 name_len2++;    /* trailing null */
1585                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1586                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1587                 name_len2++;    /* trailing null */
1588                 name_len2++;    /* signature byte */
1589         }
1590
1591         count = 1 /* 1st signature byte */  + name_len + name_len2;
1592         pSMB->hdr.smb_buf_length += count;
1593         pSMB->ByteCount = cpu_to_le16(count);
1594
1595         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1596                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1597         if (rc) {
1598                 cFYI(1, ("Send error in copy = %d with %d files copied",
1599                         rc, le16_to_cpu(pSMBr->CopyCount)));
1600         }
1601         if (pSMB)
1602                 cifs_buf_release(pSMB);
1603
1604         if (rc == -EAGAIN)
1605                 goto copyRetry;
1606
1607         return rc;
1608 }
1609
1610 int
1611 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1612                       const char *fromName, const char *toName,
1613                       const struct nls_table *nls_codepage)
1614 {
1615         TRANSACTION2_SPI_REQ *pSMB = NULL;
1616         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1617         char *data_offset;
1618         int name_len;
1619         int name_len_target;
1620         int rc = 0;
1621         int bytes_returned = 0;
1622         __u16 params, param_offset, offset, byte_count;
1623
1624         cFYI(1, ("In Symlink Unix style"));
1625 createSymLinkRetry:
1626         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1627                       (void **) &pSMBr);
1628         if (rc)
1629                 return rc;
1630
1631         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1632                 name_len =
1633                     cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1634                                   /* find define for this maxpathcomponent */
1635                                   , nls_codepage);
1636                 name_len++;     /* trailing null */
1637                 name_len *= 2;
1638
1639         } else {                /* BB improve the check for buffer overruns BB */
1640                 name_len = strnlen(fromName, PATH_MAX);
1641                 name_len++;     /* trailing null */
1642                 strncpy(pSMB->FileName, fromName, name_len);
1643         }
1644         params = 6 + name_len;
1645         pSMB->MaxSetupCount = 0;
1646         pSMB->Reserved = 0;
1647         pSMB->Flags = 0;
1648         pSMB->Timeout = 0;
1649         pSMB->Reserved2 = 0;
1650         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1651                                      InformationLevel) - 4;
1652         offset = param_offset + params;
1653
1654         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1655         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1656                 name_len_target =
1657                     cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1658                                   /* find define for this maxpathcomponent */
1659                                   , nls_codepage);
1660                 name_len_target++;      /* trailing null */
1661                 name_len_target *= 2;
1662         } else {                /* BB improve the check for buffer overruns BB */
1663                 name_len_target = strnlen(toName, PATH_MAX);
1664                 name_len_target++;      /* trailing null */
1665                 strncpy(data_offset, toName, name_len_target);
1666         }
1667
1668         pSMB->MaxParameterCount = cpu_to_le16(2);
1669         /* BB find exact max on data count below from sess */
1670         pSMB->MaxDataCount = cpu_to_le16(1000);
1671         pSMB->SetupCount = 1;
1672         pSMB->Reserved3 = 0;
1673         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1674         byte_count = 3 /* pad */  + params + name_len_target;
1675         pSMB->DataCount = cpu_to_le16(name_len_target);
1676         pSMB->ParameterCount = cpu_to_le16(params);
1677         pSMB->TotalDataCount = pSMB->DataCount;
1678         pSMB->TotalParameterCount = pSMB->ParameterCount;
1679         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1680         pSMB->DataOffset = cpu_to_le16(offset);
1681         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1682         pSMB->Reserved4 = 0;
1683         pSMB->hdr.smb_buf_length += byte_count;
1684         pSMB->ByteCount = cpu_to_le16(byte_count);
1685         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1686                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1687         cifs_stats_inc(&tcon->num_symlinks);
1688         if (rc) {
1689                 cFYI(1,
1690                      ("Send error in SetPathInfo (create symlink) = %d",
1691                       rc));
1692         }
1693
1694         if (pSMB)
1695                 cifs_buf_release(pSMB);
1696
1697         if (rc == -EAGAIN)
1698                 goto createSymLinkRetry;
1699
1700         return rc;
1701 }
1702
1703 int
1704 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1705                        const char *fromName, const char *toName,
1706                        const struct nls_table *nls_codepage, int remap)
1707 {
1708         TRANSACTION2_SPI_REQ *pSMB = NULL;
1709         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1710         char *data_offset;
1711         int name_len;
1712         int name_len_target;
1713         int rc = 0;
1714         int bytes_returned = 0;
1715         __u16 params, param_offset, offset, byte_count;
1716
1717         cFYI(1, ("In Create Hard link Unix style"));
1718 createHardLinkRetry:
1719         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1720                       (void **) &pSMBr);
1721         if (rc)
1722                 return rc;
1723
1724         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1725                 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1726                                             PATH_MAX, nls_codepage, remap);
1727                 name_len++;     /* trailing null */
1728                 name_len *= 2;
1729
1730         } else {                /* BB improve the check for buffer overruns BB */
1731                 name_len = strnlen(toName, PATH_MAX);
1732                 name_len++;     /* trailing null */
1733                 strncpy(pSMB->FileName, toName, name_len);
1734         }
1735         params = 6 + name_len;
1736         pSMB->MaxSetupCount = 0;
1737         pSMB->Reserved = 0;
1738         pSMB->Flags = 0;
1739         pSMB->Timeout = 0;
1740         pSMB->Reserved2 = 0;
1741         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1742                                      InformationLevel) - 4;
1743         offset = param_offset + params;
1744
1745         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1746         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1747                 name_len_target =
1748                     cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1749                                      nls_codepage, remap);
1750                 name_len_target++;      /* trailing null */
1751                 name_len_target *= 2;
1752         } else {                /* BB improve the check for buffer overruns BB */
1753                 name_len_target = strnlen(fromName, PATH_MAX);
1754                 name_len_target++;      /* trailing null */
1755                 strncpy(data_offset, fromName, name_len_target);
1756         }
1757
1758         pSMB->MaxParameterCount = cpu_to_le16(2);
1759         /* BB find exact max on data count below from sess*/
1760         pSMB->MaxDataCount = cpu_to_le16(1000);
1761         pSMB->SetupCount = 1;
1762         pSMB->Reserved3 = 0;
1763         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1764         byte_count = 3 /* pad */  + params + name_len_target;
1765         pSMB->ParameterCount = cpu_to_le16(params);
1766         pSMB->TotalParameterCount = pSMB->ParameterCount;
1767         pSMB->DataCount = cpu_to_le16(name_len_target);
1768         pSMB->TotalDataCount = pSMB->DataCount;
1769         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1770         pSMB->DataOffset = cpu_to_le16(offset);
1771         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1772         pSMB->Reserved4 = 0;
1773         pSMB->hdr.smb_buf_length += byte_count;
1774         pSMB->ByteCount = cpu_to_le16(byte_count);
1775         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1776                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1777         cifs_stats_inc(&tcon->num_hardlinks);
1778         if (rc) {
1779                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1780         }
1781
1782         cifs_buf_release(pSMB);
1783         if (rc == -EAGAIN)
1784                 goto createHardLinkRetry;
1785
1786         return rc;
1787 }
1788
1789 int
1790 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1791                    const char *fromName, const char *toName,
1792                    const struct nls_table *nls_codepage, int remap)
1793 {
1794         int rc = 0;
1795         NT_RENAME_REQ *pSMB = NULL;
1796         RENAME_RSP *pSMBr = NULL;
1797         int bytes_returned;
1798         int name_len, name_len2;
1799         __u16 count;
1800
1801         cFYI(1, ("In CIFSCreateHardLink"));
1802 winCreateHardLinkRetry:
1803
1804         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1805                       (void **) &pSMBr);
1806         if (rc)
1807                 return rc;
1808
1809         pSMB->SearchAttributes =
1810             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1811                         ATTR_DIRECTORY);
1812         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1813         pSMB->ClusterCount = 0;
1814
1815         pSMB->BufferFormat = 0x04;
1816
1817         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1818                 name_len =
1819                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1820                                      PATH_MAX, nls_codepage, remap);
1821                 name_len++;     /* trailing null */
1822                 name_len *= 2;
1823                 pSMB->OldFileName[name_len] = 0;        /* pad */
1824                 pSMB->OldFileName[name_len + 1] = 0x04; 
1825                 name_len2 =
1826                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1827                                      toName, PATH_MAX, nls_codepage, remap);
1828                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1829                 name_len2 *= 2; /* convert to bytes */
1830         } else {                /* BB improve the check for buffer overruns BB */
1831                 name_len = strnlen(fromName, PATH_MAX);
1832                 name_len++;     /* trailing null */
1833                 strncpy(pSMB->OldFileName, fromName, name_len);
1834                 name_len2 = strnlen(toName, PATH_MAX);
1835                 name_len2++;    /* trailing null */
1836                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
1837                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1838                 name_len2++;    /* trailing null */
1839                 name_len2++;    /* signature byte */
1840         }
1841
1842         count = 1 /* string type byte */  + name_len + name_len2;
1843         pSMB->hdr.smb_buf_length += count;
1844         pSMB->ByteCount = cpu_to_le16(count);
1845
1846         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1847                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1848         cifs_stats_inc(&tcon->num_hardlinks);
1849         if (rc) {
1850                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1851         }
1852         cifs_buf_release(pSMB);
1853         if (rc == -EAGAIN)
1854                 goto winCreateHardLinkRetry;
1855
1856         return rc;
1857 }
1858
1859 int
1860 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1861                         const unsigned char *searchName,
1862                         char *symlinkinfo, const int buflen,
1863                         const struct nls_table *nls_codepage)
1864 {
1865 /* SMB_QUERY_FILE_UNIX_LINK */
1866         TRANSACTION2_QPI_REQ *pSMB = NULL;
1867         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1868         int rc = 0;
1869         int bytes_returned;
1870         int name_len;
1871         __u16 params, byte_count;
1872
1873         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1874
1875 querySymLinkRetry:
1876         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1877                       (void **) &pSMBr);
1878         if (rc)
1879                 return rc;
1880
1881         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1882                 name_len =
1883                     cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
1884                                   /* find define for this maxpathcomponent */
1885                                   , nls_codepage);
1886                 name_len++;     /* trailing null */
1887                 name_len *= 2;
1888         } else {                /* BB improve the check for buffer overruns BB */
1889                 name_len = strnlen(searchName, PATH_MAX);
1890                 name_len++;     /* trailing null */
1891                 strncpy(pSMB->FileName, searchName, name_len);
1892         }
1893
1894         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1895         pSMB->TotalDataCount = 0;
1896         pSMB->MaxParameterCount = cpu_to_le16(2);
1897         /* BB find exact max data count below from sess structure BB */
1898         pSMB->MaxDataCount = cpu_to_le16(4000);
1899         pSMB->MaxSetupCount = 0;
1900         pSMB->Reserved = 0;
1901         pSMB->Flags = 0;
1902         pSMB->Timeout = 0;
1903         pSMB->Reserved2 = 0;
1904         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1905         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1906         pSMB->DataCount = 0;
1907         pSMB->DataOffset = 0;
1908         pSMB->SetupCount = 1;
1909         pSMB->Reserved3 = 0;
1910         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1911         byte_count = params + 1 /* pad */ ;
1912         pSMB->TotalParameterCount = cpu_to_le16(params);
1913         pSMB->ParameterCount = pSMB->TotalParameterCount;
1914         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1915         pSMB->Reserved4 = 0;
1916         pSMB->hdr.smb_buf_length += byte_count;
1917         pSMB->ByteCount = cpu_to_le16(byte_count);
1918
1919         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1920                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1921         if (rc) {
1922                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1923         } else {
1924                 /* decode response */
1925
1926                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1927                 if (rc || (pSMBr->ByteCount < 2))
1928                 /* BB also check enough total bytes returned */
1929                         rc = -EIO;      /* bad smb */
1930                 else {
1931                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1932                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1933
1934                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1935                                 name_len = UniStrnlen((wchar_t *) ((char *)
1936                                         &pSMBr->hdr.Protocol +data_offset),
1937                                         min_t(const int, buflen,count) / 2);
1938                         /* BB FIXME investigate remapping reserved chars here */
1939                                 cifs_strfromUCS_le(symlinkinfo,
1940                                         (__le16 *) ((char *)&pSMBr->hdr.Protocol +
1941                                                 data_offset),
1942                                         name_len, nls_codepage);
1943                         } else {
1944                                 strncpy(symlinkinfo,
1945                                         (char *) &pSMBr->hdr.Protocol + 
1946                                                 data_offset,
1947                                         min_t(const int, buflen, count));
1948                         }
1949                         symlinkinfo[buflen] = 0;
1950         /* just in case so calling code does not go off the end of buffer */
1951                 }
1952         }
1953         cifs_buf_release(pSMB);
1954         if (rc == -EAGAIN)
1955                 goto querySymLinkRetry;
1956         return rc;
1957 }
1958
1959 /* Initialize NT TRANSACT SMB into small smb request buffer.
1960    This assumes that all NT TRANSACTS that we init here have
1961    total parm and data under about 400 bytes (to fit in small cifs
1962    buffer size), which is the case so far, it easily fits. NB:
1963         Setup words themselves and ByteCount
1964         MaxSetupCount (size of returned setup area) and
1965         MaxParameterCount (returned parms size) must be set by caller */
1966 static int 
1967 smb_init_ntransact(const __u16 sub_command, const int setup_count,
1968                    const int parm_len, struct cifsTconInfo *tcon,
1969                    void ** ret_buf)
1970 {
1971         int rc;
1972         __u32 temp_offset;
1973         struct smb_com_ntransact_req * pSMB;
1974
1975         rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
1976                                 (void **)&pSMB);
1977         if (rc)
1978                 return rc;
1979         *ret_buf = (void *)pSMB;
1980         pSMB->Reserved = 0;
1981         pSMB->TotalParameterCount = cpu_to_le32(parm_len);
1982         pSMB->TotalDataCount  = 0;
1983         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
1984                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1985         pSMB->ParameterCount = pSMB->TotalParameterCount;
1986         pSMB->DataCount  = pSMB->TotalDataCount;
1987         temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
1988                         (setup_count * 2) - 4 /* for rfc1001 length itself */;
1989         pSMB->ParameterOffset = cpu_to_le32(temp_offset);
1990         pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
1991         pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
1992         pSMB->SubCommand = cpu_to_le16(sub_command);
1993         return 0;
1994 }
1995
1996 static int
1997 validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
1998                    int * pdatalen, int * pparmlen)
1999 {
2000         char * end_of_smb;
2001         __u32 data_count, data_offset, parm_count, parm_offset;
2002         struct smb_com_ntransact_rsp * pSMBr;
2003
2004         if(buf == NULL)
2005                 return -EINVAL;
2006
2007         pSMBr = (struct smb_com_ntransact_rsp *)buf;
2008
2009         /* ByteCount was converted from little endian in SendReceive */
2010         end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + 
2011                         (char *)&pSMBr->ByteCount;
2012
2013                 
2014         data_offset = le32_to_cpu(pSMBr->DataOffset);
2015         data_count = le32_to_cpu(pSMBr->DataCount);
2016         parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2017         parm_count = le32_to_cpu(pSMBr->ParameterCount);
2018
2019         *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2020         *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2021
2022         /* should we also check that parm and data areas do not overlap? */
2023         if(*ppparm > end_of_smb) {
2024                 cFYI(1,("parms start after end of smb"));
2025                 return -EINVAL;
2026         } else if(parm_count + *ppparm > end_of_smb) {
2027                 cFYI(1,("parm end after end of smb"));
2028                 return -EINVAL;
2029         } else if(*ppdata > end_of_smb) {
2030                 cFYI(1,("data starts after end of smb"));
2031                 return -EINVAL;
2032         } else if(data_count + *ppdata > end_of_smb) {
2033                 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2034                         *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr));  /* BB FIXME */
2035                 return -EINVAL;
2036         } else if(parm_count + data_count > pSMBr->ByteCount) {
2037                 cFYI(1,("parm count and data count larger than SMB"));
2038                 return -EINVAL;
2039         }
2040         return 0;
2041 }
2042
2043 int
2044 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2045                         const unsigned char *searchName,
2046                         char *symlinkinfo, const int buflen,__u16 fid,
2047                         const struct nls_table *nls_codepage)
2048 {
2049         int rc = 0;
2050         int bytes_returned;
2051         int name_len;
2052         struct smb_com_transaction_ioctl_req * pSMB;
2053         struct smb_com_transaction_ioctl_rsp * pSMBr;
2054
2055         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2056         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2057                       (void **) &pSMBr);
2058         if (rc)
2059                 return rc;
2060
2061         pSMB->TotalParameterCount = 0 ;
2062         pSMB->TotalDataCount = 0;
2063         pSMB->MaxParameterCount = cpu_to_le32(2);
2064         /* BB find exact data count max from sess structure BB */
2065         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2066                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2067         pSMB->MaxSetupCount = 4;
2068         pSMB->Reserved = 0;
2069         pSMB->ParameterOffset = 0;
2070         pSMB->DataCount = 0;
2071         pSMB->DataOffset = 0;
2072         pSMB->SetupCount = 4;
2073         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2074         pSMB->ParameterCount = pSMB->TotalParameterCount;
2075         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2076         pSMB->IsFsctl = 1; /* FSCTL */
2077         pSMB->IsRootFlag = 0;
2078         pSMB->Fid = fid; /* file handle always le */
2079         pSMB->ByteCount = 0;
2080
2081         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2082                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2083         if (rc) {
2084                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2085         } else {                /* decode response */
2086                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2087                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2088                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2089                 /* BB also check enough total bytes returned */
2090                         rc = -EIO;      /* bad smb */
2091                 else {
2092                         if(data_count && (data_count < 2048)) {
2093                                 char * end_of_smb = 2 /* sizeof byte count */ +
2094                                                 pSMBr->ByteCount +
2095                                                 (char *)&pSMBr->ByteCount;
2096
2097                                 struct reparse_data * reparse_buf = (struct reparse_data *)
2098                                         ((char *)&pSMBr->hdr.Protocol + data_offset);
2099                                 if((char*)reparse_buf >= end_of_smb) {
2100                                         rc = -EIO;
2101                                         goto qreparse_out;
2102                                 }
2103                                 if((reparse_buf->LinkNamesBuf + 
2104                                         reparse_buf->TargetNameOffset +
2105                                         reparse_buf->TargetNameLen) >
2106                                                 end_of_smb) {
2107                                         cFYI(1,("reparse buf extended beyond SMB"));
2108                                         rc = -EIO;
2109                                         goto qreparse_out;
2110                                 }
2111                                 
2112                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2113                                         name_len = UniStrnlen((wchar_t *)
2114                                                         (reparse_buf->LinkNamesBuf + 
2115                                                         reparse_buf->TargetNameOffset),
2116                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
2117                                         cifs_strfromUCS_le(symlinkinfo,
2118                                                 (__le16 *) (reparse_buf->LinkNamesBuf + 
2119                                                 reparse_buf->TargetNameOffset),
2120                                                 name_len, nls_codepage);
2121                                 } else { /* ASCII names */
2122                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
2123                                                 reparse_buf->TargetNameOffset, 
2124                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
2125                                 }
2126                         } else {
2127                                 rc = -EIO;
2128                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2129                         }
2130                         symlinkinfo[buflen] = 0; /* just in case so the caller
2131                                         does not go off the end of the buffer */
2132                         cFYI(1,("readlink result - %s ",symlinkinfo));
2133                 }
2134         }
2135 qreparse_out:
2136         cifs_buf_release(pSMB);
2137
2138         /* Note: On -EAGAIN error only caller can retry on handle based calls
2139                 since file handle passed in no longer valid */
2140
2141         return rc;
2142 }
2143
2144 #ifdef CONFIG_CIFS_POSIX
2145
2146 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2147 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2148 {
2149         /* u8 cifs fields do not need le conversion */
2150         ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2151         ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
2152         ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2153         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2154
2155         return;
2156 }
2157
2158 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2159 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2160                                 const int acl_type,const int size_of_data_area)
2161 {
2162         int size =  0;
2163         int i;
2164         __u16 count;
2165         struct cifs_posix_ace * pACE;
2166         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2167         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2168
2169         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2170                 return -EOPNOTSUPP;
2171
2172         if(acl_type & ACL_TYPE_ACCESS) {
2173                 count = le16_to_cpu(cifs_acl->access_entry_count);
2174                 pACE = &cifs_acl->ace_array[0];
2175                 size = sizeof(struct cifs_posix_acl);
2176                 size += sizeof(struct cifs_posix_ace) * count;
2177                 /* check if we would go beyond end of SMB */
2178                 if(size_of_data_area < size) {
2179                         cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2180                         return -EINVAL;
2181                 }
2182         } else if(acl_type & ACL_TYPE_DEFAULT) {
2183                 count = le16_to_cpu(cifs_acl->access_entry_count);
2184                 size = sizeof(struct cifs_posix_acl);
2185                 size += sizeof(struct cifs_posix_ace) * count;
2186 /* skip past access ACEs to get to default ACEs */
2187                 pACE = &cifs_acl->ace_array[count];
2188                 count = le16_to_cpu(cifs_acl->default_entry_count);
2189                 size += sizeof(struct cifs_posix_ace) * count;
2190                 /* check if we would go beyond end of SMB */
2191                 if(size_of_data_area < size)
2192                         return -EINVAL;
2193         } else {
2194                 /* illegal type */
2195                 return -EINVAL;
2196         }
2197
2198         size = posix_acl_xattr_size(count);
2199         if((buflen == 0) || (local_acl == NULL)) {
2200                 /* used to query ACL EA size */                         
2201         } else if(size > buflen) {
2202                 return -ERANGE;
2203         } else /* buffer big enough */ {
2204                 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2205                 for(i = 0;i < count ;i++) {
2206                         cifs_convert_ace(&local_acl->a_entries[i],pACE);
2207                         pACE ++;
2208                 }
2209         }
2210         return size;
2211 }
2212
2213 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2214                         const posix_acl_xattr_entry * local_ace)
2215 {
2216         __u16 rc = 0; /* 0 = ACL converted ok */
2217
2218         cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2219         cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
2220         /* BB is there a better way to handle the large uid? */
2221         if(local_ace->e_id == cpu_to_le32(-1)) {
2222         /* Probably no need to le convert -1 on any arch but can not hurt */
2223                 cifs_ace->cifs_uid = cpu_to_le64(-1);
2224         } else 
2225                 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2226         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2227         return rc;
2228 }
2229
2230 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2231 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2232                 const int acl_type)
2233 {
2234         __u16 rc = 0;
2235         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2236         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2237         int count;
2238         int i;
2239
2240         if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2241                 return 0;
2242
2243         count = posix_acl_xattr_count((size_t)buflen);
2244         cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2245                 count, buflen, le32_to_cpu(local_acl->a_version)));
2246         if(le32_to_cpu(local_acl->a_version) != 2) {
2247                 cFYI(1,("unknown POSIX ACL version %d",
2248                      le32_to_cpu(local_acl->a_version)));
2249                 return 0;
2250         }
2251         cifs_acl->version = cpu_to_le16(1);
2252         if(acl_type == ACL_TYPE_ACCESS) 
2253                 cifs_acl->access_entry_count = cpu_to_le16(count);
2254         else if(acl_type == ACL_TYPE_DEFAULT)
2255                 cifs_acl->default_entry_count = cpu_to_le16(count);
2256         else {
2257                 cFYI(1,("unknown ACL type %d",acl_type));
2258                 return 0;
2259         }
2260         for(i=0;i<count;i++) {
2261                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2262                                         &local_acl->a_entries[i]);
2263                 if(rc != 0) {
2264                         /* ACE not converted */
2265                         break;
2266                 }
2267         }
2268         if(rc == 0) {
2269                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2270                 rc += sizeof(struct cifs_posix_acl);
2271                 /* BB add check to make sure ACL does not overflow SMB */
2272         }
2273         return rc;
2274 }
2275
2276 int
2277 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2278                         const unsigned char *searchName,
2279                         char *acl_inf, const int buflen, const int acl_type,
2280                         const struct nls_table *nls_codepage, int remap)
2281 {
2282 /* SMB_QUERY_POSIX_ACL */
2283         TRANSACTION2_QPI_REQ *pSMB = NULL;
2284         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2285         int rc = 0;
2286         int bytes_returned;
2287         int name_len;
2288         __u16 params, byte_count;
2289                                                                                                                                              
2290         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2291
2292 queryAclRetry:
2293         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2294                 (void **) &pSMBr);
2295         if (rc)
2296                 return rc;
2297                                                                                                                                              
2298         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2299                 name_len =
2300                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2301                                          PATH_MAX, nls_codepage, remap);
2302                 name_len++;     /* trailing null */
2303                 name_len *= 2;
2304                 pSMB->FileName[name_len] = 0;
2305                 pSMB->FileName[name_len+1] = 0;
2306         } else {                /* BB improve the check for buffer overruns BB */
2307                 name_len = strnlen(searchName, PATH_MAX);
2308                 name_len++;     /* trailing null */
2309                 strncpy(pSMB->FileName, searchName, name_len);
2310         }
2311
2312         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2313         pSMB->TotalDataCount = 0;
2314         pSMB->MaxParameterCount = cpu_to_le16(2);
2315         /* BB find exact max data count below from sess structure BB */
2316         pSMB->MaxDataCount = cpu_to_le16(4000);
2317         pSMB->MaxSetupCount = 0;
2318         pSMB->Reserved = 0;
2319         pSMB->Flags = 0;
2320         pSMB->Timeout = 0;
2321         pSMB->Reserved2 = 0;
2322         pSMB->ParameterOffset = cpu_to_le16(
2323                 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2324         pSMB->DataCount = 0;
2325         pSMB->DataOffset = 0;
2326         pSMB->SetupCount = 1;
2327         pSMB->Reserved3 = 0;
2328         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2329         byte_count = params + 1 /* pad */ ;
2330         pSMB->TotalParameterCount = cpu_to_le16(params);
2331         pSMB->ParameterCount = pSMB->TotalParameterCount;
2332         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2333         pSMB->Reserved4 = 0;
2334         pSMB->hdr.smb_buf_length += byte_count;
2335         pSMB->ByteCount = cpu_to_le16(byte_count);
2336
2337         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2338                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2339         cifs_stats_inc(&tcon->num_acl_get);
2340         if (rc) {
2341                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2342         } else {
2343                 /* decode response */
2344  
2345                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2346                 if (rc || (pSMBr->ByteCount < 2))
2347                 /* BB also check enough total bytes returned */
2348                         rc = -EIO;      /* bad smb */
2349                 else {
2350                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2351                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2352                         rc = cifs_copy_posix_acl(acl_inf,
2353                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2354                                 buflen,acl_type,count);
2355                 }
2356         }
2357         cifs_buf_release(pSMB);
2358         if (rc == -EAGAIN)
2359                 goto queryAclRetry;
2360         return rc;
2361 }
2362
2363 int
2364 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2365                         const unsigned char *fileName,
2366                         const char *local_acl, const int buflen, 
2367                         const int acl_type,
2368                         const struct nls_table *nls_codepage, int remap)
2369 {
2370         struct smb_com_transaction2_spi_req *pSMB = NULL;
2371         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2372         char *parm_data;
2373         int name_len;
2374         int rc = 0;
2375         int bytes_returned = 0;
2376         __u16 params, byte_count, data_count, param_offset, offset;
2377
2378         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2379 setAclRetry:
2380         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2381                       (void **) &pSMBr);
2382         if (rc)
2383                 return rc;
2384         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2385                 name_len =
2386                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
2387                                       PATH_MAX, nls_codepage, remap);
2388                 name_len++;     /* trailing null */
2389                 name_len *= 2;
2390         } else {                /* BB improve the check for buffer overruns BB */
2391                 name_len = strnlen(fileName, PATH_MAX);
2392                 name_len++;     /* trailing null */
2393                 strncpy(pSMB->FileName, fileName, name_len);
2394         }
2395         params = 6 + name_len;
2396         pSMB->MaxParameterCount = cpu_to_le16(2);
2397         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2398         pSMB->MaxSetupCount = 0;
2399         pSMB->Reserved = 0;
2400         pSMB->Flags = 0;
2401         pSMB->Timeout = 0;
2402         pSMB->Reserved2 = 0;
2403         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2404                                      InformationLevel) - 4;
2405         offset = param_offset + params;
2406         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2407         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2408
2409         /* convert to on the wire format for POSIX ACL */
2410         data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2411
2412         if(data_count == 0) {
2413                 rc = -EOPNOTSUPP;
2414                 goto setACLerrorExit;
2415         }
2416         pSMB->DataOffset = cpu_to_le16(offset);
2417         pSMB->SetupCount = 1;
2418         pSMB->Reserved3 = 0;
2419         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2420         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2421         byte_count = 3 /* pad */  + params + data_count;
2422         pSMB->DataCount = cpu_to_le16(data_count);
2423         pSMB->TotalDataCount = pSMB->DataCount;
2424         pSMB->ParameterCount = cpu_to_le16(params);
2425         pSMB->TotalParameterCount = pSMB->ParameterCount;
2426         pSMB->Reserved4 = 0;
2427         pSMB->hdr.smb_buf_length += byte_count;
2428         pSMB->ByteCount = cpu_to_le16(byte_count);
2429         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2430                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2431         if (rc) {
2432                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2433         }
2434
2435 setACLerrorExit:
2436         cifs_buf_release(pSMB);
2437         if (rc == -EAGAIN)
2438                 goto setAclRetry;
2439         return rc;
2440 }
2441
2442 /* BB fix tabs in this function FIXME BB */
2443 int
2444 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2445                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2446 {
2447         int rc = 0;
2448         struct smb_t2_qfi_req *pSMB = NULL;
2449         struct smb_t2_qfi_rsp *pSMBr = NULL;
2450         int bytes_returned;
2451         __u16 params, byte_count;
2452
2453         cFYI(1,("In GetExtAttr"));
2454         if(tcon == NULL)
2455                 return -ENODEV;
2456
2457 GetExtAttrRetry:
2458         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2459                       (void **) &pSMBr);
2460         if (rc)
2461                 return rc;
2462
2463         params = 2 /* level */ +2 /* fid */;
2464         pSMB->t2.TotalDataCount = 0;
2465         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2466         /* BB find exact max data count below from sess structure BB */
2467         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2468         pSMB->t2.MaxSetupCount = 0;
2469         pSMB->t2.Reserved = 0;
2470         pSMB->t2.Flags = 0;
2471         pSMB->t2.Timeout = 0;
2472         pSMB->t2.Reserved2 = 0;
2473         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2474                         Fid) - 4);
2475         pSMB->t2.DataCount = 0;
2476         pSMB->t2.DataOffset = 0;
2477         pSMB->t2.SetupCount = 1;
2478         pSMB->t2.Reserved3 = 0;
2479         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2480         byte_count = params + 1 /* pad */ ;
2481         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2482         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2483         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2484         pSMB->Pad = 0;
2485         pSMB->Fid = netfid;
2486         pSMB->hdr.smb_buf_length += byte_count;
2487         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2488
2489         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2490                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2491         if (rc) {
2492                 cFYI(1, ("error %d in GetExtAttr", rc));
2493         } else {
2494                 /* decode response */
2495                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2496                 if (rc || (pSMBr->ByteCount < 2))
2497                 /* BB also check enough total bytes returned */
2498                         /* If rc should we check for EOPNOSUPP and
2499                         disable the srvino flag? or in caller? */
2500                         rc = -EIO;      /* bad smb */
2501                 else {
2502                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2503                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2504                         struct file_chattr_info * pfinfo;
2505                         /* BB Do we need a cast or hash here ? */
2506                         if(count != 16) {
2507                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
2508                                 rc = -EIO;
2509                                 goto GetExtAttrOut;
2510                         }
2511                         pfinfo = (struct file_chattr_info *)
2512                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2513                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2514                         *pMask = le64_to_cpu(pfinfo->mask);
2515                 }
2516         }
2517 GetExtAttrOut:
2518         cifs_buf_release(pSMB);
2519         if (rc == -EAGAIN)
2520                 goto GetExtAttrRetry;
2521         return rc;
2522 }
2523
2524
2525 #endif /* CONFIG_POSIX */
2526
2527
2528 /* security id for everyone */
2529 const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2530 /* group users */
2531 const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2532
2533 /* Convert CIFS ACL to POSIX form */
2534 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2535 {
2536         return 0;
2537 }
2538
2539 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2540 int
2541 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2542          /*  BB fix up return info */ char *acl_inf, const int buflen, 
2543                   const int acl_type /* ACCESS/DEFAULT not sure implication */)
2544 {
2545         int rc = 0;
2546         int buf_type = 0;
2547         QUERY_SEC_DESC_REQ * pSMB;
2548         struct kvec iov[1];
2549
2550         cFYI(1, ("GetCifsACL"));
2551
2552         rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 
2553                         8 /* parm len */, tcon, (void **) &pSMB);
2554         if (rc)
2555                 return rc;
2556
2557         pSMB->MaxParameterCount = cpu_to_le32(4);
2558         /* BB TEST with big acls that might need to be e.g. larger than 16K */
2559         pSMB->MaxSetupCount = 0;
2560         pSMB->Fid = fid; /* file handle always le */
2561         pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2562                                      CIFS_ACL_DACL);
2563         pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2564         pSMB->hdr.smb_buf_length += 11;
2565         iov[0].iov_base = (char *)pSMB;
2566         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2567
2568         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2569         cifs_stats_inc(&tcon->num_acl_get);
2570         if (rc) {
2571                 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2572         } else {                /* decode response */
2573                 struct cifs_sid * psec_desc;
2574                 __le32 * parm;
2575                 int parm_len;
2576                 int data_len;
2577                 int acl_len;
2578                 struct smb_com_ntransact_rsp * pSMBr;
2579
2580 /* validate_nttransact */
2581                 rc = validate_ntransact(iov[0].iov_base, (char **)&parm, 
2582                                         (char **)&psec_desc,
2583                                         &parm_len, &data_len);
2584                 
2585                 if(rc)
2586                         goto qsec_out;
2587                 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2588
2589                 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc));  /* BB removeme BB */
2590
2591                 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2592                         rc = -EIO;      /* bad smb */
2593                         goto qsec_out;
2594                 }
2595
2596 /* BB check that data area is minimum length and as big as acl_len */
2597
2598                 acl_len = le32_to_cpu(*(__le32 *)parm);
2599                 /* BB check if(acl_len > bufsize) */
2600
2601                 parse_sec_desc(psec_desc, acl_len);
2602         }
2603 qsec_out:
2604         if(buf_type == CIFS_SMALL_BUFFER)
2605                 cifs_small_buf_release(iov[0].iov_base);
2606         else if(buf_type == CIFS_LARGE_BUFFER)
2607                 cifs_buf_release(iov[0].iov_base);
2608         cifs_small_buf_release(pSMB);
2609         return rc;
2610 }
2611
2612
2613 /* Legacy Query Path Information call for lookup to old servers such
2614    as Win9x/WinME */
2615 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2616                  const unsigned char *searchName,
2617                  FILE_ALL_INFO * pFinfo,
2618                  const struct nls_table *nls_codepage, int remap)
2619 {
2620         QUERY_INFORMATION_REQ * pSMB;
2621         QUERY_INFORMATION_RSP * pSMBr;
2622         int rc = 0;
2623         int bytes_returned;
2624         int name_len;
2625
2626         cFYI(1, ("In SMBQPath path %s", searchName)); 
2627 QInfRetry:
2628         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2629                       (void **) &pSMBr);
2630         if (rc)
2631                 return rc;
2632
2633         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2634                 name_len =
2635                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2636                                      PATH_MAX, nls_codepage, remap);
2637                 name_len++;     /* trailing null */
2638                 name_len *= 2;
2639         } else {               
2640                 name_len = strnlen(searchName, PATH_MAX);
2641                 name_len++;     /* trailing null */
2642                 strncpy(pSMB->FileName, searchName, name_len);
2643         }
2644         pSMB->BufferFormat = 0x04;
2645         name_len++; /* account for buffer type byte */  
2646         pSMB->hdr.smb_buf_length += (__u16) name_len;
2647         pSMB->ByteCount = cpu_to_le16(name_len);
2648
2649         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2650                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2651         if (rc) {
2652                 cFYI(1, ("Send error in QueryInfo = %d", rc));
2653         } else if (pFinfo) {            /* decode response */
2654                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2655                 pFinfo->AllocationSize =
2656                         cpu_to_le64(le32_to_cpu(pSMBr->size));
2657                 pFinfo->EndOfFile = pFinfo->AllocationSize;
2658                 pFinfo->Attributes =
2659                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
2660         } else
2661                 rc = -EIO; /* bad buffer passed in */
2662
2663         cifs_buf_release(pSMB);
2664
2665         if (rc == -EAGAIN)
2666                 goto QInfRetry;
2667
2668         return rc;
2669 }
2670
2671
2672
2673
2674 int
2675 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2676                  const unsigned char *searchName,
2677                  FILE_ALL_INFO * pFindData,
2678                  const struct nls_table *nls_codepage, int remap)
2679 {
2680 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2681         TRANSACTION2_QPI_REQ *pSMB = NULL;
2682         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2683         int rc = 0;
2684         int bytes_returned;
2685         int name_len;
2686         __u16 params, byte_count;
2687
2688 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2689 QPathInfoRetry:
2690         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2691                       (void **) &pSMBr);
2692         if (rc)
2693                 return rc;
2694
2695         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2696                 name_len =
2697                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2698                                      PATH_MAX, nls_codepage, remap);
2699                 name_len++;     /* trailing null */
2700                 name_len *= 2;
2701         } else {                /* BB improve the check for buffer overruns BB */
2702                 name_len = strnlen(searchName, PATH_MAX);
2703                 name_len++;     /* trailing null */
2704                 strncpy(pSMB->FileName, searchName, name_len);
2705         }
2706
2707         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2708         pSMB->TotalDataCount = 0;
2709         pSMB->MaxParameterCount = cpu_to_le16(2);
2710         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2711         pSMB->MaxSetupCount = 0;
2712         pSMB->Reserved = 0;
2713         pSMB->Flags = 0;
2714         pSMB->Timeout = 0;
2715         pSMB->Reserved2 = 0;
2716         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2717         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2718         pSMB->DataCount = 0;
2719         pSMB->DataOffset = 0;
2720         pSMB->SetupCount = 1;
2721         pSMB->Reserved3 = 0;
2722         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2723         byte_count = params + 1 /* pad */ ;
2724         pSMB->TotalParameterCount = cpu_to_le16(params);
2725         pSMB->ParameterCount = pSMB->TotalParameterCount;
2726         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2727         pSMB->Reserved4 = 0;
2728         pSMB->hdr.smb_buf_length += byte_count;
2729         pSMB->ByteCount = cpu_to_le16(byte_count);
2730
2731         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2732                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2733         if (rc) {
2734                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2735         } else {                /* decode response */
2736                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2737
2738                 if (rc || (pSMBr->ByteCount < 40)) 
2739                         rc = -EIO;      /* bad smb */
2740                 else if (pFindData){
2741                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2742                         memcpy((char *) pFindData,
2743                                (char *) &pSMBr->hdr.Protocol +
2744                                data_offset, sizeof (FILE_ALL_INFO));
2745                 } else
2746                     rc = -ENOMEM;
2747         }
2748         cifs_buf_release(pSMB);
2749         if (rc == -EAGAIN)
2750                 goto QPathInfoRetry;
2751
2752         return rc;
2753 }
2754
2755 int
2756 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2757                      const unsigned char *searchName,
2758                      FILE_UNIX_BASIC_INFO * pFindData,
2759                      const struct nls_table *nls_codepage, int remap)
2760 {
2761 /* SMB_QUERY_FILE_UNIX_BASIC */
2762         TRANSACTION2_QPI_REQ *pSMB = NULL;
2763         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2764         int rc = 0;
2765         int bytes_returned = 0;
2766         int name_len;
2767         __u16 params, byte_count;
2768
2769         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2770 UnixQPathInfoRetry:
2771         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2772                       (void **) &pSMBr);
2773         if (rc)
2774                 return rc;
2775
2776         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2777                 name_len =
2778                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2779                                   PATH_MAX, nls_codepage, remap);
2780                 name_len++;     /* trailing null */
2781                 name_len *= 2;
2782         } else {                /* BB improve the check for buffer overruns BB */
2783                 name_len = strnlen(searchName, PATH_MAX);
2784                 name_len++;     /* trailing null */
2785                 strncpy(pSMB->FileName, searchName, name_len);
2786         }
2787
2788         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2789         pSMB->TotalDataCount = 0;
2790         pSMB->MaxParameterCount = cpu_to_le16(2);
2791         /* BB find exact max SMB PDU from sess structure BB */
2792         pSMB->MaxDataCount = cpu_to_le16(4000); 
2793         pSMB->MaxSetupCount = 0;
2794         pSMB->Reserved = 0;
2795         pSMB->Flags = 0;
2796         pSMB->Timeout = 0;
2797         pSMB->Reserved2 = 0;
2798         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2799         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2800         pSMB->DataCount = 0;
2801         pSMB->DataOffset = 0;
2802         pSMB->SetupCount = 1;
2803         pSMB->Reserved3 = 0;
2804         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2805         byte_count = params + 1 /* pad */ ;
2806         pSMB->TotalParameterCount = cpu_to_le16(params);
2807         pSMB->ParameterCount = pSMB->TotalParameterCount;
2808         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2809         pSMB->Reserved4 = 0;
2810         pSMB->hdr.smb_buf_length += byte_count;
2811         pSMB->ByteCount = cpu_to_le16(byte_count);
2812
2813         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2814                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2815         if (rc) {
2816                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2817         } else {                /* decode response */
2818                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2819
2820                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2821                         rc = -EIO;      /* bad smb */
2822                 } else {
2823                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2824                         memcpy((char *) pFindData,
2825                                (char *) &pSMBr->hdr.Protocol +
2826                                data_offset,
2827                                sizeof (FILE_UNIX_BASIC_INFO));
2828                 }
2829         }
2830         cifs_buf_release(pSMB);
2831         if (rc == -EAGAIN)
2832                 goto UnixQPathInfoRetry;
2833
2834         return rc;
2835 }
2836
2837 #if 0  /* function unused at present */
2838 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2839                const char *searchName, FILE_ALL_INFO * findData,
2840                const struct nls_table *nls_codepage)
2841 {
2842 /* level 257 SMB_ */
2843         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2844         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2845         int rc = 0;
2846         int bytes_returned;
2847         int name_len;
2848         __u16 params, byte_count;
2849
2850         cFYI(1, ("In FindUnique"));
2851 findUniqueRetry:
2852         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2853                       (void **) &pSMBr);
2854         if (rc)
2855                 return rc;
2856
2857         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2858                 name_len =
2859                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2860                                   /* find define for this maxpathcomponent */
2861                                   , nls_codepage);
2862                 name_len++;     /* trailing null */
2863                 name_len *= 2;
2864         } else {                /* BB improve the check for buffer overruns BB */
2865                 name_len = strnlen(searchName, PATH_MAX);
2866                 name_len++;     /* trailing null */
2867                 strncpy(pSMB->FileName, searchName, name_len);
2868         }
2869
2870         params = 12 + name_len /* includes null */ ;
2871         pSMB->TotalDataCount = 0;       /* no EAs */
2872         pSMB->MaxParameterCount = cpu_to_le16(2);
2873         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2874         pSMB->MaxSetupCount = 0;
2875         pSMB->Reserved = 0;
2876         pSMB->Flags = 0;
2877         pSMB->Timeout = 0;
2878         pSMB->Reserved2 = 0;
2879         pSMB->ParameterOffset = cpu_to_le16(
2880          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2881         pSMB->DataCount = 0;
2882         pSMB->DataOffset = 0;
2883         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
2884         pSMB->Reserved3 = 0;
2885         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2886         byte_count = params + 1 /* pad */ ;
2887         pSMB->TotalParameterCount = cpu_to_le16(params);
2888         pSMB->ParameterCount = pSMB->TotalParameterCount;
2889         pSMB->SearchAttributes =
2890             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2891                         ATTR_DIRECTORY);
2892         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
2893         pSMB->SearchFlags = cpu_to_le16(1);
2894         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2895         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
2896         pSMB->hdr.smb_buf_length += byte_count;
2897         pSMB->ByteCount = cpu_to_le16(byte_count);
2898
2899         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2900                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2901
2902         if (rc) {
2903                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2904         } else {                /* decode response */
2905                 cifs_stats_inc(&tcon->num_ffirst);
2906                 /* BB fill in */
2907         }
2908
2909         cifs_buf_release(pSMB);
2910         if (rc == -EAGAIN)
2911                 goto findUniqueRetry;
2912
2913         return rc;
2914 }
2915 #endif /* end unused (temporarily) function */
2916
2917 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2918 int
2919 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2920               const char *searchName, 
2921               const struct nls_table *nls_codepage,
2922               __u16 *   pnetfid,
2923               struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2924 {
2925 /* level 257 SMB_ */
2926         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2927         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2928         T2_FFIRST_RSP_PARMS * parms;
2929         int rc = 0;
2930         int bytes_returned = 0;
2931         int name_len;
2932         __u16 params, byte_count;
2933
2934         cFYI(1, ("In FindFirst for %s",searchName));
2935
2936 findFirstRetry:
2937         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2938                       (void **) &pSMBr);
2939         if (rc)
2940                 return rc;
2941
2942         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2943                 name_len =
2944                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2945                                  PATH_MAX, nls_codepage, remap);
2946                 /* We can not add the asterik earlier in case
2947                 it got remapped to 0xF03A as if it were part of the
2948                 directory name instead of a wildcard */
2949                 name_len *= 2;
2950                 pSMB->FileName[name_len] = dirsep;
2951                 pSMB->FileName[name_len+1] = 0;
2952                 pSMB->FileName[name_len+2] = '*';
2953                 pSMB->FileName[name_len+3] = 0;
2954                 name_len += 4; /* now the trailing null */
2955                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2956                 pSMB->FileName[name_len+1] = 0;
2957                 name_len += 2;
2958         } else {        /* BB add check for overrun of SMB buf BB */
2959                 name_len = strnlen(searchName, PATH_MAX);
2960 /* BB fix here and in unicode clause above ie
2961                 if(name_len > buffersize-header)
2962                         free buffer exit; BB */
2963                 strncpy(pSMB->FileName, searchName, name_len);
2964                 pSMB->FileName[name_len] = dirsep;
2965                 pSMB->FileName[name_len+1] = '*';
2966                 pSMB->FileName[name_len+2] = 0;
2967                 name_len += 3;
2968         }
2969
2970         params = 12 + name_len /* includes null */ ;
2971         pSMB->TotalDataCount = 0;       /* no EAs */
2972         pSMB->MaxParameterCount = cpu_to_le16(10);
2973         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2974                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2975         pSMB->MaxSetupCount = 0;
2976         pSMB->Reserved = 0;
2977         pSMB->Flags = 0;
2978         pSMB->Timeout = 0;
2979         pSMB->Reserved2 = 0;
2980         byte_count = params + 1 /* pad */ ;
2981         pSMB->TotalParameterCount = cpu_to_le16(params);
2982         pSMB->ParameterCount = pSMB->TotalParameterCount;
2983         pSMB->ParameterOffset = cpu_to_le16(
2984           offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2985         pSMB->DataCount = 0;
2986         pSMB->DataOffset = 0;
2987         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
2988         pSMB->Reserved3 = 0;
2989         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2990         pSMB->SearchAttributes =
2991             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2992                         ATTR_DIRECTORY);
2993         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2994         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
2995                 CIFS_SEARCH_RETURN_RESUME);
2996         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2997
2998         /* BB what should we set StorageType to? Does it matter? BB */
2999         pSMB->SearchStorageType = 0;
3000         pSMB->hdr.smb_buf_length += byte_count;
3001         pSMB->ByteCount = cpu_to_le16(byte_count);
3002
3003         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3004                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3005         cifs_stats_inc(&tcon->num_ffirst);
3006
3007         if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
3008                 /* BB Add code to handle unsupported level rc */
3009                 cFYI(1, ("Error in FindFirst = %d", rc));
3010
3011                 if (pSMB)
3012                         cifs_buf_release(pSMB);
3013
3014                 /* BB eventually could optimize out free and realloc of buf */
3015                 /*    for this case */
3016                 if (rc == -EAGAIN)
3017                         goto findFirstRetry;
3018         } else { /* decode response */
3019                 /* BB remember to free buffer if error BB */
3020                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3021                 if(rc == 0) {
3022                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3023                                 psrch_inf->unicode = TRUE;
3024                         else
3025                                 psrch_inf->unicode = FALSE;
3026
3027                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3028                         psrch_inf->srch_entries_start = 
3029                                 (char *) &pSMBr->hdr.Protocol + 
3030                                         le16_to_cpu(pSMBr->t2.DataOffset);
3031                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3032                                le16_to_cpu(pSMBr->t2.ParameterOffset));
3033
3034                         if(parms->EndofSearch)
3035                                 psrch_inf->endOfSearch = TRUE;
3036                         else
3037                                 psrch_inf->endOfSearch = FALSE;
3038
3039                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3040                         psrch_inf->index_of_last_entry = 
3041                                 psrch_inf->entries_in_buffer;
3042                         *pnetfid = parms->SearchHandle;
3043                 } else {
3044                         cifs_buf_release(pSMB);
3045                 }
3046