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