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