[CIFS] Readdir fixes to allow search to start at arbitrary position
[safe/jmp/linux-2.6] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2006
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   Contains the routines for constructing the SMB PDUs themselves
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
25  /* These are mostly routines that operate on a pathname, or on a tree id     */
26  /* (mounted volume), but there are eight handle based routines which must be */
27  /* treated slightly different for reconnection purposes since we never want  */
28  /* to reuse a stale file handle and the caller knows the file handle */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsproto.h"
38 #include "cifs_unicode.h"
39 #include "cifs_debug.h"
40 #include "cifsacl.h"
41
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44         int index;
45         char *name;
46 } protocols[] = {
47         {CIFS_PROT, "\2NT LM 0.12"}, 
48         {CIFS_PROT, "\2POSIX 2"},
49         {BAD_PROT, "\2"}
50 };
51 #else
52 static struct {
53         int index;
54         char *name;
55 } protocols[] = {
56         {CIFS_PROT, "\2NT LM 0.12"}, 
57         {BAD_PROT, "\2"}
58 };
59 #endif
60
61
62 /* Mark as invalid, all open files on tree connections since they
63    were closed when session to server was lost */
64 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
65 {
66         struct cifsFileInfo *open_file = NULL;
67         struct list_head * tmp;
68         struct list_head * tmp1;
69
70 /* list all files open on tree connection and mark them invalid */
71         write_lock(&GlobalSMBSeslock);
72         list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
73                 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
74                 if(open_file) {
75                         open_file->invalidHandle = TRUE;
76                 }
77         }
78         write_unlock(&GlobalSMBSeslock);
79         /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
80            to this tcon */
81 }
82
83 /* If the return code is zero, this function must fill in request_buf pointer */
84 static int
85 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
86          void **request_buf /* returned */)
87 {
88         int rc = 0;
89
90         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
91            check for tcp and smb session status done differently
92            for those three - in the calling routine */
93         if(tcon) {
94                 if(tcon->tidStatus == CifsExiting) {
95                         /* only tree disconnect, open, and write,
96                         (and ulogoff which does not have tcon)
97                         are allowed as we start force umount */
98                         if((smb_command != SMB_COM_WRITE_ANDX) && 
99                            (smb_command != SMB_COM_OPEN_ANDX) && 
100                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
101                                 cFYI(1,("can not send cmd %d while umounting",
102                                         smb_command));
103                                 return -ENODEV;
104                         }
105                 }
106                 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
107                                   (tcon->ses->server)){
108                         struct nls_table *nls_codepage;
109                                 /* Give Demultiplex thread up to 10 seconds to 
110                                    reconnect, should be greater than cifs socket
111                                    timeout which is 7 seconds */
112                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
113                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
114                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
115                                 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
116                                         /* on "soft" mounts we wait once */
117                                         if((tcon->retry == FALSE) || 
118                                            (tcon->ses->status == CifsExiting)) {
119                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
120                                                 return -EHOSTDOWN;
121                                         } /* else "hard" mount - keep retrying
122                                              until process is killed or server
123                                              comes back on-line */
124                                 } else /* TCP session is reestablished now */
125                                         break;
126                                  
127                         }
128                         
129                         nls_codepage = load_nls_default();
130                 /* need to prevent multiple threads trying to
131                 simultaneously reconnect the same SMB session */
132                         down(&tcon->ses->sesSem);
133                         if(tcon->ses->status == CifsNeedReconnect)
134                                 rc = cifs_setup_session(0, tcon->ses, 
135                                                         nls_codepage);
136                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
137                                 mark_open_files_invalid(tcon);
138                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
139                                         , nls_codepage);
140                                 up(&tcon->ses->sesSem);
141                                 /* BB FIXME add code to check if wsize needs
142                                    update due to negotiated smb buffer size
143                                    shrinking */
144                                 if(rc == 0)
145                                         atomic_inc(&tconInfoReconnectCount);
146
147                                 cFYI(1, ("reconnect tcon rc = %d", rc));
148                                 /* Removed call to reopen open files here - 
149                                    it is safer (and faster) to reopen files
150                                    one at a time as needed in read and write */
151
152                                 /* Check if handle based operation so we 
153                                    know whether we can continue or not without
154                                    returning to caller to reset file handle */
155                                 switch(smb_command) {
156                                         case SMB_COM_READ_ANDX:
157                                         case SMB_COM_WRITE_ANDX:
158                                         case SMB_COM_CLOSE:
159                                         case SMB_COM_FIND_CLOSE2:
160                                         case SMB_COM_LOCKING_ANDX: {
161                                                 unload_nls(nls_codepage);
162                                                 return -EAGAIN;
163                                         }
164                                 }
165                         } else {
166                                 up(&tcon->ses->sesSem);
167                         }
168                         unload_nls(nls_codepage);
169
170                 } else {
171                         return -EIO;
172                 }
173         }
174         if(rc)
175                 return rc;
176
177         *request_buf = cifs_small_buf_get();
178         if (*request_buf == NULL) {
179                 /* BB should we add a retry in here if not a writepage? */
180                 return -ENOMEM;
181         }
182
183         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
184
185         if(tcon != NULL)
186                 cifs_stats_inc(&tcon->num_smbs_sent);
187
188         return rc;
189 }
190
191 #ifdef CONFIG_CIFS_EXPERIMENTAL  
192 int
193 small_smb_init_no_tc(const int smb_command, const int wct, 
194                      struct cifsSesInfo *ses, void **request_buf)
195 {
196         int rc;
197         struct smb_hdr * buffer;
198
199         rc = small_smb_init(smb_command, wct, NULL, request_buf);
200         if(rc)
201                 return rc;
202
203         buffer = (struct smb_hdr *)*request_buf;
204         buffer->Mid = GetNextMid(ses->server);
205         if (ses->capabilities & CAP_UNICODE)
206                 buffer->Flags2 |= SMBFLG2_UNICODE;
207         if (ses->capabilities & CAP_STATUS32)
208                 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
209
210         /* uid, tid can stay at zero as set in header assemble */
211
212         /* BB add support for turning on the signing when 
213         this function is used after 1st of session setup requests */
214
215         return rc;
216 }
217 #endif  /* CONFIG_CIFS_EXPERIMENTAL */
218
219 /* If the return code is zero, this function must fill in request_buf pointer */
220 static int
221 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
222          void **request_buf /* returned */ ,
223          void **response_buf /* returned */ )
224 {
225         int rc = 0;
226
227         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
228            check for tcp and smb session status done differently
229            for those three - in the calling routine */
230         if(tcon) {
231                 if(tcon->tidStatus == CifsExiting) {
232                         /* only tree disconnect, open, and write,
233                           (and ulogoff which does not have tcon)
234                           are allowed as we start force umount */
235                         if((smb_command != SMB_COM_WRITE_ANDX) &&
236                            (smb_command != SMB_COM_OPEN_ANDX) &&
237                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
238                                 cFYI(1,("can not send cmd %d while umounting",
239                                         smb_command));
240                                 return -ENODEV;
241                         }
242                 }
243
244                 if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
245                                   (tcon->ses->server)){
246                         struct nls_table *nls_codepage;
247                                 /* Give Demultiplex thread up to 10 seconds to
248                                    reconnect, should be greater than cifs socket
249                                    timeout which is 7 seconds */
250                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
251                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
252                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
253                                 if(tcon->ses->server->tcpStatus == 
254                                                 CifsNeedReconnect) {
255                                         /* on "soft" mounts we wait once */
256                                         if((tcon->retry == FALSE) || 
257                                            (tcon->ses->status == CifsExiting)) {
258                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
259                                                 return -EHOSTDOWN;
260                                         } /* else "hard" mount - keep retrying
261                                              until process is killed or server
262                                              comes on-line */
263                                 } else /* TCP session is reestablished now */
264                                         break;
265                                  
266                         }
267                         
268                         nls_codepage = load_nls_default();
269                 /* need to prevent multiple threads trying to
270                 simultaneously reconnect the same SMB session */
271                         down(&tcon->ses->sesSem);
272                         if(tcon->ses->status == CifsNeedReconnect)
273                                 rc = cifs_setup_session(0, tcon->ses, 
274                                                         nls_codepage);
275                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
276                                 mark_open_files_invalid(tcon);
277                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
278                                               tcon, nls_codepage);
279                                 up(&tcon->ses->sesSem);
280                                 /* BB FIXME add code to check if wsize needs
281                                 update due to negotiated smb buffer size
282                                 shrinking */
283                                 if(rc == 0)
284                                         atomic_inc(&tconInfoReconnectCount);
285
286                                 cFYI(1, ("reconnect tcon rc = %d", rc));
287                                 /* Removed call to reopen open files here - 
288                                    it is safer (and faster) to reopen files
289                                    one at a time as needed in read and write */
290
291                                 /* Check if handle based operation so we 
292                                    know whether we can continue or not without
293                                    returning to caller to reset file handle */
294                                 switch(smb_command) {
295                                         case SMB_COM_READ_ANDX:
296                                         case SMB_COM_WRITE_ANDX:
297                                         case SMB_COM_CLOSE:
298                                         case SMB_COM_FIND_CLOSE2:
299                                         case SMB_COM_LOCKING_ANDX: {
300                                                 unload_nls(nls_codepage);
301                                                 return -EAGAIN;
302                                         }
303                                 }
304                         } else {
305                                 up(&tcon->ses->sesSem);
306                         }
307                         unload_nls(nls_codepage);
308
309                 } else {
310                         return -EIO;
311                 }
312         }
313         if(rc)
314                 return rc;
315
316         *request_buf = cifs_buf_get();
317         if (*request_buf == NULL) {
318                 /* BB should we add a retry in here if not a writepage? */
319                 return -ENOMEM;
320         }
321     /* Although the original thought was we needed the response buf for  */
322     /* potential retries of smb operations it turns out we can determine */
323     /* from the mid flags when the request buffer can be resent without  */
324     /* having to use a second distinct buffer for the response */
325         *response_buf = *request_buf; 
326
327         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
328                         wct /*wct */ );
329
330         if(tcon != NULL)
331                 cifs_stats_inc(&tcon->num_smbs_sent);
332
333         return rc;
334 }
335
336 static int validate_t2(struct smb_t2_rsp * pSMB) 
337 {
338         int rc = -EINVAL;
339         int total_size;
340         char * pBCC;
341
342         /* check for plausible wct, bcc and t2 data and parm sizes */
343         /* check for parm and data offset going beyond end of smb */
344         if(pSMB->hdr.WordCount >= 10) {
345                 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
346                    (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
347                         /* check that bcc is at least as big as parms + data */
348                         /* check that bcc is less than negotiated smb buffer */
349                         total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
350                         if(total_size < 512) {
351                                 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
352                                 /* BCC le converted in SendReceive */
353                                 pBCC = (pSMB->hdr.WordCount * 2) + 
354                                         sizeof(struct smb_hdr) +
355                                         (char *)pSMB;
356                                 if((total_size <= (*(u16 *)pBCC)) && 
357                                    (total_size < 
358                                         CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
359                                         return 0;
360                                 }
361                                 
362                         }
363                 }
364         }
365         cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
366                 sizeof(struct smb_t2_rsp) + 16);
367         return rc;
368 }
369 int
370 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
371 {
372         NEGOTIATE_REQ *pSMB;
373         NEGOTIATE_RSP *pSMBr;
374         int rc = 0;
375         int bytes_returned;
376         struct TCP_Server_Info * server;
377         u16 count;
378
379         if(ses->server)
380                 server = ses->server;
381         else {
382                 rc = -EIO;
383                 return rc;
384         }
385         rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
386                       (void **) &pSMB, (void **) &pSMBr);
387         if (rc)
388                 return rc;
389         pSMB->hdr.Mid = GetNextMid(server);
390         pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
391         if (extended_security)
392                 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
393
394         count = strlen(protocols[0].name) + 1;
395         strncpy(pSMB->DialectsArray, protocols[0].name, 30);    
396     /* null guaranteed to be at end of source and target buffers anyway */
397
398         pSMB->hdr.smb_buf_length += count;
399         pSMB->ByteCount = cpu_to_le16(count);
400
401         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
402                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
403         if (rc == 0) {
404                 server->secMode = pSMBr->SecurityMode;
405                 if((server->secMode & SECMODE_USER) == 0)
406                         cFYI(1,("share mode security"));
407                 server->secType = NTLM; /* BB override default for
408                                            NTLMv2 or kerberos v5 */
409                 /* one byte - no need to convert this or EncryptionKeyLen
410                    from little endian */
411                 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
412                 /* probably no need to store and check maxvcs */
413                 server->maxBuf =
414                         min(le32_to_cpu(pSMBr->MaxBufferSize),
415                         (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
416                 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
417                 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
418                 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
419                 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
420                 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
421         /* BB with UTC do we ever need to be using srvr timezone? */
422                 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
423                         memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
424                                CIFS_CRYPTO_KEY_SIZE);
425                 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
426                            && (pSMBr->EncryptionKeyLength == 0)) {
427                         /* decode security blob */
428                 } else
429                         rc = -EIO;
430
431                 /* BB might be helpful to save off the domain of server here */
432
433                 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
434                         (server->capabilities & CAP_EXTENDED_SECURITY)) {
435                         count = pSMBr->ByteCount;
436                         if (count < 16)
437                                 rc = -EIO;
438                         else if (count == 16) {
439                                 server->secType = RawNTLMSSP;
440                                 if (server->socketUseCount.counter > 1) {
441                                         if (memcmp
442                                                 (server->server_GUID,
443                                                 pSMBr->u.extended_response.
444                                                 GUID, 16) != 0) {
445                                                 cFYI(1, ("server UID changed"));
446                                                 memcpy(server->
447                                                         server_GUID,
448                                                         pSMBr->u.
449                                                         extended_response.
450                                                         GUID, 16);
451                                         }
452                                 } else
453                                         memcpy(server->server_GUID,
454                                                pSMBr->u.extended_response.
455                                                GUID, 16);
456                         } else {
457                                 rc = decode_negTokenInit(pSMBr->u.
458                                                          extended_response.
459                                                          SecurityBlob,
460                                                          count - 16,
461                                                          &server->secType);
462                                 if(rc == 1) {
463                                 /* BB Need to fill struct for sessetup here */
464                                         rc = -EOPNOTSUPP;
465                                 } else {
466                                         rc = -EINVAL;
467                                 }
468                         }
469                 } else
470                         server->capabilities &= ~CAP_EXTENDED_SECURITY;
471                 if(sign_CIFS_PDUs == FALSE) {        
472                         if(server->secMode & SECMODE_SIGN_REQUIRED)
473                                 cERROR(1,
474                                  ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
475                         server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
476                 } else if(sign_CIFS_PDUs == 1) {
477                         if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
478                                 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
479                 }
480                                 
481         }
482         
483         cifs_buf_release(pSMB);
484         return rc;
485 }
486
487 int
488 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
489 {
490         struct smb_hdr *smb_buffer;
491         struct smb_hdr *smb_buffer_response; /* BB removeme BB */
492         int rc = 0;
493         int length;
494
495         cFYI(1, ("In tree disconnect"));
496         /*
497          *  If last user of the connection and
498          *  connection alive - disconnect it
499          *  If this is the last connection on the server session disconnect it
500          *  (and inside session disconnect we should check if tcp socket needs 
501          *  to be freed and kernel thread woken up).
502          */
503         if (tcon)
504                 down(&tcon->tconSem);
505         else
506                 return -EIO;
507
508         atomic_dec(&tcon->useCount);
509         if (atomic_read(&tcon->useCount) > 0) {
510                 up(&tcon->tconSem);
511                 return -EBUSY;
512         }
513
514         /* No need to return error on this operation if tid invalidated and 
515         closed on server already e.g. due to tcp session crashing */
516         if(tcon->tidStatus == CifsNeedReconnect) {
517                 up(&tcon->tconSem);
518                 return 0;  
519         }
520
521         if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {    
522                 up(&tcon->tconSem);
523                 return -EIO;
524         }
525         rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 
526                             (void **)&smb_buffer);
527         if (rc) {
528                 up(&tcon->tconSem);
529                 return rc;
530         } else {
531                 smb_buffer_response = smb_buffer; /* BB removeme BB */
532         }
533         rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
534                          &length, 0);
535         if (rc)
536                 cFYI(1, ("Tree disconnect failed %d", rc));
537
538         if (smb_buffer)
539                 cifs_small_buf_release(smb_buffer);
540         up(&tcon->tconSem);
541
542         /* No need to return error on this operation if tid invalidated and 
543         closed on server already e.g. due to tcp session crashing */
544         if (rc == -EAGAIN)
545                 rc = 0;
546
547         return rc;
548 }
549
550 int
551 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
552 {
553         struct smb_hdr *smb_buffer_response;
554         LOGOFF_ANDX_REQ *pSMB;
555         int rc = 0;
556         int length;
557
558         cFYI(1, ("In SMBLogoff for session disconnect"));
559         if (ses)
560                 down(&ses->sesSem);
561         else
562                 return -EIO;
563
564         atomic_dec(&ses->inUse);
565         if (atomic_read(&ses->inUse) > 0) {
566                 up(&ses->sesSem);
567                 return -EBUSY;
568         }
569         rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
570         if (rc) {
571                 up(&ses->sesSem);
572                 return rc;
573         }
574
575         smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
576         
577         if(ses->server) {
578                 pSMB->hdr.Mid = GetNextMid(ses->server);
579
580                 if(ses->server->secMode & 
581                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
582                         pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
583         }
584
585         pSMB->hdr.Uid = ses->Suid;
586
587         pSMB->AndXCommand = 0xFF;
588         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
589                          smb_buffer_response, &length, 0);
590         if (ses->server) {
591                 atomic_dec(&ses->server->socketUseCount);
592                 if (atomic_read(&ses->server->socketUseCount) == 0) {
593                         spin_lock(&GlobalMid_Lock);
594                         ses->server->tcpStatus = CifsExiting;
595                         spin_unlock(&GlobalMid_Lock);
596                         rc = -ESHUTDOWN;
597                 }
598         }
599         up(&ses->sesSem);
600         cifs_small_buf_release(pSMB);
601
602         /* if session dead then we do not need to do ulogoff,
603                 since server closed smb session, no sense reporting 
604                 error */
605         if (rc == -EAGAIN)
606                 rc = 0;
607         return rc;
608 }
609
610 int
611 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
612                const struct nls_table *nls_codepage, int remap)
613 {
614         DELETE_FILE_REQ *pSMB = NULL;
615         DELETE_FILE_RSP *pSMBr = NULL;
616         int rc = 0;
617         int bytes_returned;
618         int name_len;
619
620 DelFileRetry:
621         rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
622                       (void **) &pSMBr);
623         if (rc)
624                 return rc;
625
626         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
627                 name_len =
628                     cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, 
629                                      PATH_MAX, nls_codepage, remap);
630                 name_len++;     /* trailing null */
631                 name_len *= 2;
632         } else {                /* BB improve check for buffer overruns BB */
633                 name_len = strnlen(fileName, PATH_MAX);
634                 name_len++;     /* trailing null */
635                 strncpy(pSMB->fileName, fileName, name_len);
636         }
637         pSMB->SearchAttributes =
638             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
639         pSMB->BufferFormat = 0x04;
640         pSMB->hdr.smb_buf_length += name_len + 1;
641         pSMB->ByteCount = cpu_to_le16(name_len + 1);
642         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
643                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
644         cifs_stats_inc(&tcon->num_deletes);
645         if (rc) {
646                 cFYI(1, ("Error in RMFile = %d", rc));
647         } 
648
649         cifs_buf_release(pSMB);
650         if (rc == -EAGAIN)
651                 goto DelFileRetry;
652
653         return rc;
654 }
655
656 int
657 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, 
658              const struct nls_table *nls_codepage, int remap)
659 {
660         DELETE_DIRECTORY_REQ *pSMB = NULL;
661         DELETE_DIRECTORY_RSP *pSMBr = NULL;
662         int rc = 0;
663         int bytes_returned;
664         int name_len;
665
666         cFYI(1, ("In CIFSSMBRmDir"));
667 RmDirRetry:
668         rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
669                       (void **) &pSMBr);
670         if (rc)
671                 return rc;
672
673         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
674                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
675                                          PATH_MAX, nls_codepage, remap);
676                 name_len++;     /* trailing null */
677                 name_len *= 2;
678         } else {                /* BB improve check for buffer overruns BB */
679                 name_len = strnlen(dirName, PATH_MAX);
680                 name_len++;     /* trailing null */
681                 strncpy(pSMB->DirName, dirName, name_len);
682         }
683
684         pSMB->BufferFormat = 0x04;
685         pSMB->hdr.smb_buf_length += name_len + 1;
686         pSMB->ByteCount = cpu_to_le16(name_len + 1);
687         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
688                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
689         cifs_stats_inc(&tcon->num_rmdirs);
690         if (rc) {
691                 cFYI(1, ("Error in RMDir = %d", rc));
692         }
693
694         cifs_buf_release(pSMB);
695         if (rc == -EAGAIN)
696                 goto RmDirRetry;
697         return rc;
698 }
699
700 int
701 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
702              const char *name, const struct nls_table *nls_codepage, int remap)
703 {
704         int rc = 0;
705         CREATE_DIRECTORY_REQ *pSMB = NULL;
706         CREATE_DIRECTORY_RSP *pSMBr = NULL;
707         int bytes_returned;
708         int name_len;
709
710         cFYI(1, ("In CIFSSMBMkDir"));
711 MkDirRetry:
712         rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
713                       (void **) &pSMBr);
714         if (rc)
715                 return rc;
716
717         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
718                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, 
719                                             PATH_MAX, nls_codepage, remap);
720                 name_len++;     /* trailing null */
721                 name_len *= 2;
722         } else {                /* BB improve check for buffer overruns BB */
723                 name_len = strnlen(name, PATH_MAX);
724                 name_len++;     /* trailing null */
725                 strncpy(pSMB->DirName, name, name_len);
726         }
727
728         pSMB->BufferFormat = 0x04;
729         pSMB->hdr.smb_buf_length += name_len + 1;
730         pSMB->ByteCount = cpu_to_le16(name_len + 1);
731         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
732                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
733         cifs_stats_inc(&tcon->num_mkdirs);
734         if (rc) {
735                 cFYI(1, ("Error in Mkdir = %d", rc));
736         }
737
738         cifs_buf_release(pSMB);
739         if (rc == -EAGAIN)
740                 goto MkDirRetry;
741         return rc;
742 }
743
744 static __u16 convert_disposition(int disposition)
745 {
746         __u16 ofun = 0;
747
748         switch (disposition) {
749                 case FILE_SUPERSEDE:
750                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
751                         break;
752                 case FILE_OPEN:
753                         ofun = SMBOPEN_OAPPEND;
754                         break;
755                 case FILE_CREATE:
756                         ofun = SMBOPEN_OCREATE;
757                         break;
758                 case FILE_OPEN_IF:
759                         ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
760                         break;
761                 case FILE_OVERWRITE:
762                         ofun = SMBOPEN_OTRUNC;
763                         break;
764                 case FILE_OVERWRITE_IF:
765                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
766                         break;
767                 default:
768                         cFYI(1,("unknown disposition %d",disposition));
769                         ofun =  SMBOPEN_OAPPEND; /* regular open */
770         }
771         return ofun;
772 }
773
774 int
775 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
776             const char *fileName, const int openDisposition,
777             const int access_flags, const int create_options, __u16 * netfid,
778             int *pOplock, FILE_ALL_INFO * pfile_info,
779             const struct nls_table *nls_codepage, int remap)
780 {
781         int rc = -EACCES;
782         OPENX_REQ *pSMB = NULL;
783         OPENX_RSP *pSMBr = NULL;
784         int bytes_returned;
785         int name_len;
786         __u16 count;
787
788 OldOpenRetry:
789         rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
790                       (void **) &pSMBr);
791         if (rc)
792                 return rc;
793
794         pSMB->AndXCommand = 0xFF;       /* none */
795
796         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
797                 count = 1;      /* account for one byte pad to word boundary */
798                 name_len =
799                    cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
800                                     fileName, PATH_MAX, nls_codepage, remap);
801                 name_len++;     /* trailing null */
802                 name_len *= 2;
803         } else {                /* BB improve check for buffer overruns BB */
804                 count = 0;      /* no pad */
805                 name_len = strnlen(fileName, PATH_MAX);
806                 name_len++;     /* trailing null */
807                 strncpy(pSMB->fileName, fileName, name_len);
808         }
809         if (*pOplock & REQ_OPLOCK)
810                 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
811         else if (*pOplock & REQ_BATCHOPLOCK) {
812                 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
813         }
814         pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
815         /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
816         /* 0 = read
817            1 = write
818            2 = rw
819            3 = execute
820         */
821         pSMB->Mode = cpu_to_le16(2);
822         pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
823         /* set file as system file if special file such
824            as fifo and server expecting SFU style and
825            no Unix extensions */
826
827         if(create_options & CREATE_OPTION_SPECIAL)
828                 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
829         else
830                 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
831
832         /* if ((omode & S_IWUGO) == 0)
833                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
834         /*  Above line causes problems due to vfs splitting create into two
835             pieces - need to set mode after file created not while it is
836             being created */
837
838         /* BB FIXME BB */
839 /*      pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
840         /* BB FIXME END BB */
841
842         pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
843         pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
844         count += name_len;
845         pSMB->hdr.smb_buf_length += count;
846
847         pSMB->ByteCount = cpu_to_le16(count);
848         /* long_op set to 1 to allow for oplock break timeouts */
849         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
850                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
851         cifs_stats_inc(&tcon->num_opens);
852         if (rc) {
853                 cFYI(1, ("Error in Open = %d", rc));
854         } else {
855         /* BB verify if wct == 15 */
856
857 /*              *pOplock = pSMBr->OplockLevel; */  /* BB take from action field BB */
858
859                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
860                 /* Let caller know file was created so we can set the mode. */
861                 /* Do we care about the CreateAction in any other cases? */
862         /* BB FIXME BB */
863 /*              if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
864                         *pOplock |= CIFS_CREATE_ACTION; */
865         /* BB FIXME END */
866
867                 if(pfile_info) {
868                         pfile_info->CreationTime = 0; /* BB convert CreateTime*/
869                         pfile_info->LastAccessTime = 0; /* BB fixme */
870                         pfile_info->LastWriteTime = 0; /* BB fixme */
871                         pfile_info->ChangeTime = 0;  /* BB fixme */
872                         pfile_info->Attributes =
873                                 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 
874                         /* the file_info buf is endian converted by caller */
875                         pfile_info->AllocationSize =
876                                 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
877                         pfile_info->EndOfFile = pfile_info->AllocationSize;
878                         pfile_info->NumberOfLinks = cpu_to_le32(1);
879                 }
880         }
881
882         cifs_buf_release(pSMB);
883         if (rc == -EAGAIN)
884                 goto OldOpenRetry;
885         return rc;
886 }
887
888 int
889 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
890             const char *fileName, const int openDisposition,
891             const int access_flags, const int create_options, __u16 * netfid,
892             int *pOplock, FILE_ALL_INFO * pfile_info, 
893             const struct nls_table *nls_codepage, int remap)
894 {
895         int rc = -EACCES;
896         OPEN_REQ *pSMB = NULL;
897         OPEN_RSP *pSMBr = NULL;
898         int bytes_returned;
899         int name_len;
900         __u16 count;
901
902 openRetry:
903         rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
904                       (void **) &pSMBr);
905         if (rc)
906                 return rc;
907
908         pSMB->AndXCommand = 0xFF;       /* none */
909
910         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
911                 count = 1;      /* account for one byte pad to word boundary */
912                 name_len =
913                     cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
914                                      fileName, PATH_MAX, nls_codepage, remap);
915                 name_len++;     /* trailing null */
916                 name_len *= 2;
917                 pSMB->NameLength = cpu_to_le16(name_len);
918         } else {                /* BB improve check for buffer overruns BB */
919                 count = 0;      /* no pad */
920                 name_len = strnlen(fileName, PATH_MAX);
921                 name_len++;     /* trailing null */
922                 pSMB->NameLength = cpu_to_le16(name_len);
923                 strncpy(pSMB->fileName, fileName, name_len);
924         }
925         if (*pOplock & REQ_OPLOCK)
926                 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
927         else if (*pOplock & REQ_BATCHOPLOCK) {
928                 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
929         }
930         pSMB->DesiredAccess = cpu_to_le32(access_flags);
931         pSMB->AllocationSize = 0;
932         /* set file as system file if special file such
933            as fifo and server expecting SFU style and
934            no Unix extensions */
935         if(create_options & CREATE_OPTION_SPECIAL)
936                 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
937         else
938                 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
939         /* XP does not handle ATTR_POSIX_SEMANTICS */
940         /* but it helps speed up case sensitive checks for other
941         servers such as Samba */
942         if (tcon->ses->capabilities & CAP_UNIX)
943                 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
944
945         /* if ((omode & S_IWUGO) == 0)
946                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
947         /*  Above line causes problems due to vfs splitting create into two
948                 pieces - need to set mode after file created not while it is
949                 being created */
950         pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
951         pSMB->CreateDisposition = cpu_to_le32(openDisposition);
952         pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
953         /* BB Expirement with various impersonation levels and verify */
954         pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
955         pSMB->SecurityFlags =
956             SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
957
958         count += name_len;
959         pSMB->hdr.smb_buf_length += count;
960
961         pSMB->ByteCount = cpu_to_le16(count);
962         /* long_op set to 1 to allow for oplock break timeouts */
963         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
964                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
965         cifs_stats_inc(&tcon->num_opens);
966         if (rc) {
967                 cFYI(1, ("Error in Open = %d", rc));
968         } else {
969                 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
970                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
971                 /* Let caller know file was created so we can set the mode. */
972                 /* Do we care about the CreateAction in any other cases? */
973                 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
974                         *pOplock |= CIFS_CREATE_ACTION; 
975                 if(pfile_info) {
976                     memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
977                         36 /* CreationTime to Attributes */);
978                     /* the file_info buf is endian converted by caller */
979                     pfile_info->AllocationSize = pSMBr->AllocationSize;
980                     pfile_info->EndOfFile = pSMBr->EndOfFile;
981                     pfile_info->NumberOfLinks = cpu_to_le32(1);
982                 }
983         }
984
985         cifs_buf_release(pSMB);
986         if (rc == -EAGAIN)
987                 goto openRetry;
988         return rc;
989 }
990
991 int
992 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
993             const int netfid, const unsigned int count,
994             const __u64 lseek, unsigned int *nbytes, char **buf,
995             int * pbuf_type)
996 {
997         int rc = -EACCES;
998         READ_REQ *pSMB = NULL;
999         READ_RSP *pSMBr = NULL;
1000         char *pReadData = NULL;
1001         int wct;
1002         int resp_buf_type = 0;
1003         struct kvec iov[1];
1004
1005         cFYI(1,("Reading %d bytes on fid %d",count,netfid));
1006         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1007                 wct = 12;
1008         else
1009                 wct = 10; /* old style read */
1010
1011         *nbytes = 0;
1012         rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1013         if (rc)
1014                 return rc;
1015
1016         /* tcon and ses pointer are checked in smb_init */
1017         if (tcon->ses->server == NULL)
1018                 return -ECONNABORTED;
1019
1020         pSMB->AndXCommand = 0xFF;       /* none */
1021         pSMB->Fid = netfid;
1022         pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1023         if(wct == 12)
1024                 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1025         else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1026                 return -EIO;
1027
1028         pSMB->Remaining = 0;
1029         pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1030         pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1031         if(wct == 12)
1032                 pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
1033         else {
1034                 /* old style read */
1035                 struct smb_com_readx_req * pSMBW =
1036                         (struct smb_com_readx_req *)pSMB;
1037                 pSMBW->ByteCount = 0;
1038         }
1039
1040         iov[0].iov_base = (char *)pSMB;
1041         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1042         rc = SendReceive2(xid, tcon->ses, iov, 
1043                           1 /* num iovecs */,
1044                           &resp_buf_type, 0); 
1045         cifs_stats_inc(&tcon->num_reads);
1046         pSMBr = (READ_RSP *)iov[0].iov_base;
1047         if (rc) {
1048                 cERROR(1, ("Send error in read = %d", rc));
1049         } else {
1050                 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1051                 data_length = data_length << 16;
1052                 data_length += le16_to_cpu(pSMBr->DataLength);
1053                 *nbytes = data_length;
1054
1055                 /*check that DataLength would not go beyond end of SMB */
1056                 if ((data_length > CIFSMaxBufSize)
1057                                 || (data_length > count)) {
1058                         cFYI(1,("bad length %d for count %d",data_length,count));
1059                         rc = -EIO;
1060                         *nbytes = 0;
1061                 } else {
1062                         pReadData = (char *) (&pSMBr->hdr.Protocol) +
1063                             le16_to_cpu(pSMBr->DataOffset);
1064 /*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
1065                                 cERROR(1,("Faulting on read rc = %d",rc));
1066                                 rc = -EFAULT;
1067                         }*/ /* can not use copy_to_user when using page cache*/
1068                         if(*buf)
1069                                 memcpy(*buf,pReadData,data_length);
1070                 }
1071         }
1072
1073 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1074         if(*buf) {
1075                 if(resp_buf_type == CIFS_SMALL_BUFFER)
1076                         cifs_small_buf_release(iov[0].iov_base);
1077                 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1078                         cifs_buf_release(iov[0].iov_base);
1079         } else if(resp_buf_type != CIFS_NO_BUFFER) {
1080                 /* return buffer to caller to free */ 
1081                 *buf = iov[0].iov_base;         
1082                 if(resp_buf_type == CIFS_SMALL_BUFFER)
1083                         *pbuf_type = CIFS_SMALL_BUFFER;
1084                 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1085                         *pbuf_type = CIFS_LARGE_BUFFER;
1086         } /* else no valid buffer on return - leave as null */
1087
1088         /* Note: On -EAGAIN error only caller can retry on handle based calls
1089                 since file handle passed in no longer valid */
1090         return rc;
1091 }
1092
1093
1094 int
1095 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1096              const int netfid, const unsigned int count,
1097              const __u64 offset, unsigned int *nbytes, const char *buf,
1098              const char __user * ubuf, const int long_op)
1099 {
1100         int rc = -EACCES;
1101         WRITE_REQ *pSMB = NULL;
1102         WRITE_RSP *pSMBr = NULL;
1103         int bytes_returned, wct;
1104         __u32 bytes_sent;
1105         __u16 byte_count;
1106
1107         /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1108         if(tcon->ses == NULL)
1109                 return -ECONNABORTED;
1110
1111         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1112                 wct = 14;
1113         else
1114                 wct = 12;
1115
1116         rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1117                       (void **) &pSMBr);
1118         if (rc)
1119                 return rc;
1120         /* tcon and ses pointer are checked in smb_init */
1121         if (tcon->ses->server == NULL)
1122                 return -ECONNABORTED;
1123
1124         pSMB->AndXCommand = 0xFF;       /* none */
1125         pSMB->Fid = netfid;
1126         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1127         if(wct == 14) 
1128                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1129         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1130                 return -EIO;
1131         
1132         pSMB->Reserved = 0xFFFFFFFF;
1133         pSMB->WriteMode = 0;
1134         pSMB->Remaining = 0;
1135
1136         /* Can increase buffer size if buffer is big enough in some cases - ie we 
1137         can send more if LARGE_WRITE_X capability returned by the server and if
1138         our buffer is big enough or if we convert to iovecs on socket writes
1139         and eliminate the copy to the CIFS buffer */
1140         if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1141                 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1142         } else {
1143                 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1144                          & ~0xFF;
1145         }
1146
1147         if (bytes_sent > count)
1148                 bytes_sent = count;
1149         pSMB->DataOffset =
1150                 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1151         if(buf)
1152             memcpy(pSMB->Data,buf,bytes_sent);
1153         else if(ubuf) {
1154                 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1155                         cifs_buf_release(pSMB);
1156                         return -EFAULT;
1157                 }
1158         } else if (count != 0) {
1159                 /* No buffer */
1160                 cifs_buf_release(pSMB);
1161                 return -EINVAL;
1162         } /* else setting file size with write of zero bytes */
1163         if(wct == 14)
1164                 byte_count = bytes_sent + 1; /* pad */
1165         else /* wct == 12 */ {
1166                 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1167         }
1168         pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1169         pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1170         pSMB->hdr.smb_buf_length += byte_count;
1171
1172         if(wct == 14)
1173                 pSMB->ByteCount = cpu_to_le16(byte_count);
1174         else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
1175                 struct smb_com_writex_req * pSMBW = 
1176                         (struct smb_com_writex_req *)pSMB;
1177                 pSMBW->ByteCount = cpu_to_le16(byte_count);
1178         }
1179
1180         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1181                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1182         cifs_stats_inc(&tcon->num_writes);
1183         if (rc) {
1184                 cFYI(1, ("Send error in write = %d", rc));
1185                 *nbytes = 0;
1186         } else {
1187                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1188                 *nbytes = (*nbytes) << 16;
1189                 *nbytes += le16_to_cpu(pSMBr->Count);
1190         }
1191
1192         cifs_buf_release(pSMB);
1193
1194         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1195                 since file handle passed in no longer valid */
1196
1197         return rc;
1198 }
1199
1200 int
1201 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1202              const int netfid, const unsigned int count,
1203              const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1204              int n_vec, const int long_op)
1205 {
1206         int rc = -EACCES;
1207         WRITE_REQ *pSMB = NULL;
1208         int wct;
1209         int smb_hdr_len;
1210         int resp_buf_type = 0;
1211
1212         cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1213
1214         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1215                 wct = 14;
1216         else
1217                 wct = 12;
1218         rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1219         if (rc)
1220                 return rc;
1221         /* tcon and ses pointer are checked in smb_init */
1222         if (tcon->ses->server == NULL)
1223                 return -ECONNABORTED;
1224
1225         pSMB->AndXCommand = 0xFF;       /* none */
1226         pSMB->Fid = netfid;
1227         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1228         if(wct == 14)
1229                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1230         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1231                 return -EIO;
1232         pSMB->Reserved = 0xFFFFFFFF;
1233         pSMB->WriteMode = 0;
1234         pSMB->Remaining = 0;
1235
1236         pSMB->DataOffset =
1237             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1238
1239         pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1240         pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1241         smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1242         if(wct == 14)
1243                 pSMB->hdr.smb_buf_length += count+1;
1244         else /* wct == 12 */
1245                 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ 
1246         if(wct == 14)
1247                 pSMB->ByteCount = cpu_to_le16(count + 1);
1248         else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1249                 struct smb_com_writex_req * pSMBW =
1250                                 (struct smb_com_writex_req *)pSMB;
1251                 pSMBW->ByteCount = cpu_to_le16(count + 5);
1252         }
1253         iov[0].iov_base = pSMB;
1254         if(wct == 14)
1255                 iov[0].iov_len = smb_hdr_len + 4;
1256         else /* wct == 12 pad bigger by four bytes */
1257                 iov[0].iov_len = smb_hdr_len + 8;
1258         
1259
1260         rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1261                           long_op);
1262         cifs_stats_inc(&tcon->num_writes);
1263         if (rc) {
1264                 cFYI(1, ("Send error Write2 = %d", rc));
1265                 *nbytes = 0;
1266         } else if(resp_buf_type == 0) {
1267                 /* presumably this can not happen, but best to be safe */
1268                 rc = -EIO;
1269                 *nbytes = 0;
1270         } else {
1271                 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1272                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1273                 *nbytes = (*nbytes) << 16;
1274                 *nbytes += le16_to_cpu(pSMBr->Count);
1275         } 
1276
1277 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1278         if(resp_buf_type == CIFS_SMALL_BUFFER)
1279                 cifs_small_buf_release(iov[0].iov_base);
1280         else if(resp_buf_type == CIFS_LARGE_BUFFER)
1281                 cifs_buf_release(iov[0].iov_base);
1282
1283         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1284                 since file handle passed in no longer valid */
1285
1286         return rc;
1287 }
1288
1289
1290 int
1291 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1292             const __u16 smb_file_id, const __u64 len,
1293             const __u64 offset, const __u32 numUnlock,
1294             const __u32 numLock, const __u8 lockType, const int waitFlag)
1295 {
1296         int rc = 0;
1297         LOCK_REQ *pSMB = NULL;
1298         LOCK_RSP *pSMBr = NULL;
1299         int bytes_returned;
1300         int timeout = 0;
1301         __u16 count;
1302
1303         cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1304         rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1305
1306         if (rc)
1307                 return rc;
1308
1309         pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1310
1311         if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1312                 timeout = -1; /* no response expected */
1313                 pSMB->Timeout = 0;
1314         } else if (waitFlag == TRUE) {
1315                 timeout = 3;  /* blocking operation, no timeout */
1316                 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1317         } else {
1318                 pSMB->Timeout = 0;
1319         }
1320
1321         pSMB->NumberOfLocks = cpu_to_le16(numLock);
1322         pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1323         pSMB->LockType = lockType;
1324         pSMB->AndXCommand = 0xFF;       /* none */
1325         pSMB->Fid = smb_file_id; /* netfid stays le */
1326
1327         if((numLock != 0) || (numUnlock != 0)) {
1328                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1329                 /* BB where to store pid high? */
1330                 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1331                 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1332                 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1333                 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1334                 count = sizeof(LOCKING_ANDX_RANGE);
1335         } else {
1336                 /* oplock break */
1337                 count = 0;
1338         }
1339         pSMB->hdr.smb_buf_length += count;
1340         pSMB->ByteCount = cpu_to_le16(count);
1341
1342         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1343                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1344         cifs_stats_inc(&tcon->num_locks);
1345         if (rc) {
1346                 cFYI(1, ("Send error in Lock = %d", rc));
1347         }
1348         cifs_small_buf_release(pSMB);
1349
1350         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1351         since file handle passed in no longer valid */
1352         return rc;
1353 }
1354
1355 int
1356 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1357                 const __u16 smb_file_id, const int get_flag, const __u64 len,
1358                 const __u64 lkoffset, const __u16 lock_type, const int waitFlag)
1359 {
1360         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1361         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1362         char *data_offset;
1363         struct cifs_posix_lock *parm_data;
1364         int rc = 0;
1365         int bytes_returned = 0;
1366         __u16 params, param_offset, offset, byte_count, count;
1367
1368         cFYI(1, ("Posix Lock"));
1369         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1370
1371         if (rc)
1372                 return rc;
1373
1374         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1375
1376         params = 6; 
1377         pSMB->MaxSetupCount = 0;
1378         pSMB->Reserved = 0;
1379         pSMB->Flags = 0;
1380         pSMB->Timeout = 0;
1381         pSMB->Reserved2 = 0;
1382         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1383         offset = param_offset + params;
1384
1385         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1386
1387         count = sizeof(struct cifs_posix_lock);
1388         pSMB->MaxParameterCount = cpu_to_le16(2);
1389         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1390         pSMB->SetupCount = 1;
1391         pSMB->Reserved3 = 0;
1392         if(get_flag)
1393                 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1394         else
1395                 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1396         byte_count = 3 /* pad */  + params + count;
1397         pSMB->DataCount = cpu_to_le16(count);
1398         pSMB->ParameterCount = cpu_to_le16(params);
1399         pSMB->TotalDataCount = pSMB->DataCount;
1400         pSMB->TotalParameterCount = pSMB->ParameterCount;
1401         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1402         parm_data = (struct cifs_posix_lock *) 
1403                         (((char *) &pSMB->hdr.Protocol) + offset);
1404
1405         parm_data->lock_type = cpu_to_le16(lock_type);
1406         if(waitFlag)
1407                 parm_data->lock_flags = 1;
1408         parm_data->pid = cpu_to_le32(current->tgid);
1409         parm_data->start = lkoffset;
1410         parm_data->length = len;  /* normalize negative numbers */
1411
1412         pSMB->DataOffset = cpu_to_le16(offset);
1413         pSMB->Fid = smb_file_id;
1414         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1415         pSMB->Reserved4 = 0;
1416         pSMB->hdr.smb_buf_length += byte_count;
1417         pSMB->ByteCount = cpu_to_le16(byte_count);
1418         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1419                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1420         if (rc) {
1421                 cFYI(1, ("Send error in Posix Lock = %d", rc));
1422         }
1423
1424         if (pSMB)
1425                 cifs_small_buf_release(pSMB);
1426
1427         /* Note: On -EAGAIN error only caller can retry on handle based calls
1428            since file handle passed in no longer valid */
1429
1430         return rc;
1431 }
1432
1433
1434 int
1435 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1436 {
1437         int rc = 0;
1438         CLOSE_REQ *pSMB = NULL;
1439         CLOSE_RSP *pSMBr = NULL;
1440         int bytes_returned;
1441         cFYI(1, ("In CIFSSMBClose"));
1442
1443 /* do not retry on dead session on close */
1444         rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1445         if(rc == -EAGAIN)
1446                 return 0;
1447         if (rc)
1448                 return rc;
1449
1450         pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1451
1452         pSMB->FileID = (__u16) smb_file_id;
1453         pSMB->LastWriteTime = 0;
1454         pSMB->ByteCount = 0;
1455         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1456                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1457         cifs_stats_inc(&tcon->num_closes);
1458         if (rc) {
1459                 if(rc!=-EINTR) {
1460                         /* EINTR is expected when user ctl-c to kill app */
1461                         cERROR(1, ("Send error in Close = %d", rc));
1462                 }
1463         }
1464
1465         cifs_small_buf_release(pSMB);
1466
1467         /* Since session is dead, file will be closed on server already */
1468         if(rc == -EAGAIN)
1469                 rc = 0;
1470
1471         return rc;
1472 }
1473
1474 int
1475 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1476               const char *fromName, const char *toName,
1477               const struct nls_table *nls_codepage, int remap)
1478 {
1479         int rc = 0;
1480         RENAME_REQ *pSMB = NULL;
1481         RENAME_RSP *pSMBr = NULL;
1482         int bytes_returned;
1483         int name_len, name_len2;
1484         __u16 count;
1485
1486         cFYI(1, ("In CIFSSMBRename"));
1487 renameRetry:
1488         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1489                       (void **) &pSMBr);
1490         if (rc)
1491                 return rc;
1492
1493         pSMB->BufferFormat = 0x04;
1494         pSMB->SearchAttributes =
1495             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1496                         ATTR_DIRECTORY);
1497
1498         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1499                 name_len =
1500                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, 
1501                                      PATH_MAX, nls_codepage, remap);
1502                 name_len++;     /* trailing null */
1503                 name_len *= 2;
1504                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1505         /* protocol requires ASCII signature byte on Unicode string */
1506                 pSMB->OldFileName[name_len + 1] = 0x00;
1507                 name_len2 =
1508                     cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1509                                      toName, PATH_MAX, nls_codepage, remap);
1510                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1511                 name_len2 *= 2; /* convert to bytes */
1512         } else {                /* BB improve the check for buffer overruns BB */
1513                 name_len = strnlen(fromName, PATH_MAX);
1514                 name_len++;     /* trailing null */
1515                 strncpy(pSMB->OldFileName, fromName, name_len);
1516                 name_len2 = strnlen(toName, PATH_MAX);
1517                 name_len2++;    /* trailing null */
1518                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1519                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1520                 name_len2++;    /* trailing null */
1521                 name_len2++;    /* signature byte */
1522         }
1523
1524         count = 1 /* 1st signature byte */  + name_len + name_len2;
1525         pSMB->hdr.smb_buf_length += count;
1526         pSMB->ByteCount = cpu_to_le16(count);
1527
1528         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1529                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1530         cifs_stats_inc(&tcon->num_renames);
1531         if (rc) {
1532                 cFYI(1, ("Send error in rename = %d", rc));
1533         } 
1534
1535         cifs_buf_release(pSMB);
1536
1537         if (rc == -EAGAIN)
1538                 goto renameRetry;
1539
1540         return rc;
1541 }
1542
1543 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
1544                 int netfid, char * target_name, 
1545                 const struct nls_table * nls_codepage, int remap)
1546 {
1547         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1548         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1549         struct set_file_rename * rename_info;
1550         char *data_offset;
1551         char dummy_string[30];
1552         int rc = 0;
1553         int bytes_returned = 0;
1554         int len_of_str;
1555         __u16 params, param_offset, offset, count, byte_count;
1556
1557         cFYI(1, ("Rename to File by handle"));
1558         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1559                         (void **) &pSMBr);
1560         if (rc)
1561                 return rc;
1562
1563         params = 6;
1564         pSMB->MaxSetupCount = 0;
1565         pSMB->Reserved = 0;
1566         pSMB->Flags = 0;
1567         pSMB->Timeout = 0;
1568         pSMB->Reserved2 = 0;
1569         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1570         offset = param_offset + params;
1571
1572         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1573         rename_info = (struct set_file_rename *) data_offset;
1574         pSMB->MaxParameterCount = cpu_to_le16(2);
1575         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1576         pSMB->SetupCount = 1;
1577         pSMB->Reserved3 = 0;
1578         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1579         byte_count = 3 /* pad */  + params;
1580         pSMB->ParameterCount = cpu_to_le16(params);
1581         pSMB->TotalParameterCount = pSMB->ParameterCount;
1582         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1583         pSMB->DataOffset = cpu_to_le16(offset);
1584         /* construct random name ".cifs_tmp<inodenum><mid>" */
1585         rename_info->overwrite = cpu_to_le32(1);
1586         rename_info->root_fid  = 0;
1587         /* unicode only call */
1588         if(target_name == NULL) {
1589                 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1590                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1591                                         dummy_string, 24, nls_codepage, remap);
1592         } else {
1593                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1594                                         target_name, PATH_MAX, nls_codepage, remap);
1595         }
1596         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1597         count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1598         byte_count += count;
1599         pSMB->DataCount = cpu_to_le16(count);
1600         pSMB->TotalDataCount = pSMB->DataCount;
1601         pSMB->Fid = netfid;
1602         pSMB->InformationLevel =
1603                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1604         pSMB->Reserved4 = 0;
1605         pSMB->hdr.smb_buf_length += byte_count;
1606         pSMB->ByteCount = cpu_to_le16(byte_count);
1607         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1608                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1609         cifs_stats_inc(&pTcon->num_t2renames);
1610         if (rc) {
1611                 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1612         }
1613
1614         cifs_buf_release(pSMB);
1615
1616         /* Note: On -EAGAIN error only caller can retry on handle based calls
1617                 since file handle passed in no longer valid */
1618
1619         return rc;
1620 }
1621
1622 int
1623 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
1624             const __u16 target_tid, const char *toName, const int flags,
1625             const struct nls_table *nls_codepage, int remap)
1626 {
1627         int rc = 0;
1628         COPY_REQ *pSMB = NULL;
1629         COPY_RSP *pSMBr = NULL;
1630         int bytes_returned;
1631         int name_len, name_len2;
1632         __u16 count;
1633
1634         cFYI(1, ("In CIFSSMBCopy"));
1635 copyRetry:
1636         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1637                         (void **) &pSMBr);
1638         if (rc)
1639                 return rc;
1640
1641         pSMB->BufferFormat = 0x04;
1642         pSMB->Tid2 = target_tid;
1643
1644         pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1645
1646         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1647                 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, 
1648                                             fromName, PATH_MAX, nls_codepage,
1649                                             remap);
1650                 name_len++;     /* trailing null */
1651                 name_len *= 2;
1652                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1653                 /* protocol requires ASCII signature byte on Unicode string */
1654                 pSMB->OldFileName[name_len + 1] = 0x00;
1655                 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1656                                 toName, PATH_MAX, nls_codepage, remap);
1657                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1658                 name_len2 *= 2; /* convert to bytes */
1659         } else {                /* BB improve the check for buffer overruns BB */
1660                 name_len = strnlen(fromName, PATH_MAX);
1661                 name_len++;     /* trailing null */
1662                 strncpy(pSMB->OldFileName, fromName, name_len);
1663                 name_len2 = strnlen(toName, PATH_MAX);
1664                 name_len2++;    /* trailing null */
1665                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1666                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1667                 name_len2++;    /* trailing null */
1668                 name_len2++;    /* signature byte */
1669         }
1670
1671         count = 1 /* 1st signature byte */  + name_len + name_len2;
1672         pSMB->hdr.smb_buf_length += count;
1673         pSMB->ByteCount = cpu_to_le16(count);
1674
1675         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1676                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1677         if (rc) {
1678                 cFYI(1, ("Send error in copy = %d with %d files copied",
1679                         rc, le16_to_cpu(pSMBr->CopyCount)));
1680         }
1681         if (pSMB)
1682                 cifs_buf_release(pSMB);
1683
1684         if (rc == -EAGAIN)
1685                 goto copyRetry;
1686
1687         return rc;
1688 }
1689
1690 int
1691 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1692                       const char *fromName, const char *toName,
1693                       const struct nls_table *nls_codepage)
1694 {
1695         TRANSACTION2_SPI_REQ *pSMB = NULL;
1696         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1697         char *data_offset;
1698         int name_len;
1699         int name_len_target;
1700         int rc = 0;
1701         int bytes_returned = 0;
1702         __u16 params, param_offset, offset, byte_count;
1703
1704         cFYI(1, ("In Symlink Unix style"));
1705 createSymLinkRetry:
1706         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1707                       (void **) &pSMBr);
1708         if (rc)
1709                 return rc;
1710
1711         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1712                 name_len =
1713                     cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1714                                   /* find define for this maxpathcomponent */
1715                                   , nls_codepage);
1716                 name_len++;     /* trailing null */
1717                 name_len *= 2;
1718
1719         } else {                /* BB improve the check for buffer overruns BB */
1720                 name_len = strnlen(fromName, PATH_MAX);
1721                 name_len++;     /* trailing null */
1722                 strncpy(pSMB->FileName, fromName, name_len);
1723         }
1724         params = 6 + name_len;
1725         pSMB->MaxSetupCount = 0;
1726         pSMB->Reserved = 0;
1727         pSMB->Flags = 0;
1728         pSMB->Timeout = 0;
1729         pSMB->Reserved2 = 0;
1730         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1731                                      InformationLevel) - 4;
1732         offset = param_offset + params;
1733
1734         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1735         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1736                 name_len_target =
1737                     cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1738                                   /* find define for this maxpathcomponent */
1739                                   , nls_codepage);
1740                 name_len_target++;      /* trailing null */
1741                 name_len_target *= 2;
1742         } else {                /* BB improve the check for buffer overruns BB */
1743                 name_len_target = strnlen(toName, PATH_MAX);
1744                 name_len_target++;      /* trailing null */
1745                 strncpy(data_offset, toName, name_len_target);
1746         }
1747
1748         pSMB->MaxParameterCount = cpu_to_le16(2);
1749         /* BB find exact max on data count below from sess */
1750         pSMB->MaxDataCount = cpu_to_le16(1000);
1751         pSMB->SetupCount = 1;
1752         pSMB->Reserved3 = 0;
1753         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1754         byte_count = 3 /* pad */  + params + name_len_target;
1755         pSMB->DataCount = cpu_to_le16(name_len_target);
1756         pSMB->ParameterCount = cpu_to_le16(params);
1757         pSMB->TotalDataCount = pSMB->DataCount;
1758         pSMB->TotalParameterCount = pSMB->ParameterCount;
1759         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1760         pSMB->DataOffset = cpu_to_le16(offset);
1761         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1762         pSMB->Reserved4 = 0;
1763         pSMB->hdr.smb_buf_length += byte_count;
1764         pSMB->ByteCount = cpu_to_le16(byte_count);
1765         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1766                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1767         cifs_stats_inc(&tcon->num_symlinks);
1768         if (rc) {
1769                 cFYI(1,
1770                      ("Send error in SetPathInfo (create symlink) = %d",
1771                       rc));
1772         }
1773
1774         if (pSMB)
1775                 cifs_buf_release(pSMB);
1776
1777         if (rc == -EAGAIN)
1778                 goto createSymLinkRetry;
1779
1780         return rc;
1781 }
1782
1783 int
1784 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1785                        const char *fromName, const char *toName,
1786                        const struct nls_table *nls_codepage, int remap)
1787 {
1788         TRANSACTION2_SPI_REQ *pSMB = NULL;
1789         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1790         char *data_offset;
1791         int name_len;
1792         int name_len_target;
1793         int rc = 0;
1794         int bytes_returned = 0;
1795         __u16 params, param_offset, offset, byte_count;
1796
1797         cFYI(1, ("In Create Hard link Unix style"));
1798 createHardLinkRetry:
1799         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1800                       (void **) &pSMBr);
1801         if (rc)
1802                 return rc;
1803
1804         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1805                 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1806                                             PATH_MAX, nls_codepage, remap);
1807                 name_len++;     /* trailing null */
1808                 name_len *= 2;
1809
1810         } else {                /* BB improve the check for buffer overruns BB */
1811                 name_len = strnlen(toName, PATH_MAX);
1812                 name_len++;     /* trailing null */
1813                 strncpy(pSMB->FileName, toName, name_len);
1814         }
1815         params = 6 + name_len;
1816         pSMB->MaxSetupCount = 0;
1817         pSMB->Reserved = 0;
1818         pSMB->Flags = 0;
1819         pSMB->Timeout = 0;
1820         pSMB->Reserved2 = 0;
1821         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1822                                      InformationLevel) - 4;
1823         offset = param_offset + params;
1824
1825         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1826         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1827                 name_len_target =
1828                     cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1829                                      nls_codepage, remap);
1830                 name_len_target++;      /* trailing null */
1831                 name_len_target *= 2;
1832         } else {                /* BB improve the check for buffer overruns BB */
1833                 name_len_target = strnlen(fromName, PATH_MAX);
1834                 name_len_target++;      /* trailing null */
1835                 strncpy(data_offset, fromName, name_len_target);
1836         }
1837
1838         pSMB->MaxParameterCount = cpu_to_le16(2);
1839         /* BB find exact max on data count below from sess*/
1840         pSMB->MaxDataCount = cpu_to_le16(1000);
1841         pSMB->SetupCount = 1;
1842         pSMB->Reserved3 = 0;
1843         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1844         byte_count = 3 /* pad */  + params + name_len_target;
1845         pSMB->ParameterCount = cpu_to_le16(params);
1846         pSMB->TotalParameterCount = pSMB->ParameterCount;
1847         pSMB->DataCount = cpu_to_le16(name_len_target);
1848         pSMB->TotalDataCount = pSMB->DataCount;
1849         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1850         pSMB->DataOffset = cpu_to_le16(offset);
1851         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1852         pSMB->Reserved4 = 0;
1853         pSMB->hdr.smb_buf_length += byte_count;
1854         pSMB->ByteCount = cpu_to_le16(byte_count);
1855         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1856                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1857         cifs_stats_inc(&tcon->num_hardlinks);
1858         if (rc) {
1859                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1860         }
1861
1862         cifs_buf_release(pSMB);
1863         if (rc == -EAGAIN)
1864                 goto createHardLinkRetry;
1865
1866         return rc;
1867 }
1868
1869 int
1870 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1871                    const char *fromName, const char *toName,
1872                    const struct nls_table *nls_codepage, int remap)
1873 {
1874         int rc = 0;
1875         NT_RENAME_REQ *pSMB = NULL;
1876         RENAME_RSP *pSMBr = NULL;
1877         int bytes_returned;
1878         int name_len, name_len2;
1879         __u16 count;
1880
1881         cFYI(1, ("In CIFSCreateHardLink"));
1882 winCreateHardLinkRetry:
1883
1884         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1885                       (void **) &pSMBr);
1886         if (rc)
1887                 return rc;
1888
1889         pSMB->SearchAttributes =
1890             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1891                         ATTR_DIRECTORY);
1892         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1893         pSMB->ClusterCount = 0;
1894
1895         pSMB->BufferFormat = 0x04;
1896
1897         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1898                 name_len =
1899                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1900                                      PATH_MAX, nls_codepage, remap);
1901                 name_len++;     /* trailing null */
1902                 name_len *= 2;
1903                 pSMB->OldFileName[name_len] = 0;        /* pad */
1904                 pSMB->OldFileName[name_len + 1] = 0x04; 
1905                 name_len2 =
1906                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1907                                      toName, PATH_MAX, nls_codepage, remap);
1908                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1909                 name_len2 *= 2; /* convert to bytes */
1910         } else {                /* BB improve the check for buffer overruns BB */
1911                 name_len = strnlen(fromName, PATH_MAX);
1912                 name_len++;     /* trailing null */
1913                 strncpy(pSMB->OldFileName, fromName, name_len);
1914                 name_len2 = strnlen(toName, PATH_MAX);
1915                 name_len2++;    /* trailing null */
1916                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
1917                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1918                 name_len2++;    /* trailing null */
1919                 name_len2++;    /* signature byte */
1920         }
1921
1922         count = 1 /* string type byte */  + name_len + name_len2;
1923         pSMB->hdr.smb_buf_length += count;
1924         pSMB->ByteCount = cpu_to_le16(count);
1925
1926         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1927                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1928         cifs_stats_inc(&tcon->num_hardlinks);
1929         if (rc) {
1930                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1931         }
1932         cifs_buf_release(pSMB);
1933         if (rc == -EAGAIN)
1934                 goto winCreateHardLinkRetry;
1935
1936         return rc;
1937 }
1938
1939 int
1940 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1941                         const unsigned char *searchName,
1942                         char *symlinkinfo, const int buflen,
1943                         const struct nls_table *nls_codepage)
1944 {
1945 /* SMB_QUERY_FILE_UNIX_LINK */
1946         TRANSACTION2_QPI_REQ *pSMB = NULL;
1947         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1948         int rc = 0;
1949         int bytes_returned;
1950         int name_len;
1951         __u16 params, byte_count;
1952
1953         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1954
1955 querySymLinkRetry:
1956         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1957                       (void **) &pSMBr);
1958         if (rc)
1959                 return rc;
1960
1961         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1962                 name_len =
1963                     cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
1964                                   /* find define for this maxpathcomponent */
1965                                   , nls_codepage);
1966                 name_len++;     /* trailing null */
1967                 name_len *= 2;
1968         } else {                /* BB improve the check for buffer overruns BB */
1969                 name_len = strnlen(searchName, PATH_MAX);
1970                 name_len++;     /* trailing null */
1971                 strncpy(pSMB->FileName, searchName, name_len);
1972         }
1973
1974         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1975         pSMB->TotalDataCount = 0;
1976         pSMB->MaxParameterCount = cpu_to_le16(2);
1977         /* BB find exact max data count below from sess structure BB */
1978         pSMB->MaxDataCount = cpu_to_le16(4000);
1979         pSMB->MaxSetupCount = 0;
1980         pSMB->Reserved = 0;
1981         pSMB->Flags = 0;
1982         pSMB->Timeout = 0;
1983         pSMB->Reserved2 = 0;
1984         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1985         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1986         pSMB->DataCount = 0;
1987         pSMB->DataOffset = 0;
1988         pSMB->SetupCount = 1;
1989         pSMB->Reserved3 = 0;
1990         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1991         byte_count = params + 1 /* pad */ ;
1992         pSMB->TotalParameterCount = cpu_to_le16(params);
1993         pSMB->ParameterCount = pSMB->TotalParameterCount;
1994         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1995         pSMB->Reserved4 = 0;
1996         pSMB->hdr.smb_buf_length += byte_count;
1997         pSMB->ByteCount = cpu_to_le16(byte_count);
1998
1999         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2000                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2001         if (rc) {
2002                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2003         } else {
2004                 /* decode response */
2005
2006                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2007                 if (rc || (pSMBr->ByteCount < 2))
2008                 /* BB also check enough total bytes returned */
2009                         rc = -EIO;      /* bad smb */
2010                 else {
2011                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2012                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2013
2014                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2015                                 name_len = UniStrnlen((wchar_t *) ((char *)
2016                                         &pSMBr->hdr.Protocol +data_offset),
2017                                         min_t(const int, buflen,count) / 2);
2018                         /* BB FIXME investigate remapping reserved chars here */
2019                                 cifs_strfromUCS_le(symlinkinfo,
2020                                         (__le16 *) ((char *)&pSMBr->hdr.Protocol +
2021                                                 data_offset),
2022                                         name_len, nls_codepage);
2023                         } else {
2024                                 strncpy(symlinkinfo,
2025                                         (char *) &pSMBr->hdr.Protocol + 
2026                                                 data_offset,
2027                                         min_t(const int, buflen, count));
2028                         }
2029                         symlinkinfo[buflen] = 0;
2030         /* just in case so calling code does not go off the end of buffer */
2031                 }
2032         }
2033         cifs_buf_release(pSMB);
2034         if (rc == -EAGAIN)
2035                 goto querySymLinkRetry;
2036         return rc;
2037 }
2038
2039 /* Initialize NT TRANSACT SMB into small smb request buffer.
2040    This assumes that all NT TRANSACTS that we init here have
2041    total parm and data under about 400 bytes (to fit in small cifs
2042    buffer size), which is the case so far, it easily fits. NB:
2043         Setup words themselves and ByteCount
2044         MaxSetupCount (size of returned setup area) and
2045         MaxParameterCount (returned parms size) must be set by caller */
2046 static int 
2047 smb_init_ntransact(const __u16 sub_command, const int setup_count,
2048                    const int parm_len, struct cifsTconInfo *tcon,
2049                    void ** ret_buf)
2050 {
2051         int rc;
2052         __u32 temp_offset;
2053         struct smb_com_ntransact_req * pSMB;
2054
2055         rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2056                                 (void **)&pSMB);
2057         if (rc)
2058                 return rc;
2059         *ret_buf = (void *)pSMB;
2060         pSMB->Reserved = 0;
2061         pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2062         pSMB->TotalDataCount  = 0;
2063         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2064                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2065         pSMB->ParameterCount = pSMB->TotalParameterCount;
2066         pSMB->DataCount  = pSMB->TotalDataCount;
2067         temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2068                         (setup_count * 2) - 4 /* for rfc1001 length itself */;
2069         pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2070         pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2071         pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2072         pSMB->SubCommand = cpu_to_le16(sub_command);
2073         return 0;
2074 }
2075
2076 static int
2077 validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2078                    int * pdatalen, int * pparmlen)
2079 {
2080         char * end_of_smb;
2081         __u32 data_count, data_offset, parm_count, parm_offset;
2082         struct smb_com_ntransact_rsp * pSMBr;
2083
2084         if(buf == NULL)
2085                 return -EINVAL;
2086
2087         pSMBr = (struct smb_com_ntransact_rsp *)buf;
2088
2089         /* ByteCount was converted from little endian in SendReceive */
2090         end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + 
2091                         (char *)&pSMBr->ByteCount;
2092
2093                 
2094         data_offset = le32_to_cpu(pSMBr->DataOffset);
2095         data_count = le32_to_cpu(pSMBr->DataCount);
2096         parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2097         parm_count = le32_to_cpu(pSMBr->ParameterCount);
2098
2099         *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2100         *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2101
2102         /* should we also check that parm and data areas do not overlap? */
2103         if(*ppparm > end_of_smb) {
2104                 cFYI(1,("parms start after end of smb"));
2105                 return -EINVAL;
2106         } else if(parm_count + *ppparm > end_of_smb) {
2107                 cFYI(1,("parm end after end of smb"));
2108                 return -EINVAL;
2109         } else if(*ppdata > end_of_smb) {
2110                 cFYI(1,("data starts after end of smb"));
2111                 return -EINVAL;
2112         } else if(data_count + *ppdata > end_of_smb) {
2113                 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2114                         *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr));  /* BB FIXME */
2115                 return -EINVAL;
2116         } else if(parm_count + data_count > pSMBr->ByteCount) {
2117                 cFYI(1,("parm count and data count larger than SMB"));
2118                 return -EINVAL;
2119         }
2120         return 0;
2121 }
2122
2123 int
2124 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2125                         const unsigned char *searchName,
2126                         char *symlinkinfo, const int buflen,__u16 fid,
2127                         const struct nls_table *nls_codepage)
2128 {
2129         int rc = 0;
2130         int bytes_returned;
2131         int name_len;
2132         struct smb_com_transaction_ioctl_req * pSMB;
2133         struct smb_com_transaction_ioctl_rsp * pSMBr;
2134
2135         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2136         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2137                       (void **) &pSMBr);
2138         if (rc)
2139                 return rc;
2140
2141         pSMB->TotalParameterCount = 0 ;
2142         pSMB->TotalDataCount = 0;
2143         pSMB->MaxParameterCount = cpu_to_le32(2);
2144         /* BB find exact data count max from sess structure BB */
2145         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2146                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2147         pSMB->MaxSetupCount = 4;
2148         pSMB->Reserved = 0;
2149         pSMB->ParameterOffset = 0;
2150         pSMB->DataCount = 0;
2151         pSMB->DataOffset = 0;
2152         pSMB->SetupCount = 4;
2153         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2154         pSMB->ParameterCount = pSMB->TotalParameterCount;
2155         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2156         pSMB->IsFsctl = 1; /* FSCTL */
2157         pSMB->IsRootFlag = 0;
2158         pSMB->Fid = fid; /* file handle always le */
2159         pSMB->ByteCount = 0;
2160
2161         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2162                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2163         if (rc) {
2164                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2165         } else {                /* decode response */
2166                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2167                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2168                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2169                 /* BB also check enough total bytes returned */
2170                         rc = -EIO;      /* bad smb */
2171                 else {
2172                         if(data_count && (data_count < 2048)) {
2173                                 char * end_of_smb = 2 /* sizeof byte count */ +
2174                                                 pSMBr->ByteCount +
2175                                                 (char *)&pSMBr->ByteCount;
2176
2177                                 struct reparse_data * reparse_buf = (struct reparse_data *)
2178                                         ((char *)&pSMBr->hdr.Protocol + data_offset);
2179                                 if((char*)reparse_buf >= end_of_smb) {
2180                                         rc = -EIO;
2181                                         goto qreparse_out;
2182                                 }
2183                                 if((reparse_buf->LinkNamesBuf + 
2184                                         reparse_buf->TargetNameOffset +
2185                                         reparse_buf->TargetNameLen) >
2186                                                 end_of_smb) {
2187                                         cFYI(1,("reparse buf extended beyond SMB"));
2188                                         rc = -EIO;
2189                                         goto qreparse_out;
2190                                 }
2191                                 
2192                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2193                                         name_len = UniStrnlen((wchar_t *)
2194                                                         (reparse_buf->LinkNamesBuf + 
2195                                                         reparse_buf->TargetNameOffset),
2196                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
2197                                         cifs_strfromUCS_le(symlinkinfo,
2198                                                 (__le16 *) (reparse_buf->LinkNamesBuf + 
2199                                                 reparse_buf->TargetNameOffset),
2200                                                 name_len, nls_codepage);
2201                                 } else { /* ASCII names */
2202                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
2203                                                 reparse_buf->TargetNameOffset, 
2204                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
2205                                 }
2206                         } else {
2207                                 rc = -EIO;
2208                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2209                         }
2210                         symlinkinfo[buflen] = 0; /* just in case so the caller
2211                                         does not go off the end of the buffer */
2212                         cFYI(1,("readlink result - %s ",symlinkinfo));
2213                 }
2214         }
2215 qreparse_out:
2216         cifs_buf_release(pSMB);
2217
2218         /* Note: On -EAGAIN error only caller can retry on handle based calls
2219                 since file handle passed in no longer valid */
2220
2221         return rc;
2222 }
2223
2224 #ifdef CONFIG_CIFS_POSIX
2225
2226 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2227 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2228 {
2229         /* u8 cifs fields do not need le conversion */
2230         ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2231         ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
2232         ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2233         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2234
2235         return;
2236 }
2237
2238 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2239 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2240                                 const int acl_type,const int size_of_data_area)
2241 {
2242         int size =  0;
2243         int i;
2244         __u16 count;
2245         struct cifs_posix_ace * pACE;
2246         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2247         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2248
2249         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2250                 return -EOPNOTSUPP;
2251
2252         if(acl_type & ACL_TYPE_ACCESS) {
2253                 count = le16_to_cpu(cifs_acl->access_entry_count);
2254                 pACE = &cifs_acl->ace_array[0];
2255                 size = sizeof(struct cifs_posix_acl);
2256                 size += sizeof(struct cifs_posix_ace) * count;
2257                 /* check if we would go beyond end of SMB */
2258                 if(size_of_data_area < size) {
2259                         cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2260                         return -EINVAL;
2261                 }
2262         } else if(acl_type & ACL_TYPE_DEFAULT) {
2263                 count = le16_to_cpu(cifs_acl->access_entry_count);
2264                 size = sizeof(struct cifs_posix_acl);
2265                 size += sizeof(struct cifs_posix_ace) * count;
2266 /* skip past access ACEs to get to default ACEs */
2267                 pACE = &cifs_acl->ace_array[count];
2268                 count = le16_to_cpu(cifs_acl->default_entry_count);
2269                 size += sizeof(struct cifs_posix_ace) * count;
2270                 /* check if we would go beyond end of SMB */
2271                 if(size_of_data_area < size)
2272                         return -EINVAL;
2273         } else {
2274                 /* illegal type */
2275                 return -EINVAL;
2276         }
2277
2278         size = posix_acl_xattr_size(count);
2279         if((buflen == 0) || (local_acl == NULL)) {
2280                 /* used to query ACL EA size */                         
2281         } else if(size > buflen) {
2282                 return -ERANGE;
2283         } else /* buffer big enough */ {
2284                 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2285                 for(i = 0;i < count ;i++) {
2286                         cifs_convert_ace(&local_acl->a_entries[i],pACE);
2287                         pACE ++;
2288                 }
2289         }
2290         return size;
2291 }
2292
2293 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2294                         const posix_acl_xattr_entry * local_ace)
2295 {
2296         __u16 rc = 0; /* 0 = ACL converted ok */
2297
2298         cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2299         cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
2300         /* BB is there a better way to handle the large uid? */
2301         if(local_ace->e_id == cpu_to_le32(-1)) {
2302         /* Probably no need to le convert -1 on any arch but can not hurt */
2303                 cifs_ace->cifs_uid = cpu_to_le64(-1);
2304         } else 
2305                 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2306         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2307         return rc;
2308 }
2309
2310 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2311 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2312                 const int acl_type)
2313 {
2314         __u16 rc = 0;
2315         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2316         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2317         int count;
2318         int i;
2319
2320         if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2321                 return 0;
2322
2323         count = posix_acl_xattr_count((size_t)buflen);
2324         cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2325                 count, buflen, le32_to_cpu(local_acl->a_version)));
2326         if(le32_to_cpu(local_acl->a_version) != 2) {
2327                 cFYI(1,("unknown POSIX ACL version %d",
2328                      le32_to_cpu(local_acl->a_version)));
2329                 return 0;
2330         }
2331         cifs_acl->version = cpu_to_le16(1);
2332         if(acl_type == ACL_TYPE_ACCESS) 
2333                 cifs_acl->access_entry_count = cpu_to_le16(count);
2334         else if(acl_type == ACL_TYPE_DEFAULT)
2335                 cifs_acl->default_entry_count = cpu_to_le16(count);
2336         else {
2337                 cFYI(1,("unknown ACL type %d",acl_type));
2338                 return 0;
2339         }
2340         for(i=0;i<count;i++) {
2341                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2342                                         &local_acl->a_entries[i]);
2343                 if(rc != 0) {
2344                         /* ACE not converted */
2345                         break;
2346                 }
2347         }
2348         if(rc == 0) {
2349                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2350                 rc += sizeof(struct cifs_posix_acl);
2351                 /* BB add check to make sure ACL does not overflow SMB */
2352         }
2353         return rc;
2354 }
2355
2356 int
2357 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2358                         const unsigned char *searchName,
2359                         char *acl_inf, const int buflen, const int acl_type,
2360                         const struct nls_table *nls_codepage, int remap)
2361 {
2362 /* SMB_QUERY_POSIX_ACL */
2363         TRANSACTION2_QPI_REQ *pSMB = NULL;
2364         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2365         int rc = 0;
2366         int bytes_returned;
2367         int name_len;
2368         __u16 params, byte_count;
2369                                                                                                                                              
2370         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2371
2372 queryAclRetry:
2373         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2374                 (void **) &pSMBr);
2375         if (rc)
2376                 return rc;
2377                                                                                                                                              
2378         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2379                 name_len =
2380                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2381                                          PATH_MAX, nls_codepage, remap);
2382                 name_len++;     /* trailing null */
2383                 name_len *= 2;
2384                 pSMB->FileName[name_len] = 0;
2385                 pSMB->FileName[name_len+1] = 0;
2386         } else {                /* BB improve the check for buffer overruns BB */
2387                 name_len = strnlen(searchName, PATH_MAX);
2388                 name_len++;     /* trailing null */
2389                 strncpy(pSMB->FileName, searchName, name_len);
2390         }
2391
2392         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2393         pSMB->TotalDataCount = 0;
2394         pSMB->MaxParameterCount = cpu_to_le16(2);
2395         /* BB find exact max data count below from sess structure BB */
2396         pSMB->MaxDataCount = cpu_to_le16(4000);
2397         pSMB->MaxSetupCount = 0;
2398         pSMB->Reserved = 0;
2399         pSMB->Flags = 0;
2400         pSMB->Timeout = 0;
2401         pSMB->Reserved2 = 0;
2402         pSMB->ParameterOffset = cpu_to_le16(
2403                 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2404         pSMB->DataCount = 0;
2405         pSMB->DataOffset = 0;
2406         pSMB->SetupCount = 1;
2407         pSMB->Reserved3 = 0;
2408         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2409         byte_count = params + 1 /* pad */ ;
2410         pSMB->TotalParameterCount = cpu_to_le16(params);
2411         pSMB->ParameterCount = pSMB->TotalParameterCount;
2412         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2413         pSMB->Reserved4 = 0;
2414         pSMB->hdr.smb_buf_length += byte_count;
2415         pSMB->ByteCount = cpu_to_le16(byte_count);
2416
2417         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2418                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2419         cifs_stats_inc(&tcon->num_acl_get);
2420         if (rc) {
2421                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2422         } else {
2423                 /* decode response */
2424  
2425                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2426                 if (rc || (pSMBr->ByteCount < 2))
2427                 /* BB also check enough total bytes returned */
2428                         rc = -EIO;      /* bad smb */
2429                 else {
2430                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2431                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2432                         rc = cifs_copy_posix_acl(acl_inf,
2433                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2434                                 buflen,acl_type,count);
2435                 }
2436         }
2437         cifs_buf_release(pSMB);
2438         if (rc == -EAGAIN)
2439                 goto queryAclRetry;
2440         return rc;
2441 }
2442
2443 int
2444 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2445                         const unsigned char *fileName,
2446                         const char *local_acl, const int buflen, 
2447                         const int acl_type,
2448                         const struct nls_table *nls_codepage, int remap)
2449 {
2450         struct smb_com_transaction2_spi_req *pSMB = NULL;
2451         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2452         char *parm_data;
2453         int name_len;
2454         int rc = 0;
2455         int bytes_returned = 0;
2456         __u16 params, byte_count, data_count, param_offset, offset;
2457
2458         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2459 setAclRetry:
2460         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2461                       (void **) &pSMBr);
2462         if (rc)
2463                 return rc;
2464         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2465                 name_len =
2466                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
2467                                       PATH_MAX, nls_codepage, remap);
2468                 name_len++;     /* trailing null */
2469                 name_len *= 2;
2470         } else {                /* BB improve the check for buffer overruns BB */
2471                 name_len = strnlen(fileName, PATH_MAX);
2472                 name_len++;     /* trailing null */
2473                 strncpy(pSMB->FileName, fileName, name_len);
2474         }
2475         params = 6 + name_len;
2476         pSMB->MaxParameterCount = cpu_to_le16(2);
2477         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2478         pSMB->MaxSetupCount = 0;
2479         pSMB->Reserved = 0;
2480         pSMB->Flags = 0;
2481         pSMB->Timeout = 0;
2482         pSMB->Reserved2 = 0;
2483         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2484                                      InformationLevel) - 4;
2485         offset = param_offset + params;
2486         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2487         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2488
2489         /* convert to on the wire format for POSIX ACL */
2490         data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2491
2492         if(data_count == 0) {
2493                 rc = -EOPNOTSUPP;
2494                 goto setACLerrorExit;
2495         }
2496         pSMB->DataOffset = cpu_to_le16(offset);
2497         pSMB->SetupCount = 1;
2498         pSMB->Reserved3 = 0;
2499         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2500         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2501         byte_count = 3 /* pad */  + params + data_count;
2502         pSMB->DataCount = cpu_to_le16(data_count);
2503         pSMB->TotalDataCount = pSMB->DataCount;
2504         pSMB->ParameterCount = cpu_to_le16(params);
2505         pSMB->TotalParameterCount = pSMB->ParameterCount;
2506         pSMB->Reserved4 = 0;
2507         pSMB->hdr.smb_buf_length += byte_count;
2508         pSMB->ByteCount = cpu_to_le16(byte_count);
2509         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2510                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2511         if (rc) {
2512                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2513         }
2514
2515 setACLerrorExit:
2516         cifs_buf_release(pSMB);
2517         if (rc == -EAGAIN)
2518                 goto setAclRetry;
2519         return rc;
2520 }
2521
2522 /* BB fix tabs in this function FIXME BB */
2523 int
2524 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2525                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2526 {
2527         int rc = 0;
2528         struct smb_t2_qfi_req *pSMB = NULL;
2529         struct smb_t2_qfi_rsp *pSMBr = NULL;
2530         int bytes_returned;
2531         __u16 params, byte_count;
2532
2533         cFYI(1,("In GetExtAttr"));
2534         if(tcon == NULL)
2535                 return -ENODEV;
2536
2537 GetExtAttrRetry:
2538         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2539                       (void **) &pSMBr);
2540         if (rc)
2541                 return rc;
2542
2543         params = 2 /* level */ +2 /* fid */;
2544         pSMB->t2.TotalDataCount = 0;
2545         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2546         /* BB find exact max data count below from sess structure BB */
2547         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2548         pSMB->t2.MaxSetupCount = 0;
2549         pSMB->t2.Reserved = 0;
2550         pSMB->t2.Flags = 0;
2551         pSMB->t2.Timeout = 0;
2552         pSMB->t2.Reserved2 = 0;
2553         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2554                         Fid) - 4);
2555         pSMB->t2.DataCount = 0;
2556         pSMB->t2.DataOffset = 0;
2557         pSMB->t2.SetupCount = 1;
2558         pSMB->t2.Reserved3 = 0;
2559         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2560         byte_count = params + 1 /* pad */ ;
2561         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2562         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2563         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2564         pSMB->Pad = 0;
2565         pSMB->Fid = netfid;
2566         pSMB->hdr.smb_buf_length += byte_count;
2567         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2568
2569         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2570                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2571         if (rc) {
2572                 cFYI(1, ("error %d in GetExtAttr", rc));
2573         } else {
2574                 /* decode response */
2575                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2576                 if (rc || (pSMBr->ByteCount < 2))
2577                 /* BB also check enough total bytes returned */
2578                         /* If rc should we check for EOPNOSUPP and
2579                         disable the srvino flag? or in caller? */
2580                         rc = -EIO;      /* bad smb */
2581                 else {
2582                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2583                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2584                         struct file_chattr_info * pfinfo;
2585                         /* BB Do we need a cast or hash here ? */
2586                         if(count != 16) {
2587                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
2588                                 rc = -EIO;
2589                                 goto GetExtAttrOut;
2590                         }
2591                         pfinfo = (struct file_chattr_info *)
2592                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2593                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2594                         *pMask = le64_to_cpu(pfinfo->mask);
2595                 }
2596         }
2597 GetExtAttrOut:
2598         cifs_buf_release(pSMB);
2599         if (rc == -EAGAIN)
2600                 goto GetExtAttrRetry;
2601         return rc;
2602 }
2603
2604
2605 #endif /* CONFIG_POSIX */
2606
2607
2608 /* security id for everyone */
2609 const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2610 /* group users */
2611 const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2612
2613 /* Convert CIFS ACL to POSIX form */
2614 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2615 {
2616         return 0;
2617 }
2618
2619 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2620 int
2621 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2622          /*  BB fix up return info */ char *acl_inf, const int buflen, 
2623                   const int acl_type /* ACCESS/DEFAULT not sure implication */)
2624 {
2625         int rc = 0;
2626         int buf_type = 0;
2627         QUERY_SEC_DESC_REQ * pSMB;
2628         struct kvec iov[1];
2629
2630         cFYI(1, ("GetCifsACL"));
2631
2632         rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 
2633                         8 /* parm len */, tcon, (void **) &pSMB);
2634         if (rc)
2635                 return rc;
2636
2637         pSMB->MaxParameterCount = cpu_to_le32(4);
2638         /* BB TEST with big acls that might need to be e.g. larger than 16K */
2639         pSMB->MaxSetupCount = 0;
2640         pSMB->Fid = fid; /* file handle always le */
2641         pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2642                                      CIFS_ACL_DACL);
2643         pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2644         pSMB->hdr.smb_buf_length += 11;
2645         iov[0].iov_base = (char *)pSMB;
2646         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2647
2648         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2649         cifs_stats_inc(&tcon->num_acl_get);
2650         if (rc) {
2651                 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2652         } else {                /* decode response */
2653                 struct cifs_sid * psec_desc;
2654                 __le32 * parm;
2655                 int parm_len;
2656                 int data_len;
2657                 int acl_len;
2658                 struct smb_com_ntransact_rsp * pSMBr;
2659
2660 /* validate_nttransact */
2661                 rc = validate_ntransact(iov[0].iov_base, (char **)&parm, 
2662                                         (char **)&psec_desc,
2663                                         &parm_len, &data_len);
2664                 
2665                 if(rc)
2666                         goto qsec_out;
2667                 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2668
2669                 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc));  /* BB removeme BB */
2670
2671                 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2672                         rc = -EIO;      /* bad smb */
2673                         goto qsec_out;
2674                 }
2675
2676 /* BB check that data area is minimum length and as big as acl_len */
2677
2678                 acl_len = le32_to_cpu(*(__le32 *)parm);
2679                 /* BB check if(acl_len > bufsize) */
2680
2681                 parse_sec_desc(psec_desc, acl_len);
2682         }
2683 qsec_out:
2684         if(buf_type == CIFS_SMALL_BUFFER)
2685                 cifs_small_buf_release(iov[0].iov_base);
2686         else if(buf_type == CIFS_LARGE_BUFFER)
2687                 cifs_buf_release(iov[0].iov_base);
2688 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2689         return rc;
2690 }
2691
2692
2693 /* Legacy Query Path Information call for lookup to old servers such
2694    as Win9x/WinME */
2695 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2696                  const unsigned char *searchName,
2697                  FILE_ALL_INFO * pFinfo,
2698                  const struct nls_table *nls_codepage, int remap)
2699 {
2700         QUERY_INFORMATION_REQ * pSMB;
2701         QUERY_INFORMATION_RSP * pSMBr;
2702         int rc = 0;
2703         int bytes_returned;
2704         int name_len;
2705
2706         cFYI(1, ("In SMBQPath path %s", searchName)); 
2707 QInfRetry:
2708         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2709                       (void **) &pSMBr);
2710         if (rc)
2711                 return rc;
2712
2713         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2714                 name_len =
2715                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2716                                      PATH_MAX, nls_codepage, remap);
2717                 name_len++;     /* trailing null */
2718                 name_len *= 2;
2719         } else {               
2720                 name_len = strnlen(searchName, PATH_MAX);
2721                 name_len++;     /* trailing null */
2722                 strncpy(pSMB->FileName, searchName, name_len);
2723         }
2724         pSMB->BufferFormat = 0x04;
2725         name_len++; /* account for buffer type byte */  
2726         pSMB->hdr.smb_buf_length += (__u16) name_len;
2727         pSMB->ByteCount = cpu_to_le16(name_len);
2728
2729         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2730                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2731         if (rc) {
2732                 cFYI(1, ("Send error in QueryInfo = %d", rc));
2733         } else if (pFinfo) {            /* decode response */
2734                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2735                 pFinfo->AllocationSize =
2736                         cpu_to_le64(le32_to_cpu(pSMBr->size));
2737                 pFinfo->EndOfFile = pFinfo->AllocationSize;
2738                 pFinfo->Attributes =
2739                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
2740         } else
2741                 rc = -EIO; /* bad buffer passed in */
2742
2743         cifs_buf_release(pSMB);
2744
2745         if (rc == -EAGAIN)
2746                 goto QInfRetry;
2747
2748         return rc;
2749 }
2750
2751
2752
2753
2754 int
2755 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2756                  const unsigned char *searchName,
2757                  FILE_ALL_INFO * pFindData,
2758                  const struct nls_table *nls_codepage, int remap)
2759 {
2760 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2761         TRANSACTION2_QPI_REQ *pSMB = NULL;
2762         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2763         int rc = 0;
2764         int bytes_returned;
2765         int name_len;
2766         __u16 params, byte_count;
2767
2768 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2769 QPathInfoRetry:
2770         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2771                       (void **) &pSMBr);
2772         if (rc)
2773                 return rc;
2774
2775         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2776                 name_len =
2777                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2778                                      PATH_MAX, nls_codepage, remap);
2779                 name_len++;     /* trailing null */
2780                 name_len *= 2;
2781         } else {                /* BB improve the check for buffer overruns BB */
2782                 name_len = strnlen(searchName, PATH_MAX);
2783                 name_len++;     /* trailing null */
2784                 strncpy(pSMB->FileName, searchName, name_len);
2785         }
2786
2787         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2788         pSMB->TotalDataCount = 0;
2789         pSMB->MaxParameterCount = cpu_to_le16(2);
2790         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2791         pSMB->MaxSetupCount = 0;
2792         pSMB->Reserved = 0;
2793         pSMB->Flags = 0;
2794         pSMB->Timeout = 0;
2795         pSMB->Reserved2 = 0;
2796         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2797         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2798         pSMB->DataCount = 0;
2799         pSMB->DataOffset = 0;
2800         pSMB->SetupCount = 1;
2801         pSMB->Reserved3 = 0;
2802         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2803         byte_count = params + 1 /* pad */ ;
2804         pSMB->TotalParameterCount = cpu_to_le16(params);
2805         pSMB->ParameterCount = pSMB->TotalParameterCount;
2806         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2807         pSMB->Reserved4 = 0;
2808         pSMB->hdr.smb_buf_length += byte_count;
2809         pSMB->ByteCount = cpu_to_le16(byte_count);
2810
2811         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2812                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2813         if (rc) {
2814                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2815         } else {                /* decode response */
2816                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2817
2818                 if (rc || (pSMBr->ByteCount < 40)) 
2819                         rc = -EIO;      /* bad smb */
2820                 else if (pFindData){
2821                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2822                         memcpy((char *) pFindData,
2823                                (char *) &pSMBr->hdr.Protocol +
2824                                data_offset, sizeof (FILE_ALL_INFO));
2825                 } else
2826                     rc = -ENOMEM;
2827         }
2828         cifs_buf_release(pSMB);
2829         if (rc == -EAGAIN)
2830                 goto QPathInfoRetry;
2831
2832         return rc;
2833 }
2834
2835 int
2836 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2837                      const unsigned char *searchName,
2838                      FILE_UNIX_BASIC_INFO * pFindData,
2839                      const struct nls_table *nls_codepage, int remap)
2840 {
2841 /* SMB_QUERY_FILE_UNIX_BASIC */
2842         TRANSACTION2_QPI_REQ *pSMB = NULL;
2843         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2844         int rc = 0;
2845         int bytes_returned = 0;
2846         int name_len;
2847         __u16 params, byte_count;
2848
2849         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2850 UnixQPathInfoRetry:
2851         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2852                       (void **) &pSMBr);
2853         if (rc)
2854                 return rc;
2855
2856         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2857                 name_len =
2858                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2859                                   PATH_MAX, nls_codepage, remap);
2860                 name_len++;     /* trailing null */
2861                 name_len *= 2;
2862         } else {                /* BB improve the check for buffer overruns BB */
2863                 name_len = strnlen(searchName, PATH_MAX);
2864                 name_len++;     /* trailing null */
2865                 strncpy(pSMB->FileName, searchName, name_len);
2866         }
2867
2868         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2869         pSMB->TotalDataCount = 0;
2870         pSMB->MaxParameterCount = cpu_to_le16(2);
2871         /* BB find exact max SMB PDU from sess structure BB */
2872         pSMB->MaxDataCount = cpu_to_le16(4000); 
2873         pSMB->MaxSetupCount = 0;
2874         pSMB->Reserved = 0;
2875         pSMB->Flags = 0;
2876         pSMB->Timeout = 0;
2877         pSMB->Reserved2 = 0;
2878         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2879         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2880         pSMB->DataCount = 0;
2881         pSMB->DataOffset = 0;
2882         pSMB->SetupCount = 1;
2883         pSMB->Reserved3 = 0;
2884         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2885         byte_count = params + 1 /* pad */ ;
2886         pSMB->TotalParameterCount = cpu_to_le16(params);
2887         pSMB->ParameterCount = pSMB->TotalParameterCount;
2888         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2889         pSMB->Reserved4 = 0;
2890         pSMB->hdr.smb_buf_length += byte_count;
2891         pSMB->ByteCount = cpu_to_le16(byte_count);
2892
2893         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2894                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2895         if (rc) {
2896                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2897         } else {                /* decode response */
2898                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2899
2900                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2901                         rc = -EIO;      /* bad smb */
2902                 } else {
2903                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2904                         memcpy((char *) pFindData,
2905                                (char *) &pSMBr->hdr.Protocol +
2906                                data_offset,
2907                                sizeof (FILE_UNIX_BASIC_INFO));
2908                 }
2909         }
2910         cifs_buf_release(pSMB);
2911         if (rc == -EAGAIN)
2912                 goto UnixQPathInfoRetry;
2913
2914         return rc;
2915 }
2916
2917 #if 0  /* function unused at present */
2918 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2919                const char *searchName, FILE_ALL_INFO * findData,
2920                const struct nls_table *nls_codepage)
2921 {
2922 /* level 257 SMB_ */
2923         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2924         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2925         int rc = 0;
2926         int bytes_returned;
2927         int name_len;
2928         __u16 params, byte_count;
2929
2930         cFYI(1, ("In FindUnique"));
2931 findUniqueRetry:
2932         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2933                       (void **) &pSMBr);
2934         if (rc)
2935                 return rc;
2936
2937         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2938                 name_len =
2939                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2940                                   /* find define for this maxpathcomponent */
2941                                   , nls_codepage);
2942                 name_len++;     /* trailing null */
2943                 name_len *= 2;
2944         } else {                /* BB improve the check for buffer overruns BB */
2945                 name_len = strnlen(searchName, PATH_MAX);
2946                 name_len++;     /* trailing null */
2947                 strncpy(pSMB->FileName, searchName, name_len);
2948         }
2949
2950         params = 12 + name_len /* includes null */ ;
2951         pSMB->TotalDataCount = 0;       /* no EAs */
2952         pSMB->MaxParameterCount = cpu_to_le16(2);
2953         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2954         pSMB->MaxSetupCount = 0;
2955         pSMB->Reserved = 0;
2956         pSMB->Flags = 0;
2957         pSMB->Timeout = 0;
2958         pSMB->Reserved2 = 0;
2959         pSMB->ParameterOffset = cpu_to_le16(
2960          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2961         pSMB->DataCount = 0;
2962         pSMB->DataOffset = 0;
2963         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
2964         pSMB->Reserved3 = 0;
2965         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2966         byte_count = params + 1 /* pad */ ;
2967         pSMB->TotalParameterCount = cpu_to_le16(params);
2968         pSMB->ParameterCount = pSMB->TotalParameterCount;
2969         pSMB->SearchAttributes =
2970             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2971                         ATTR_DIRECTORY);
2972         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
2973         pSMB->SearchFlags = cpu_to_le16(1);
2974         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2975         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
2976         pSMB->hdr.smb_buf_length += byte_count;
2977         pSMB->ByteCount = cpu_to_le16(byte_count);
2978
2979         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2980                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2981
2982         if (rc) {
2983                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2984         } else {                /* decode response */
2985                 cifs_stats_inc(&tcon->num_ffirst);
2986                 /* BB fill in */
2987         }
2988
2989         cifs_buf_release(pSMB);
2990         if (rc == -EAGAIN)
2991                 goto findUniqueRetry;
2992
2993         return rc;
2994 }
2995 #endif /* end unused (temporarily) function */
2996
2997 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2998 int
2999 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3000               const char *searchName, 
3001               const struct nls_table *nls_codepage,
3002               __u16 *   pnetfid,
3003               struct cifs_search_info * psrch_inf, int remap, const char dirsep)
3004 {
3005 /* level 257 SMB_ */
3006         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3007         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3008         T2_FFIRST_RSP_PARMS * parms;
3009         int rc = 0;
3010         int bytes_returned = 0;
3011         int name_len;
3012         __u16 params, byte_count;
3013
3014         cFYI(1, ("In FindFirst for %s",searchName));
3015
3016 findFirstRetry:
3017         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3018                       (void **) &pSMBr);
3019         if (rc)
3020                 return rc;
3021
3022         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3023                 name_len =
3024                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
3025                                  PATH_MAX, nls_codepage, remap);
3026                 /* We can not add the asterik earlier in case
3027                 it got remapped to 0xF03A as if it were part of the
3028                 directory name instead of a wildcard */
3029                 name_len *= 2;
3030                 pSMB->FileName[name_len] = dirsep;
3031                 pSMB->FileName[name_len+1] = 0;
3032                 pSMB->FileName[name_len+2] = '*';
3033                 pSMB->FileName[name_len+3] = 0;
3034                 name_len += 4; /* now the trailing null */
3035                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3036                 pSMB->FileName[name_len+1] = 0;
3037                 name_len += 2;
3038         } else {        /* BB add check for overrun of SMB buf BB */
3039                 name_len = strnlen(searchName, PATH_MAX);
3040 /* BB fix here and in unicode clause above ie
3041                 if(name_len > buffersize-header)
3042                         free buffer exit; BB */
3043                 strncpy(pSMB->FileName, searchName, name_len);
3044                 pSMB->FileName[name_len] = dirsep;
3045                 pSMB->FileName[name_len+1] = '*';
3046                 pSMB->FileName[name_len+2] = 0;
3047                 name_len += 3;
3048         }
3049
3050         params = 12 + name_len /* includes null */ ;
3051         pSMB->TotalDataCount = 0;       /* no EAs */
3052         pSMB->MaxParameterCount = cpu_to_le16(10);
3053         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3054                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3055         pSMB->MaxSetupCount = 0;
3056         pSMB->Reserved = 0;
3057         pSMB->Flags = 0;
3058         pSMB->Timeout = 0;
3059         pSMB->Reserved2 = 0;
3060         byte_count = params + 1 /* pad */ ;
3061         pSMB->TotalParameterCount = cpu_to_le16(params);
3062         pSMB->ParameterCount = pSMB->TotalParameterCount;
3063         pSMB->ParameterOffset = cpu_to_le16(
3064               offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3065                 - 4);
3066         pSMB->DataCount = 0;
3067         pSMB->DataOffset = 0;
3068         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
3069         pSMB->Reserved3 = 0;
3070         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3071         pSMB->SearchAttributes =
3072             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3073                         ATTR_DIRECTORY);
3074         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3075         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
3076                 CIFS_SEARCH_RETURN_RESUME);
3077         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3078
3079         /* BB what should we set StorageType to? Does it matter? BB */
3080         pSMB->SearchStorageType = 0;
3081         pSMB->hdr.smb_buf_length += byte_count;
3082         pSMB->ByteCount = cpu_to_le16(byte_count);
3083
3084         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3085                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3086         cifs_stats_inc(&tcon->num_ffirst);
3087
3088         if (rc) {/* BB add logic to retry regular search if Unix search
3089                         rejected unexpectedly by server */
3090                 /* BB Add code to handle unsupported level rc */
3091                 cFYI(1, ("Error in FindFirst = %d", rc));
3092
3093                 cifs_buf_release(pSMB);
3094
3095                 /* BB eventually could optimize out free and realloc of buf */
3096                 /*    for this case */
3097                 if (rc == -EAGAIN)
3098                         goto findFirstRetry;
3099         } else { /* decode response */
3100                 /* BB remember to free buffer if error BB */
3101                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3102                 if(rc == 0) {
3103                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3104                                 psrch_inf->unicode = TRUE;
3105                         else
3106                                 psrch_inf->unicode = FALSE;
3107
3108                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3109                         psrch_inf->smallBuf = 0;
3110                         psrch_inf->srch_entries_start = 
3111                                 (char *) &pSMBr->hdr.Protocol + 
3112                                         le16_to_cpu(pSMBr->t2.DataOffset);
3113                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3114                                le16_to_cpu(pSMBr->t2.ParameterOffset));
3115
3116                         if(parms->EndofSearch)
3117                                 psrch_inf->endOfSearch = TRUE;
3118                         else
3119                                 psrch_inf->endOfSearch = FALSE;
3120
3121                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3122                         psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3123                                 psrch_inf->entries_in_buffer;
3124                         *pnetfid = parms->SearchHandle;
3125                 } else {
3126                         cifs_buf_release(pSMB);
3127                 }
3128         }
3129
3130         return rc;
3131 }
3132
3133 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3134             __u16 searchHandle, struct cifs_search_info * psrch_inf)
3135 {
3136         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3137         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3138         T2_FNEXT_RSP_PARMS * parms;
3139         char *response_data;
3140         int rc = 0;
3141         int bytes_returned, name_len;
3142         __u16 params, byte_count;
3143
3144         cFYI(1, ("In FindNext"));
3145
3146         if(psrch_inf->endOfSearch == TRUE)
3147                 return -ENOENT;
3148
3149         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3150                 (void **) &pSMBr);
3151         if (rc)
3152                 return rc;
3153
3154         params = 14;    /* includes 2 bytes of null string, converted to LE below */
3155         byte_count = 0;
3156         pSMB->TotalDataCount = 0;       /* no EAs */
3157         pSMB->MaxParameterCount = cpu_to_le16(8);
3158         pSMB->MaxDataCount =
3159             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3160         pSMB->MaxSetupCount = 0;
3161         pSMB->Reserved = 0;
3162         pSMB->Flags = 0;
3163         pSMB->Timeout = 0;
3164         pSMB->Reserved2 = 0;
3165         pSMB->ParameterOffset =  cpu_to_le16(
3166               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3167         pSMB->DataCount = 0;
3168         pSMB->DataOffset = 0;
3169         pSMB->SetupCount = 1;
3170         pSMB->Reserved3 = 0;
3171         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3172         pSMB->SearchHandle = searchHandle;      /* always kept as le */
3173         pSMB->SearchCount =
3174                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3175         /* test for Unix extensions */
3176 /*      if (tcon->ses->capabilities & CAP_UNIX) {
3177                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3178                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3179         } else {
3180                 pSMB->InformationLevel =
3181                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3182                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3183         } */
3184         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3185         pSMB->ResumeKey = psrch_inf->resume_key;
3186         pSMB->SearchFlags =
3187               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3188
3189         name_len = psrch_inf->resume_name_len;
3190         params += name_len;
3191         if(name_len < PATH_MAX) {
3192                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3193                 byte_count += name_len;
3194                 /* 14 byte parm len above enough for 2 byte null terminator */
3195                 pSMB->ResumeFileName[name_len] = 0;
3196                 pSMB->ResumeFileName[name_len+1] = 0;
3197         } else {
3198                 rc = -EINVAL;
3199                 goto FNext2_err_exit;
3200         }
3201         byte_count = params + 1 /* pad */ ;
3202         pSMB->TotalParameterCount = cpu_to_le16(params);
3203         pSMB->ParameterCount = pSMB->TotalParameterCount;
3204         pSMB->hdr.smb_buf_length += byte_count;
3205         pSMB->ByteCount = cpu_to_le16(byte_count);
3206                                                                                               
3207         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3208                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3209         cifs_stats_inc(&tcon->num_fnext);
3210         if (rc) {
3211                 if (rc == -EBADF) {
3212                         psrch_inf->endOfSearch = TRUE;
3213                         rc = 0; /* search probably was closed at end of search above */
3214                 } else
3215                         cFYI(1, ("FindNext returned = %d", rc));
3216         } else {                /* decode response */
3217                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3218                 
3219                 if(rc == 0) {
3220                         /* BB fixme add lock for file (srch_info) struct here */
3221                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3222                                 psrch_inf->unicode = TRUE;
3223                         else
3224                                 psrch_inf->unicode = FALSE;
3225                         response_data = (char *) &pSMBr->hdr.Protocol +
3226                                le16_to_cpu(pSMBr->t2.ParameterOffset);
3227                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
3228                         response_data = (char *)&pSMBr->hdr.Protocol +
3229                                 le16_to_cpu(pSMBr->t2.DataOffset);
3230                         if(psrch_inf->smallBuf)
3231                                 cifs_small_buf_release(
3232                                         psrch_inf->ntwrk_buf_start);
3233                         else
3234                                 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3235                         psrch_inf->srch_entries_start = response_data;
3236                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
3237                         psrch_inf->smallBuf = 0;
3238                         if(parms->EndofSearch)
3239                                 psrch_inf->endOfSearch = TRUE;
3240                         else
3241                                 psrch_inf->endOfSearch = FALSE;
3242                                                                                               
3243                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3244                         psrch_inf->index_of_last_entry +=
3245                                 psrch_inf->entries_in_buffer;
3246 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3247
3248                         /* BB fixme add unlock here */
3249                 }
3250
3251         }
3252
3253         /* BB On error, should we leave previous search buf (and count and
3254         last entry fields) intact or free the previous one? */
3255
3256         /* Note: On -EAGAIN error only caller can retry on handle based calls
3257         since file handle passed in no longer valid */
3258 FNext2_err_exit:
3259         if (rc != 0)
3260                 cifs_buf_release(pSMB);
3261                                                                                               
3262         return rc;
3263 }
3264
3265 int
3266 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3267 {
3268         int rc = 0;
3269         FINDCLOSE_REQ *pSMB = NULL;
3270         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3271         int bytes_returned;
3272
3273         cFYI(1, ("In CIFSSMBFindClose"));
3274         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3275
3276         /* no sense returning error if session restarted
3277                 as file handle has been closed */
3278         if(rc == -EAGAIN)
3279                 return 0;
3280         if (rc)
3281                 return rc;
3282
3283         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
3284         pSMB->FileID = searchHandle;
3285         pSMB->ByteCount = 0;
3286         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3287                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3288         if (rc) {
3289                 cERROR(1, ("Send error in FindClose = %d", rc));
3290         }
3291         cifs_stats_inc(&tcon->num_fclose);
3292         cifs_small_buf_release(pSMB);
3293
3294         /* Since session is dead, search handle closed on server already */
3295         if (rc == -EAGAIN)
3296                 rc = 0;
3297
3298         return rc;
3299 }
3300
3301 int
3302 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3303                 const unsigned char *searchName,
3304                 __u64 * inode_number,
3305                 const struct nls_table *nls_codepage, int remap)
3306 {
3307         int rc = 0;
3308         TRANSACTION2_QPI_REQ *pSMB = NULL;
3309         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3310         int name_len, bytes_returned;
3311         __u16 params, byte_count;
3312
3313         cFYI(1,("In GetSrvInodeNum for %s",searchName));
3314         if(tcon == NULL)
3315                 return -ENODEV; 
3316
3317 GetInodeNumberRetry:
3318         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3319                       (void **) &pSMBr);
3320         if (rc)
3321                 return rc;
3322
3323
3324         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3325                 name_len =
3326                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3327                                 PATH_MAX,nls_codepage, remap);
3328                 name_len++;     /* trailing null */
3329                 name_len *= 2;
3330         } else {                /* BB improve the check for buffer overruns BB */
3331                 name_len = strnlen(searchName, PATH_MAX);
3332                 name_len++;     /* trailing null */
3333                 strncpy(pSMB->FileName, searchName, name_len);
3334         }
3335
3336         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
3337         pSMB->TotalDataCount = 0;
3338         pSMB->MaxParameterCount = cpu_to_le16(2);
3339         /* BB find exact max data count below from sess structure BB */
3340         pSMB->MaxDataCount = cpu_to_le16(4000);
3341         pSMB->MaxSetupCount = 0;
3342         pSMB->Reserved = 0;
3343         pSMB->Flags = 0;
3344         pSMB->Timeout = 0;
3345         pSMB->Reserved2 = 0;
3346         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3347                 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3348         pSMB->DataCount = 0;
3349         pSMB->DataOffset = 0;
3350         pSMB->SetupCount = 1;
3351         pSMB->Reserved3 = 0;
3352         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3353         byte_count = params + 1 /* pad */ ;
3354         pSMB->TotalParameterCount = cpu_to_le16(params);
3355         pSMB->ParameterCount = pSMB->TotalParameterCount;
3356         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3357         pSMB->Reserved4 = 0;
3358         pSMB->hdr.smb_buf_length += byte_count;
3359         pSMB->ByteCount = cpu_to_le16(byte_count);
3360
3361         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3362                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3363         if (rc) {
3364                 cFYI(1, ("error %d in QueryInternalInfo", rc));
3365         } else {
3366                 /* decode response */
3367                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3368                 if (rc || (pSMBr->ByteCount < 2))
3369                 /* BB also check enough total bytes returned */
3370                         /* If rc should we check for EOPNOSUPP and
3371                         disable the srvino flag? or in caller? */
3372                         rc = -EIO;      /* bad smb */
3373                 else {
3374                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3375                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3376                         struct file_internal_info * pfinfo;
3377                         /* BB Do we need a cast or hash here ? */
3378                         if(count < 8) {
3379                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3380                                 rc = -EIO;
3381                                 goto GetInodeNumOut;
3382                         }
3383                         pfinfo = (struct file_internal_info *)
3384                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3385                         *inode_number = pfinfo->UniqueId;
3386                 }
3387         }
3388 GetInodeNumOut:
3389         cifs_buf_release(pSMB);
3390         if (rc == -EAGAIN)
3391                 goto GetInodeNumberRetry;
3392         return rc;
3393 }
3394
3395 int
3396 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3397                 const unsigned char *searchName,
3398                 unsigned char **targetUNCs,
3399                 unsigned int *number_of_UNC_in_array,
3400                 const struct nls_table *nls_codepage, int remap)
3401 {
3402 /* TRANS2_GET_DFS_REFERRAL */
3403         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3404         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3405         struct dfs_referral_level_3 * referrals = NULL;
3406         int rc = 0;
3407         int bytes_returned;
3408         int name_len;
3409         unsigned int i;
3410         char * temp;
3411         __u16 params, byte_count;
3412         *number_of_UNC_in_array = 0;
3413         *targetUNCs = NULL;
3414
3415         cFYI(1, ("In GetDFSRefer the path %s", searchName));
3416         if (ses == NULL)
3417                 return -ENODEV;
3418 getDFSRetry:
3419         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3420                       (void **) &pSMBr);
3421         if (rc)
3422                 return rc;
3423         
3424         /* server pointer checked in called function, 
3425         but should never be null here anyway */
3426         pSMB->hdr.Mid = GetNextMid(ses->server);
3427         pSMB->hdr.Tid = ses->ipc_tid;
3428         pSMB->hdr.Uid = ses->Suid;
3429         if (ses->capabilities & CAP_STATUS32) {
3430                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3431         }
3432         if (ses->capabilities & CAP_DFS) {
3433                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3434         }
3435
3436         if (ses->capabilities & CAP_UNICODE) {
3437                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3438                 name_len =
3439                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3440                                      searchName, PATH_MAX, nls_codepage, remap);
3441                 name_len++;     /* trailing null */
3442                 name_len *= 2;
3443         } else {                /* BB improve the check for buffer overruns BB */
3444                 name_len = strnlen(searchName, PATH_MAX);
3445                 name_len++;     /* trailing null */
3446                 strncpy(pSMB->RequestFileName, searchName, name_len);
3447         }
3448
3449         params = 2 /* level */  + name_len /*includes null */ ;
3450         pSMB->TotalDataCount = 0;
3451         pSMB->DataCount = 0;
3452         pSMB->DataOffset = 0;
3453         pSMB->MaxParameterCount = 0;
3454         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3455         pSMB->MaxSetupCount = 0;
3456         pSMB->Reserved = 0;
3457         pSMB->Flags = 0;
3458         pSMB->Timeout = 0;
3459         pSMB->Reserved2 = 0;
3460         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3461         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3462         pSMB->SetupCount = 1;
3463         pSMB->Reserved3 = 0;
3464         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3465         byte_count = params + 3 /* pad */ ;
3466         pSMB->ParameterCount = cpu_to_le16(params);
3467         pSMB->TotalParameterCount = pSMB->ParameterCount;
3468         pSMB->MaxReferralLevel = cpu_to_le16(3);
3469         pSMB->hdr.smb_buf_length += byte_count;
3470         pSMB->ByteCount = cpu_to_le16(byte_count);
3471
3472         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3473                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3474         if (rc) {
3475                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3476         } else {                /* decode response */
3477 /* BB Add logic to parse referrals here */
3478                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3479
3480                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
3481                         rc = -EIO;      /* bad smb */
3482                 else {
3483                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
3484                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3485
3486                         cFYI(1,
3487                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
3488                               pSMBr->ByteCount, data_offset));
3489                         referrals = 
3490                             (struct dfs_referral_level_3 *) 
3491                                         (8 /* sizeof start of data block */ +
3492                                         data_offset +
3493                                         (char *) &pSMBr->hdr.Protocol); 
3494                         cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",
3495                                 le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive)));
3496                         /* BB This field is actually two bytes in from start of
3497                            data block so we could do safety check that DataBlock
3498                            begins at address of pSMBr->NumberOfReferrals */
3499                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3500
3501                         /* BB Fix below so can return more than one referral */
3502                         if(*number_of_UNC_in_array > 1)
3503                                 *number_of_UNC_in_array = 1;
3504
3505                         /* get the length of the strings describing refs */
3506                         name_len = 0;
3507                         for(i=0;i<*number_of_UNC_in_array;i++) {
3508                                 /* make sure that DfsPathOffset not past end */
3509                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3510                                 if (offset > data_count) {
3511                                         /* if invalid referral, stop here and do 
3512                                         not try to copy any more */
3513                                         *number_of_UNC_in_array = i;
3514                                         break;
3515                                 } 
3516                                 temp = ((char *)referrals) + offset;
3517
3518                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3519                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
3520                                 } else {
3521                                         name_len += strnlen(temp,data_count);
3522                                 }
3523                                 referrals++;
3524                                 /* BB add check that referral pointer does not fall off end PDU */
3525                                 
3526                         }
3527                         /* BB add check for name_len bigger than bcc */
3528                         *targetUNCs = 
3529                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3530                         if(*targetUNCs == NULL) {
3531                                 rc = -ENOMEM;
3532                                 goto GetDFSRefExit;
3533                         }
3534                         /* copy the ref strings */
3535                         referrals =  
3536                             (struct dfs_referral_level_3 *) 
3537                                         (8 /* sizeof data hdr */ +
3538                                         data_offset + 
3539                                         (char *) &pSMBr->hdr.Protocol);
3540
3541                         for(i=0;i<*number_of_UNC_in_array;i++) {
3542                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3543                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3544                                         cifs_strfromUCS_le(*targetUNCs,
3545                                                 (__le16 *) temp, name_len, nls_codepage);
3546                                 } else {
3547                                         strncpy(*targetUNCs,temp,name_len);
3548                                 }
3549                                 /*  BB update target_uncs pointers */
3550                                 referrals++;
3551                         }
3552                         temp = *targetUNCs;
3553                         temp[name_len] = 0;
3554                 }
3555
3556         }
3557 GetDFSRefExit:
3558         if (pSMB)
3559                 cifs_buf_release(pSMB);
3560
3561         if (rc == -EAGAIN)
3562                 goto getDFSRetry;
3563
3564         return rc;
3565 }
3566
3567 /* Query File System Info such as free space to old servers such as Win 9x */
3568 int
3569 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3570 {
3571 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3572         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3573         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3574         FILE_SYSTEM_ALLOC_INFO *response_data;
3575         int rc = 0;
3576         int bytes_returned = 0;
3577         __u16 params, byte_count;
3578
3579         cFYI(1, ("OldQFSInfo"));
3580 oldQFSInfoRetry:
3581         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3582                 (void **) &pSMBr);
3583         if (rc)
3584                 return rc;
3585         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3586                       (void **) &pSMBr);
3587         if (rc)
3588                 return rc;
3589
3590         params = 2;     /* level */
3591         pSMB->TotalDataCount = 0;
3592         pSMB->MaxParameterCount = cpu_to_le16(2);
3593         pSMB->MaxDataCount = cpu_to_le16(1000);
3594         pSMB->MaxSetupCount = 0;
3595         pSMB->Reserved = 0;
3596         pSMB->Flags = 0;
3597         pSMB->Timeout = 0;
3598         pSMB->Reserved2 = 0;
3599         byte_count = params + 1 /* pad */ ;
3600         pSMB->TotalParameterCount = cpu_to_le16(params);
3601         pSMB->ParameterCount = pSMB->TotalParameterCount;
3602         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3603         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3604         pSMB->DataCount = 0;
3605         pSMB->DataOffset = 0;
3606         pSMB->SetupCount = 1;
3607         pSMB->Reserved3 = 0;
3608         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3609         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3610         pSMB->hdr.smb_buf_length += byte_count;
3611         pSMB->ByteCount = cpu_to_le16(byte_count);
3612
3613         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3614                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3615         if (rc) {
3616                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3617         } else {                /* decode response */
3618                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3619
3620                 if (rc || (pSMBr->ByteCount < 18))
3621                         rc = -EIO;      /* bad smb */
3622                 else {
3623                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3624                         cFYI(1,("qfsinf resp BCC: %d  Offset %d",
3625                                  pSMBr->ByteCount, data_offset));
3626
3627                         response_data =
3628                                 (FILE_SYSTEM_ALLOC_INFO *) 
3629                                 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3630                         FSData->f_bsize =
3631                                 le16_to_cpu(response_data->BytesPerSector) *
3632                                 le32_to_cpu(response_data->
3633                                         SectorsPerAllocationUnit);
3634                         FSData->f_blocks =
3635                                 le32_to_cpu(response_data->TotalAllocationUnits);
3636                         FSData->f_bfree = FSData->f_bavail =
3637                                 le32_to_cpu(response_data->FreeAllocationUnits);
3638                         cFYI(1,
3639                              ("Blocks: %lld  Free: %lld Block size %ld",
3640                               (unsigned long long)FSData->f_blocks,
3641                               (unsigned long long)FSData->f_bfree,
3642                               FSData->f_bsize));
3643                 }
3644         }
3645         cifs_buf_release(pSMB);
3646
3647         if (rc == -EAGAIN)
3648                 goto oldQFSInfoRetry;
3649
3650         return rc;
3651 }
3652
3653 int
3654 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3655 {
3656 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3657         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3658         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3659         FILE_SYSTEM_INFO *response_data;
3660         int rc = 0;
3661         int bytes_returned = 0;
3662         __u16 params, byte_count;
3663
3664         cFYI(1, ("In QFSInfo"));
3665 QFSInfoRetry:
3666         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3667                       (void **) &pSMBr);
3668         if (rc)
3669                 return rc;
3670
3671         params = 2;     /* level */
3672         pSMB->TotalDataCount = 0;
3673         pSMB->MaxParameterCount = cpu_to_le16(2);
3674         pSMB->MaxDataCount = cpu_to_le16(1000);
3675         pSMB->MaxSetupCount = 0;
3676         pSMB->Reserved = 0;
3677         pSMB->Flags = 0;
3678         pSMB->Timeout = 0;
3679         pSMB->Reserved2 = 0;
3680         byte_count = params + 1 /* pad */ ;
3681         pSMB->TotalParameterCount = cpu_to_le16(params);
3682         pSMB->ParameterCount = pSMB->TotalParameterCount;
3683         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3684         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3685         pSMB->DataCount = 0;
3686         pSMB->DataOffset = 0;
3687         pSMB->SetupCount = 1;
3688         pSMB->Reserved3 = 0;
3689         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3690         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3691         pSMB->hdr.smb_buf_length += byte_count;
3692         pSMB->ByteCount = cpu_to_le16(byte_count);
3693
3694         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3695                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3696         if (rc) {
3697                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3698         } else {                /* decode response */
3699                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3700
3701                 if (rc || (pSMBr->ByteCount < 24))
3702                         rc = -EIO;      /* bad smb */
3703                 else {
3704                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3705
3706                         response_data =
3707                             (FILE_SYSTEM_INFO
3708                              *) (((char *) &pSMBr->hdr.Protocol) +
3709                                  data_offset);
3710                         FSData->f_bsize =
3711                             le32_to_cpu(response_data->BytesPerSector) *
3712                             le32_to_cpu(response_data->
3713                                         SectorsPerAllocationUnit);
3714                         FSData->f_blocks =
3715                             le64_to_cpu(response_data->TotalAllocationUnits);
3716                         FSData->f_bfree = FSData->f_bavail =
3717                             le64_to_cpu(response_data->FreeAllocationUnits);
3718                         cFYI(1,
3719                              ("Blocks: %lld  Free: %lld Block size %ld",
3720                               (unsigned long long)FSData->f_blocks,
3721                               (unsigned long long)FSData->f_bfree,
3722                               FSData->f_bsize));
3723                 }
3724         }
3725         cifs_buf_release(pSMB);
3726
3727         if (rc == -EAGAIN)
3728                 goto QFSInfoRetry;
3729
3730         return rc;
3731 }
3732
3733 int
3734 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3735 {
3736 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3737         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3738         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3739         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3740         int rc = 0;
3741         int bytes_returned = 0;
3742         __u16 params, byte_count;
3743
3744         cFYI(1, ("In QFSAttributeInfo"));
3745 QFSAttributeRetry:
3746         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3747                       (void **) &pSMBr);
3748         if (rc)
3749                 return rc;
3750
3751         params = 2;     /* level */
3752         pSMB->TotalDataCount = 0;
3753         pSMB->MaxParameterCount = cpu_to_le16(2);
3754         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3755         pSMB->MaxSetupCount = 0;
3756         pSMB->Reserved = 0;
3757         pSMB->Flags = 0;
3758         pSMB->Timeout = 0;
3759         pSMB->Reserved2 = 0;
3760         byte_count = params + 1 /* pad */ ;
3761         pSMB->TotalParameterCount = cpu_to_le16(params);
3762         pSMB->ParameterCount = pSMB->TotalParameterCount;
3763         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3764         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3765         pSMB->DataCount = 0;
3766         pSMB->DataOffset = 0;
3767         pSMB->SetupCount = 1;
3768         pSMB->Reserved3 = 0;
3769         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3770         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3771         pSMB->hdr.smb_buf_length += byte_count;
3772         pSMB->ByteCount = cpu_to_le16(byte_count);
3773
3774         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3775                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3776         if (rc) {
3777                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3778         } else {                /* decode response */
3779                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3780
3781                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3782                         rc = -EIO;      /* bad smb */
3783                 } else {
3784                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3785                         response_data =
3786                             (FILE_SYSTEM_ATTRIBUTE_INFO
3787                              *) (((char *) &pSMBr->hdr.Protocol) +
3788                                  data_offset);
3789                         memcpy(&tcon->fsAttrInfo, response_data,
3790                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3791                 }
3792         }
3793         cifs_buf_release(pSMB);
3794
3795         if (rc == -EAGAIN)
3796                 goto QFSAttributeRetry;
3797
3798         return rc;
3799 }
3800
3801 int
3802 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3803 {
3804 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3805         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3806         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3807         FILE_SYSTEM_DEVICE_INFO *response_data;
3808         int rc = 0;
3809         int bytes_returned = 0;
3810         __u16 params, byte_count;
3811
3812         cFYI(1, ("In QFSDeviceInfo"));
3813 QFSDeviceRetry:
3814         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3815                       (void **) &pSMBr);
3816         if (rc)
3817                 return rc;
3818
3819         params = 2;     /* level */
3820         pSMB->TotalDataCount = 0;
3821         pSMB->MaxParameterCount = cpu_to_le16(2);
3822         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3823         pSMB->MaxSetupCount = 0;
3824         pSMB->Reserved = 0;
3825         pSMB->Flags = 0;
3826         pSMB->Timeout = 0;
3827         pSMB->Reserved2 = 0;
3828         byte_count = params + 1 /* pad */ ;
3829         pSMB->TotalParameterCount = cpu_to_le16(params);
3830         pSMB->ParameterCount = pSMB->TotalParameterCount;
3831         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3832         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3833
3834         pSMB->DataCount = 0;
3835         pSMB->DataOffset = 0;
3836         pSMB->SetupCount = 1;
3837         pSMB->Reserved3 = 0;
3838         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3839         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3840         pSMB->hdr.smb_buf_length += byte_count;
3841         pSMB->ByteCount = cpu_to_le16(byte_count);
3842
3843         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3844                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3845         if (rc) {
3846                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3847         } else {                /* decode response */
3848                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3849
3850                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3851                         rc = -EIO;      /* bad smb */
3852                 else {
3853                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3854                         response_data =
3855                             (FILE_SYSTEM_DEVICE_INFO *)
3856                                 (((char *) &pSMBr->hdr.Protocol) +
3857                                  data_offset);
3858                         memcpy(&tcon->fsDevInfo, response_data,
3859                                sizeof (FILE_SYSTEM_DEVICE_INFO));
3860                 }
3861         }
3862         cifs_buf_release(pSMB);
3863
3864         if (rc == -EAGAIN)
3865                 goto QFSDeviceRetry;
3866
3867         return rc;
3868 }
3869
3870 int
3871 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3872 {
3873 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
3874         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3875         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3876         FILE_SYSTEM_UNIX_INFO *response_data;
3877         int rc = 0;
3878         int bytes_returned = 0;
3879         __u16 params, byte_count;
3880
3881         cFYI(1, ("In QFSUnixInfo"));
3882 QFSUnixRetry:
3883         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3884                       (void **) &pSMBr);
3885         if (rc)
3886                 return rc;
3887
3888         params = 2;     /* level */
3889         pSMB->TotalDataCount = 0;
3890         pSMB->DataCount = 0;
3891         pSMB->DataOffset = 0;
3892         pSMB->MaxParameterCount = cpu_to_le16(2);
3893         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3894         pSMB->MaxSetupCount = 0;
3895         pSMB->Reserved = 0;
3896         pSMB->Flags = 0;
3897         pSMB->Timeout = 0;
3898         pSMB->Reserved2 = 0;
3899         byte_count = params + 1 /* pad */ ;
3900         pSMB->ParameterCount = cpu_to_le16(params);
3901         pSMB->TotalParameterCount = pSMB->ParameterCount;
3902         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3903         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3904         pSMB->SetupCount = 1;
3905         pSMB->Reserved3 = 0;
3906         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3907         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3908         pSMB->hdr.smb_buf_length += byte_count;
3909         pSMB->ByteCount = cpu_to_le16(byte_count);
3910
3911         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3912                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3913         if (rc) {
3914                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3915         } else {                /* decode response */
3916                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3917
3918                 if (rc || (pSMBr->ByteCount < 13)) {
3919                         rc = -EIO;      /* bad smb */
3920                 } else {
3921                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3922                         response_data =
3923                             (FILE_SYSTEM_UNIX_INFO
3924                              *) (((char *) &pSMBr->hdr.Protocol) +
3925                                  data_offset);
3926                         memcpy(&tcon->fsUnixInfo, response_data,
3927                                sizeof (FILE_SYSTEM_UNIX_INFO));
3928                 }
3929         }
3930         cifs_buf_release(pSMB);
3931
3932         if (rc == -EAGAIN)
3933                 goto QFSUnixRetry;
3934
3935
3936         return rc;
3937 }
3938
3939 int
3940 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3941 {
3942 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
3943         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3944         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3945         int rc = 0;
3946         int bytes_returned = 0;
3947         __u16 params, param_offset, offset, byte_count;
3948
3949         cFYI(1, ("In SETFSUnixInfo"));
3950 SETFSUnixRetry:
3951         /* BB switch to small buf init to save memory */
3952         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3953                       (void **) &pSMBr);
3954         if (rc)
3955                 return rc;
3956
3957         params = 4;     /* 2 bytes zero followed by info level. */
3958         pSMB->MaxSetupCount = 0;
3959         pSMB->Reserved = 0;
3960         pSMB->Flags = 0;
3961         pSMB->Timeout = 0;
3962         pSMB->Reserved2 = 0;
3963         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3964         offset = param_offset + params;
3965
3966         pSMB->MaxParameterCount = cpu_to_le16(4);
3967         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3968         pSMB->SetupCount = 1;
3969         pSMB->Reserved3 = 0;
3970         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3971         byte_count = 1 /* pad */ + params + 12;
3972
3973         pSMB->DataCount = cpu_to_le16(12);
3974         pSMB->ParameterCount = cpu_to_le16(params);
3975         pSMB->TotalDataCount = pSMB->DataCount;
3976         pSMB->TotalParameterCount = pSMB->ParameterCount;
3977         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3978         pSMB->DataOffset = cpu_to_le16(offset);
3979
3980         /* Params. */
3981         pSMB->FileNum = 0;
3982         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3983
3984         /* Data. */
3985         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3986         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3987         pSMB->ClientUnixCap = cpu_to_le64(cap);
3988
3989         pSMB->hdr.smb_buf_length += byte_count;
3990         pSMB->ByteCount = cpu_to_le16(byte_count);
3991
3992         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3993                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3994         if (rc) {
3995                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3996         } else {                /* decode response */
3997                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3998                 if (rc) {
3999                         rc = -EIO;      /* bad smb */
4000                 }
4001         }
4002         cifs_buf_release(pSMB);
4003
4004         if (rc == -EAGAIN)
4005                 goto SETFSUnixRetry;
4006
4007         return rc;
4008 }
4009
4010
4011
4012 int
4013 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4014                    struct kstatfs *FSData)
4015 {
4016 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
4017         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4018         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4019         FILE_SYSTEM_POSIX_INFO *response_data;
4020         int rc = 0;
4021         int bytes_returned = 0;
4022         __u16 params, byte_count;
4023
4024         cFYI(1, ("In QFSPosixInfo"));
4025 QFSPosixRetry:
4026         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4027                       (void **) &pSMBr);
4028         if (rc)
4029                 return rc;
4030
4031         params = 2;     /* level */
4032         pSMB->TotalDataCount = 0;
4033         pSMB->DataCount = 0;
4034         pSMB->DataOffset = 0;
4035         pSMB->MaxParameterCount = cpu_to_le16(2);
4036         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4037         pSMB->MaxSetupCount = 0;
4038         pSMB->Reserved = 0;
4039         pSMB->Flags = 0;
4040         pSMB->Timeout = 0;
4041         pSMB->Reserved2 = 0;
4042         byte_count = params + 1 /* pad */ ;
4043         pSMB->ParameterCount = cpu_to_le16(params);
4044         pSMB->TotalParameterCount = pSMB->ParameterCount;
4045         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
4046         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4047         pSMB->SetupCount = 1;
4048         pSMB->Reserved3 = 0;
4049         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4050         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4051         pSMB->hdr.smb_buf_length += byte_count;
4052         pSMB->ByteCount = cpu_to_le16(byte_count);
4053
4054         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4055                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4056         if (rc) {
4057                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4058         } else {                /* decode response */
4059                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4060
4061                 if (rc || (pSMBr->ByteCount < 13)) {
4062                         rc = -EIO;      /* bad smb */
4063                 } else {
4064                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4065                         response_data =
4066                             (FILE_SYSTEM_POSIX_INFO
4067                              *) (((char *) &pSMBr->hdr.Protocol) +
4068                                  data_offset);
4069                         FSData->f_bsize =
4070                                         le32_to_cpu(response_data->BlockSize);
4071                         FSData->f_blocks =
4072                                         le64_to_cpu(response_data->TotalBlocks);
4073                         FSData->f_bfree =
4074                             le64_to_cpu(response_data->BlocksAvail);
4075                         if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4076                                 FSData->f_bavail = FSData->f_bfree;
4077                         } else {
4078                                 FSData->f_bavail =
4079                                         le64_to_cpu(response_data->UserBlocksAvail);
4080                         }
4081                         if(response_data->TotalFileNodes != cpu_to_le64(-1))
4082                                 FSData->f_files =
4083                                         le64_to_cpu(response_data->TotalFileNodes);
4084                         if(response_data->FreeFileNodes != cpu_to_le64(-1))
4085                                 FSData->f_ffree =
4086                                         le64_to_cpu(response_data->FreeFileNodes);
4087                 }
4088         }
4089         cifs_buf_release(pSMB);
4090
4091         if (rc == -EAGAIN)
4092                 goto QFSPosixRetry;
4093
4094         return rc;
4095 }
4096
4097
4098 /* We can not use write of zero bytes trick to 
4099    set file size due to need for large file support.  Also note that 
4100    this SetPathInfo is preferred to SetFileInfo based method in next 
4101    routine which is only needed to work around a sharing violation bug
4102    in Samba which this routine can run into */
4103
4104 int
4105 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4106               __u64 size, int SetAllocation, 
4107               const struct nls_table *nls_codepage, int remap)
4108 {
4109         struct smb_com_transaction2_spi_req *pSMB = NULL;
4110         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4111         struct file_end_of_file_info *parm_data;
4112         int name_len;
4113         int rc = 0;
4114         int bytes_returned = 0;
4115         __u16 params, byte_count, data_count, param_offset, offset;
4116
4117         cFYI(1, ("In SetEOF"));
4118 SetEOFRetry:
4119         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4120                       (void **) &pSMBr);
4121         if (rc)
4122                 return rc;
4123
4124         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4125                 name_len =
4126                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4127                                      PATH_MAX, nls_codepage, remap);
4128                 name_len++;     /* trailing null */
4129                 name_len *= 2;
4130         } else {        /* BB improve the check for buffer overruns BB */
4131                 name_len = strnlen(fileName, PATH_MAX);
4132                 name_len++;     /* trailing null */
4133                 strncpy(pSMB->FileName, fileName, name_len);
4134         }
4135         params = 6 + name_len;
4136         data_count = sizeof (struct file_end_of_file_info);
4137         pSMB->MaxParameterCount = cpu_to_le16(2);
4138         pSMB->MaxDataCount = cpu_to_le16(4100);
4139         pSMB->MaxSetupCount = 0;
4140         pSMB->Reserved = 0;
4141         pSMB->Flags = 0;
4142         pSMB->Timeout = 0;
4143         pSMB->Reserved2 = 0;
4144         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4145                                      InformationLevel) - 4;
4146         offset = param_offset + params;
4147         if(SetAllocation) {
4148                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4149                     pSMB->InformationLevel =
4150                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4151                 else
4152                     pSMB->InformationLevel =
4153                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4154         } else /* Set File Size */  {    
4155             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4156                     pSMB->InformationLevel =
4157                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4158             else
4159                     pSMB->InformationLevel =
4160                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4161         }
4162
4163         parm_data =
4164             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4165                                        offset);
4166         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4167         pSMB->DataOffset = cpu_to_le16(offset);
4168         pSMB->SetupCount = 1;
4169         pSMB->Reserved3 = 0;
4170         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4171         byte_count = 3 /* pad */  + params + data_count;
4172         pSMB->DataCount = cpu_to_le16(data_count);
4173         pSMB->TotalDataCount = pSMB->DataCount;
4174         pSMB->ParameterCount = cpu_to_le16(params);
4175         pSMB->TotalParameterCount = pSMB->ParameterCount;
4176         pSMB->Reserved4 = 0;
4177         pSMB->hdr.smb_buf_length += byte_count;
4178         parm_data->FileSize = cpu_to_le64(size);
4179         pSMB->ByteCount = cpu_to_le16(byte_count);
4180         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4181                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4182         if (rc) {
4183                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4184         }
4185
4186         cifs_buf_release(pSMB);
4187
4188         if (rc == -EAGAIN)
4189                 goto SetEOFRetry;
4190
4191         return rc;
4192 }
4193
4194 int
4195 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
4196                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
4197 {
4198         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4199         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4200         char *data_offset;
4201         struct file_end_of_file_info *parm_data;
4202         int rc = 0;
4203         int bytes_returned = 0;
4204         __u16 params, param_offset, offset, byte_count, count;
4205
4206         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4207                         (long long)size));
4208         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4209
4210         if (rc)
4211                 return rc;
4212
4213         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4214
4215         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4216         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4217     
4218         params = 6;
4219         pSMB->MaxSetupCount = 0;
4220         pSMB->Reserved = 0;
4221         pSMB->Flags = 0;
4222         pSMB->Timeout = 0;
4223         pSMB->Reserved2 = 0;
4224         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4225         offset = param_offset + params;
4226
4227         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
4228
4229         count = sizeof(struct file_end_of_file_info);
4230         pSMB->MaxParameterCount = cpu_to_le16(2);
4231         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4232         pSMB->SetupCount = 1;
4233         pSMB->Reserved3 = 0;
4234         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4235         byte_count = 3 /* pad */  + params + count;
4236         pSMB->DataCount = cpu_to_le16(count);
4237         pSMB->ParameterCount = cpu_to_le16(params);
4238         pSMB->TotalDataCount = pSMB->DataCount;
4239         pSMB->TotalParameterCount = pSMB->ParameterCount;
4240         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4241         parm_data =
4242                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4243                         offset);
4244         pSMB->DataOffset = cpu_to_le16(offset);
4245         parm_data->FileSize = cpu_to_le64(size);
4246         pSMB->Fid = fid;
4247         if(SetAllocation) {
4248                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4249                         pSMB->InformationLevel =
4250                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4251                 else
4252                         pSMB->InformationLevel =
4253                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4254         } else /* Set File Size */  {    
4255             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4256                     pSMB->InformationLevel =
4257                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4258             else
4259                     pSMB->InformationLevel =
4260                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4261         }
4262         pSMB->Reserved4 = 0;
4263         pSMB->hdr.smb_buf_length += byte_count;
4264         pSMB->ByteCount = cpu_to_le16(byte_count);
4265         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4266                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4267         if (rc) {
4268                 cFYI(1,
4269                      ("Send error in SetFileInfo (SetFileSize) = %d",
4270                       rc));
4271         }
4272
4273         if (pSMB)
4274                 cifs_small_buf_release(pSMB);
4275
4276         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4277                 since file handle passed in no longer valid */
4278
4279         return rc;
4280 }
4281
4282 /* Some legacy servers such as NT4 require that the file times be set on 
4283    an open handle, rather than by pathname - this is awkward due to
4284    potential access conflicts on the open, but it is unavoidable for these
4285    old servers since the only other choice is to go from 100 nanosecond DCE
4286    time and resort to the original setpathinfo level which takes the ancient
4287    DOS time format with 2 second granularity */
4288 int
4289 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
4290                    __u16 fid)
4291 {
4292         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4293         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4294         char *data_offset;
4295         int rc = 0;
4296         int bytes_returned = 0;
4297         __u16 params, param_offset, offset, byte_count, count;
4298
4299         cFYI(1, ("Set Times (via SetFileInfo)"));
4300         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4301
4302         if (rc)
4303                 return rc;
4304
4305         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4306
4307         /* At this point there is no need to override the current pid
4308         with the pid of the opener, but that could change if we someday
4309         use an existing handle (rather than opening one on the fly) */
4310         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4311         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4312     
4313         params = 6;
4314         pSMB->MaxSetupCount = 0;
4315         pSMB->Reserved = 0;
4316         pSMB->Flags = 0;
4317         pSMB->Timeout = 0;
4318         pSMB->Reserved2 = 0;
4319         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4320         offset = param_offset + params;
4321
4322         data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
4323
4324         count = sizeof (FILE_BASIC_INFO);
4325         pSMB->MaxParameterCount = cpu_to_le16(2);
4326         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4327         pSMB->SetupCount = 1;
4328         pSMB->Reserved3 = 0;
4329         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4330         byte_count = 3 /* pad */  + params + count;
4331         pSMB->DataCount = cpu_to_le16(count);
4332         pSMB->ParameterCount = cpu_to_le16(params);
4333         pSMB->TotalDataCount = pSMB->DataCount;
4334         pSMB->TotalParameterCount = pSMB->ParameterCount;
4335         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4336         pSMB->DataOffset = cpu_to_le16(offset);
4337         pSMB->Fid = fid;
4338         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4339                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4340         else
4341                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4342         pSMB->Reserved4 = 0;
4343         pSMB->hdr.smb_buf_length += byte_count;
4344         pSMB->ByteCount = cpu_to_le16(byte_count);
4345         memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4346         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4347                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4348         if (rc) {
4349                 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4350         }
4351
4352         cifs_small_buf_release(pSMB);
4353
4354         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4355                 since file handle passed in no longer valid */
4356
4357         return rc;
4358 }
4359
4360
4361 int
4362 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4363                 const FILE_BASIC_INFO * data, 
4364                 const struct nls_table *nls_codepage, int remap)
4365 {
4366         TRANSACTION2_SPI_REQ *pSMB = NULL;
4367         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4368         int name_len;
4369         int rc = 0;
4370         int bytes_returned = 0;
4371         char *data_offset;
4372         __u16 params, param_offset, offset, byte_count, count;
4373
4374         cFYI(1, ("In SetTimes"));
4375
4376 SetTimesRetry:
4377         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4378                       (void **) &pSMBr);
4379         if (rc)
4380                 return rc;
4381
4382         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4383                 name_len =
4384                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4385                                      PATH_MAX, nls_codepage, remap);
4386                 name_len++;     /* trailing null */
4387                 name_len *= 2;
4388         } else {                /* BB improve the check for buffer overruns BB */
4389                 name_len = strnlen(fileName, PATH_MAX);
4390                 name_len++;     /* trailing null */
4391                 strncpy(pSMB->FileName, fileName, name_len);
4392         }
4393
4394         params = 6 + name_len;
4395         count = sizeof (FILE_BASIC_INFO);
4396         pSMB->MaxParameterCount = cpu_to_le16(2);
4397         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4398         pSMB->MaxSetupCount = 0;
4399         pSMB->Reserved = 0;
4400         pSMB->Flags = 0;
4401         pSMB->Timeout = 0;
4402         pSMB->Reserved2 = 0;
4403         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4404                                      InformationLevel) - 4;
4405         offset = param_offset + params;
4406         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4407         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4408         pSMB->DataOffset = cpu_to_le16(offset);
4409         pSMB->SetupCount = 1;
4410         pSMB->Reserved3 = 0;
4411         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4412         byte_count = 3 /* pad */  + params + count;
4413
4414         pSMB->DataCount = cpu_to_le16(count);
4415         pSMB->ParameterCount = cpu_to_le16(params);
4416         pSMB->TotalDataCount = pSMB->DataCount;
4417         pSMB->TotalParameterCount = pSMB->ParameterCount;
4418         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4419                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4420         else
4421                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4422         pSMB->Reserved4 = 0;
4423         pSMB->hdr.smb_buf_length += byte_count;
4424         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4425         pSMB->ByteCount = cpu_to_le16(byte_count);
4426         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4427                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4428         if (rc) {
4429                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4430         }
4431
4432         cifs_buf_release(pSMB);
4433
4434         if (rc == -EAGAIN)
4435                 goto SetTimesRetry;
4436
4437         return rc;
4438 }
4439
4440 /* Can not be used to set time stamps yet (due to old DOS time format) */
4441 /* Can be used to set attributes */
4442 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
4443           handling it anyway and NT4 was what we thought it would be needed for
4444           Do not delete it until we prove whether needed for Win9x though */
4445 int
4446 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4447                 __u16 dos_attrs, const struct nls_table *nls_codepage)
4448 {
4449         SETATTR_REQ *pSMB = NULL;
4450         SETATTR_RSP *pSMBr = NULL;
4451         int rc = 0;
4452         int bytes_returned;
4453         int name_len;
4454
4455         cFYI(1, ("In SetAttrLegacy"));
4456
4457 SetAttrLgcyRetry:
4458         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4459                       (void **) &pSMBr);
4460         if (rc)
4461                 return rc;
4462
4463         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4464                 name_len =
4465                         ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
4466                                 PATH_MAX, nls_codepage);
4467                 name_len++;     /* trailing null */
4468                 name_len *= 2;
4469         } else {                /* BB improve the check for buffer overruns BB */
4470                 name_len = strnlen(fileName, PATH_MAX);
4471                 name_len++;     /* trailing null */
4472                 strncpy(pSMB->fileName, fileName, name_len);
4473         }
4474         pSMB->attr = cpu_to_le16(dos_attrs);
4475         pSMB->BufferFormat = 0x04;
4476         pSMB->hdr.smb_buf_length += name_len + 1;
4477         pSMB->ByteCount = cpu_to_le16(name_len + 1);
4478         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4479                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4480         if (rc) {
4481                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4482         }
4483
4484         cifs_buf_release(pSMB);
4485
4486         if (rc == -EAGAIN)
4487                 goto SetAttrLgcyRetry;
4488
4489         return rc;
4490 }
4491 #endif /* temporarily unneeded SetAttr legacy function */
4492
4493 int
4494 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4495                     char *fileName, __u64 mode, __u64 uid, __u64 gid, 
4496                     dev_t device, const struct nls_table *nls_codepage, 
4497                     int remap)
4498 {
4499         TRANSACTION2_SPI_REQ *pSMB = NULL;
4500         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4501         int name_len;
4502         int rc = 0;
4503         int bytes_returned = 0;
4504         FILE_UNIX_BASIC_INFO *data_offset;
4505         __u16 params, param_offset, offset, count, byte_count;
4506
4507         cFYI(1, ("In SetUID/GID/Mode"));
4508 setPermsRetry:
4509         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4510                       (void **) &pSMBr);
4511         if (rc)
4512                 return rc;
4513
4514         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4515                 name_len =
4516                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4517                                      PATH_MAX, nls_codepage, remap);
4518                 name_len++;     /* trailing null */
4519                 name_len *= 2;
4520         } else {        /* BB improve the check for buffer overruns BB */
4521                 name_len = strnlen(fileName, PATH_MAX);
4522                 name_len++;     /* trailing null */
4523                 strncpy(pSMB->FileName, fileName, name_len);
4524         }
4525
4526         params = 6 + name_len;
4527         count = sizeof (FILE_UNIX_BASIC_INFO);
4528         pSMB->MaxParameterCount = cpu_to_le16(2);
4529         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4530         pSMB->MaxSetupCount = 0;
4531         pSMB->Reserved = 0;
4532         pSMB->Flags = 0;
4533         pSMB->Timeout = 0;
4534         pSMB->Reserved2 = 0;
4535         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4536                                      InformationLevel) - 4;
4537         offset = param_offset + params;
4538         data_offset =
4539             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4540                                       offset);
4541         memset(data_offset, 0, count);
4542         pSMB->DataOffset = cpu_to_le16(offset);
4543         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4544         pSMB->SetupCount = 1;
4545         pSMB->Reserved3 = 0;
4546         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4547         byte_count = 3 /* pad */  + params + count;
4548         pSMB->ParameterCount = cpu_to_le16(params);
4549         pSMB->DataCount = cpu_to_le16(count);
4550         pSMB->TotalParameterCount = pSMB->ParameterCount;
4551         pSMB->TotalDataCount = pSMB->DataCount;
4552         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4553         pSMB->Reserved4 = 0;
4554         pSMB->hdr.smb_buf_length += byte_count;
4555         data_offset->Uid = cpu_to_le64(uid);
4556         data_offset->Gid = cpu_to_le64(gid);
4557         /* better to leave device as zero when it is  */
4558         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4559         data_offset->DevMinor = cpu_to_le64(MINOR(device));
4560         data_offset->Permissions = cpu_to_le64(mode);
4561     
4562         if(S_ISREG(mode))
4563                 data_offset->Type = cpu_to_le32(UNIX_FILE);
4564         else if(S_ISDIR(mode))
4565                 data_offset->Type = cpu_to_le32(UNIX_DIR);
4566         else if(S_ISLNK(mode))
4567                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4568         else if(S_ISCHR(mode))
4569                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4570         else if(S_ISBLK(mode))
4571                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4572         else if(S_ISFIFO(mode))
4573                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4574         else if(S_ISSOCK(mode))
4575                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4576
4577
4578         pSMB->ByteCount = cpu_to_le16(byte_count);
4579         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4580                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4581         if (rc) {
4582                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4583         }
4584
4585         if (pSMB)
4586                 cifs_buf_release(pSMB);
4587         if (rc == -EAGAIN)
4588                 goto setPermsRetry;
4589         return rc;
4590 }
4591
4592 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
4593                   const int notify_subdirs, const __u16 netfid,
4594                   __u32 filter, struct file * pfile, int multishot, 
4595                   const struct nls_table *nls_codepage)
4596 {
4597         int rc = 0;
4598         struct smb_com_transaction_change_notify_req * pSMB = NULL;
4599         struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4600         struct dir_notify_req *dnotify_req;
4601         int bytes_returned;
4602
4603         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4604         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4605                       (void **) &pSMBr);
4606         if (rc)
4607                 return rc;
4608
4609         pSMB->TotalParameterCount = 0 ;
4610         pSMB->TotalDataCount = 0;
4611         pSMB->MaxParameterCount = cpu_to_le32(2);
4612         /* BB find exact data count max from sess structure BB */
4613         pSMB->MaxDataCount = 0; /* same in little endian or be */
4614 /* BB VERIFY verify which is correct for above BB */
4615         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4616                                              MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4617
4618         pSMB->MaxSetupCount = 4;
4619         pSMB->Reserved = 0;
4620         pSMB->ParameterOffset = 0;
4621         pSMB->DataCount = 0;
4622         pSMB->DataOffset = 0;
4623         pSMB->SetupCount = 4; /* single byte does not need le conversion */
4624         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4625         pSMB->ParameterCount = pSMB->TotalParameterCount;
4626         if(notify_subdirs)
4627                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4628         pSMB->Reserved2 = 0;
4629         pSMB->CompletionFilter = cpu_to_le32(filter);
4630         pSMB->Fid = netfid; /* file handle always le */
4631         pSMB->ByteCount = 0;
4632
4633         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4634                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4635         if (rc) {
4636                 cFYI(1, ("Error in Notify = %d", rc));
4637         } else {
4638                 /* Add file to outstanding requests */
4639                 /* BB change to kmem cache alloc */     
4640                 dnotify_req = (struct dir_notify_req *) kmalloc(
4641                                                 sizeof(struct dir_notify_req),
4642                                                  GFP_KERNEL);
4643                 if(dnotify_req) {
4644                         dnotify_req->Pid = pSMB->hdr.Pid;
4645                         dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4646                         dnotify_req->Mid = pSMB->hdr.Mid;
4647                         dnotify_req->Tid = pSMB->hdr.Tid;
4648                         dnotify_req->Uid = pSMB->hdr.Uid;
4649                         dnotify_req->netfid = netfid;
4650                         dnotify_req->pfile = pfile;
4651                         dnotify_req->filter = filter;
4652                         dnotify_req->multishot = multishot;
4653                         spin_lock(&GlobalMid_Lock);
4654                         list_add_tail(&dnotify_req->lhead, 
4655                                         &GlobalDnotifyReqList);
4656                         spin_unlock(&GlobalMid_Lock);
4657                 } else 
4658                         rc = -ENOMEM;
4659         }
4660         cifs_buf_release(pSMB);
4661         return rc;      
4662 }
4663 #ifdef CONFIG_CIFS_XATTR
4664 ssize_t
4665 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4666                  const unsigned char *searchName,
4667                  char * EAData, size_t buf_size,
4668                  const struct nls_table *nls_codepage, int remap)
4669 {
4670                 /* BB assumes one setup word */
4671         TRANSACTION2_QPI_REQ *pSMB = NULL;
4672         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4673         int rc = 0;
4674         int bytes_returned;
4675         int name_len;
4676         struct fea * temp_fea;
4677         char * temp_ptr;
4678         __u16 params, byte_count;
4679
4680         cFYI(1, ("In Query All EAs path %s", searchName));
4681 QAllEAsRetry:
4682         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4683                       (void **) &pSMBr);
4684         if (rc)
4685                 return rc;
4686
4687         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4688                 name_len =
4689                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4690                                      PATH_MAX, nls_codepage, remap);
4691                 name_len++;     /* trailing null */
4692                 name_len *= 2;
4693         } else {        /* BB improve the check for buffer overruns BB */
4694                 name_len = strnlen(searchName, PATH_MAX);
4695                 name_len++;     /* trailing null */
4696                 strncpy(pSMB->FileName, searchName, name_len);
4697         }
4698
4699         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4700         pSMB->TotalDataCount = 0;
4701         pSMB->MaxParameterCount = cpu_to_le16(2);
4702         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4703         pSMB->MaxSetupCount = 0;
4704         pSMB->Reserved = 0;
4705         pSMB->Flags = 0;
4706         pSMB->Timeout = 0;
4707         pSMB->Reserved2 = 0;
4708         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4709         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4710         pSMB->DataCount = 0;
4711         pSMB->DataOffset = 0;
4712         pSMB->SetupCount = 1;
4713         pSMB->Reserved3 = 0;
4714         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4715         byte_count = params + 1 /* pad */ ;
4716         pSMB->TotalParameterCount = cpu_to_le16(params);
4717         pSMB->ParameterCount = pSMB->TotalParameterCount;
4718         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4719         pSMB->Reserved4 = 0;
4720         pSMB->hdr.smb_buf_length += byte_count;
4721         pSMB->ByteCount = cpu_to_le16(byte_count);
4722
4723         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4724                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4725         if (rc) {
4726                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4727         } else {                /* decode response */
4728                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4729
4730                 /* BB also check enough total bytes returned */
4731                 /* BB we need to improve the validity checking
4732                 of these trans2 responses */
4733                 if (rc || (pSMBr->ByteCount < 4)) 
4734                         rc = -EIO;      /* bad smb */
4735            /* else if (pFindData){
4736                         memcpy((char *) pFindData,
4737                                (char *) &pSMBr->hdr.Protocol +
4738                                data_offset, kl);
4739                 }*/ else {
4740                         /* check that length of list is not more than bcc */
4741                         /* check that each entry does not go beyond length
4742                            of list */
4743                         /* check that each element of each entry does not
4744                            go beyond end of list */
4745                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4746                         struct fealist * ea_response_data;
4747                         rc = 0;
4748                         /* validate_trans2_offsets() */
4749                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4750                         ea_response_data = (struct fealist *)
4751                                 (((char *) &pSMBr->hdr.Protocol) +
4752                                 data_offset);
4753                         name_len = le32_to_cpu(ea_response_data->list_len);
4754                         cFYI(1,("ea length %d", name_len));
4755                         if(name_len <= 8) {
4756                         /* returned EA size zeroed at top of function */
4757                                 cFYI(1,("empty EA list returned from server"));
4758                         } else {
4759                                 /* account for ea list len */
4760                                 name_len -= 4;
4761                                 temp_fea = ea_response_data->list;
4762                                 temp_ptr = (char *)temp_fea;
4763                                 while(name_len > 0) {
4764                                         __u16 value_len;
4765                                         name_len -= 4;
4766                                         temp_ptr += 4;
4767                                         rc += temp_fea->name_len;
4768                                 /* account for prefix user. and trailing null */
4769                                         rc = rc + 5 + 1; 
4770                                         if(rc<(int)buf_size) {
4771                                                 memcpy(EAData,"user.",5);
4772                                                 EAData+=5;
4773                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
4774                                                 EAData+=temp_fea->name_len;
4775                                                 /* null terminate name */
4776                                                 *EAData = 0;
4777                                                 EAData = EAData + 1;
4778                                         } else if(buf_size == 0) {
4779                                                 /* skip copy - calc size only */
4780                                         } else {
4781                                                 /* stop before overrun buffer */
4782                                                 rc = -ERANGE;
4783                                                 break;
4784                                         }
4785                                         name_len -= temp_fea->name_len;
4786                                         temp_ptr += temp_fea->name_len;
4787                                         /* account for trailing null */
4788                                         name_len--;
4789                                         temp_ptr++;
4790                                         value_len = le16_to_cpu(temp_fea->value_len);
4791                                         name_len -= value_len;
4792                                         temp_ptr += value_len;
4793                                         /* BB check that temp_ptr is still within smb BB*/
4794                                 /* no trailing null to account for in value len */
4795                                         /* go on to next EA */
4796                                         temp_fea = (struct fea *)temp_ptr;
4797                                 }
4798                         }
4799                 }
4800         }
4801         if (pSMB)
4802                 cifs_buf_release(pSMB);
4803         if (rc == -EAGAIN)
4804                 goto QAllEAsRetry;
4805
4806         return (ssize_t)rc;
4807 }
4808
4809 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4810                 const unsigned char * searchName,const unsigned char * ea_name,
4811                 unsigned char * ea_value, size_t buf_size, 
4812                 const struct nls_table *nls_codepage, int remap)
4813 {
4814         TRANSACTION2_QPI_REQ *pSMB = NULL;
4815         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4816         int rc = 0;
4817         int bytes_returned;
4818         int name_len;
4819         struct fea * temp_fea;
4820         char * temp_ptr;
4821         __u16 params, byte_count;
4822
4823         cFYI(1, ("In Query EA path %s", searchName));
4824 QEARetry:
4825         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4826                       (void **) &pSMBr);
4827         if (rc)
4828                 return rc;
4829
4830         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4831                 name_len =
4832                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4833                                      PATH_MAX, nls_codepage, remap);
4834                 name_len++;     /* trailing null */
4835                 name_len *= 2;
4836         } else {        /* BB improve the check for buffer overruns BB */
4837                 name_len = strnlen(searchName, PATH_MAX);
4838                 name_len++;     /* trailing null */
4839                 strncpy(pSMB->FileName, searchName, name_len);
4840         }
4841
4842         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4843         pSMB->TotalDataCount = 0;
4844         pSMB->MaxParameterCount = cpu_to_le16(2);
4845         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4846         pSMB->MaxSetupCount = 0;
4847         pSMB->Reserved = 0;
4848         pSMB->Flags = 0;
4849         pSMB->Timeout = 0;
4850         pSMB->Reserved2 = 0;
4851         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4852         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4853         pSMB->DataCount = 0;
4854         pSMB->DataOffset = 0;
4855         pSMB->SetupCount = 1;
4856         pSMB->Reserved3 = 0;
4857         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4858         byte_count = params + 1 /* pad */ ;
4859         pSMB->TotalParameterCount = cpu_to_le16(params);
4860         pSMB->ParameterCount = pSMB->TotalParameterCount;
4861         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4862         pSMB->Reserved4 = 0;
4863         pSMB->hdr.smb_buf_length += byte_count;
4864         pSMB->ByteCount = cpu_to_le16(byte_count);
4865
4866         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4867                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4868         if (rc) {
4869                 cFYI(1, ("Send error in Query EA = %d", rc));
4870         } else {                /* decode response */
4871                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4872
4873                 /* BB also check enough total bytes returned */
4874                 /* BB we need to improve the validity checking
4875                 of these trans2 responses */
4876                 if (rc || (pSMBr->ByteCount < 4)) 
4877                         rc = -EIO;      /* bad smb */
4878            /* else if (pFindData){
4879                         memcpy((char *) pFindData,
4880                                (char *) &pSMBr->hdr.Protocol +
4881                                data_offset, kl);
4882                 }*/ else {
4883                         /* check that length of list is not more than bcc */
4884                         /* check that each entry does not go beyond length
4885                            of list */
4886                         /* check that each element of each entry does not
4887                            go beyond end of list */
4888                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4889                         struct fealist * ea_response_data;
4890                         rc = -ENODATA;
4891                         /* validate_trans2_offsets() */
4892                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4893                         ea_response_data = (struct fealist *)
4894                                 (((char *) &pSMBr->hdr.Protocol) +
4895                                 data_offset);
4896                         name_len = le32_to_cpu(ea_response_data->list_len);
4897                         cFYI(1,("ea length %d", name_len));
4898                         if(name_len <= 8) {
4899                         /* returned EA size zeroed at top of function */
4900                                 cFYI(1,("empty EA list returned from server"));
4901                         } else {
4902                                 /* account for ea list len */
4903                                 name_len -= 4;
4904                                 temp_fea = ea_response_data->list;
4905                                 temp_ptr = (char *)temp_fea;
4906                                 /* loop through checking if we have a matching
4907                                 name and then return the associated value */
4908                                 while(name_len > 0) {
4909                                         __u16 value_len;
4910                                         name_len -= 4;
4911                                         temp_ptr += 4;
4912                                         value_len = le16_to_cpu(temp_fea->value_len);
4913                                 /* BB validate that value_len falls within SMB, 
4914                                 even though maximum for name_len is 255 */ 
4915                                         if(memcmp(temp_fea->name,ea_name,
4916                                                   temp_fea->name_len) == 0) {
4917                                                 /* found a match */
4918                                                 rc = value_len;
4919                                 /* account for prefix user. and trailing null */
4920                                                 if(rc<=(int)buf_size) {
4921                                                         memcpy(ea_value,
4922                                                                 temp_fea->name+temp_fea->name_len+1,
4923                                                                 rc);
4924                                                         /* ea values, unlike ea names,
4925                                                         are not null terminated */
4926                                                 } else if(buf_size == 0) {
4927                                                 /* skip copy - calc size only */
4928                                                 } else {
4929                                                         /* stop before overrun buffer */
4930                                                         rc = -ERANGE;
4931                                                 }
4932                                                 break;
4933                                         }
4934                                         name_len -= temp_fea->name_len;
4935                                         temp_ptr += temp_fea->name_len;
4936                                         /* account for trailing null */
4937                                         name_len--;
4938                                         temp_ptr++;
4939                                         name_len -= value_len;
4940                                         temp_ptr += value_len;
4941                                 /* no trailing null to account for in value len */
4942                                         /* go on to next EA */
4943                                         temp_fea = (struct fea *)temp_ptr;
4944                                 }
4945                         } 
4946                 }
4947         }
4948         if (pSMB)
4949                 cifs_buf_release(pSMB);
4950         if (rc == -EAGAIN)
4951                 goto QEARetry;
4952
4953         return (ssize_t)rc;
4954 }
4955
4956 int
4957 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4958                 const char * ea_name, const void * ea_value, 
4959                 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4960                 int remap)
4961 {
4962         struct smb_com_transaction2_spi_req *pSMB = NULL;
4963         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4964         struct fealist *parm_data;
4965         int name_len;
4966         int rc = 0;
4967         int bytes_returned = 0;
4968         __u16 params, param_offset, byte_count, offset, count;
4969
4970         cFYI(1, ("In SetEA"));
4971 SetEARetry:
4972         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4973                       (void **) &pSMBr);
4974         if (rc)
4975                 return rc;
4976
4977         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4978                 name_len =
4979                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4980                                      PATH_MAX, nls_codepage, remap);
4981                 name_len++;     /* trailing null */
4982                 name_len *= 2;
4983         } else {                /* BB improve the check for buffer overruns BB */
4984                 name_len = strnlen(fileName, PATH_MAX);
4985                 name_len++;     /* trailing null */
4986                 strncpy(pSMB->FileName, fileName, name_len);
4987         }
4988
4989         params = 6 + name_len;
4990
4991         /* done calculating parms using name_len of file name,
4992         now use name_len to calculate length of ea name
4993         we are going to create in the inode xattrs */
4994         if(ea_name == NULL)
4995                 name_len = 0;
4996         else
4997                 name_len = strnlen(ea_name,255);
4998
4999         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5000         pSMB->MaxParameterCount = cpu_to_le16(2);
5001         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5002         pSMB->MaxSetupCount = 0;
5003         pSMB->Reserved = 0;
5004         pSMB->Flags = 0;
5005         pSMB->Timeout = 0;
5006         pSMB->Reserved2 = 0;
5007         param_offset = offsetof(struct smb_com_transaction2_spi_req,
5008                                      InformationLevel) - 4;
5009         offset = param_offset + params;
5010         pSMB->InformationLevel =
5011                 cpu_to_le16(SMB_SET_FILE_EA);
5012
5013         parm_data =
5014                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5015                                        offset);
5016         pSMB->ParameterOffset = cpu_to_le16(param_offset);
5017         pSMB->DataOffset = cpu_to_le16(offset);
5018         pSMB->SetupCount = 1;
5019         pSMB->Reserved3 = 0;
5020         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5021         byte_count = 3 /* pad */  + params + count;
5022         pSMB->DataCount = cpu_to_le16(count);
5023         parm_data->list_len = cpu_to_le32(count);
5024         parm_data->list[0].EA_flags = 0;
5025         /* we checked above that name len is less than 255 */
5026         parm_data->list[0].name_len = (__u8)name_len;
5027         /* EA names are always ASCII */
5028         if(ea_name)
5029                 strncpy(parm_data->list[0].name,ea_name,name_len);
5030         parm_data->list[0].name[name_len] = 0;
5031         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5032         /* caller ensures that ea_value_len is less than 64K but
5033         we need to ensure that it fits within the smb */
5034
5035         /*BB add length check that it would fit in negotiated SMB buffer size BB */
5036         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5037         if(ea_value_len)
5038                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5039
5040         pSMB->TotalDataCount = pSMB->DataCount;
5041         pSMB->ParameterCount = cpu_to_le16(params);
5042         pSMB->TotalParameterCount = pSMB->ParameterCount;
5043         pSMB->Reserved4 = 0;
5044         pSMB->hdr.smb_buf_length += byte_count;
5045         pSMB->ByteCount = cpu_to_le16(byte_count);
5046         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5047                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5048         if (rc) {
5049                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5050         }
5051
5052         cifs_buf_release(pSMB);
5053
5054         if (rc == -EAGAIN)
5055                 goto SetEARetry;
5056
5057         return rc;
5058 }
5059
5060 #endif