[CIFS] CIFS readdir perf optimizations part 1
[linux-2.6] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2006
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   Contains the routines for constructing the SMB PDUs themselves
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
25  /* These are mostly routines that operate on a pathname, or on a tree id     */
26  /* (mounted volume), but there are eight handle based routines which must be */
27  /* treated slightly different for reconnection purposes since we never want  */
28  /* to reuse a stale file handle and the caller knows the file handle */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsproto.h"
38 #include "cifs_unicode.h"
39 #include "cifs_debug.h"
40 #include "cifsacl.h"
41
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44         int index;
45         char *name;
46 } protocols[] = {
47         {CIFS_PROT, "\2NT LM 0.12"}, 
48         {CIFS_PROT, "\2POSIX 2"},
49         {BAD_PROT, "\2"}
50 };
51 #else
52 static struct {
53         int index;
54         char *name;
55 } protocols[] = {
56         {CIFS_PROT, "\2NT LM 0.12"}, 
57         {BAD_PROT, "\2"}
58 };
59 #endif
60
61
62 /* Mark as invalid, all open files on tree connections since they
63    were closed when session to server was lost */
64 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
65 {
66         struct cifsFileInfo *open_file = NULL;
67         struct list_head * tmp;
68         struct list_head * tmp1;
69
70 /* list all files open on tree connection and mark them invalid */
71         write_lock(&GlobalSMBSeslock);
72         list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
73                 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
74                 if(open_file) {
75                         open_file->invalidHandle = TRUE;
76                 }
77         }
78         write_unlock(&GlobalSMBSeslock);
79         /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
80            to this tcon */
81 }
82
83 /* If the return code is zero, this function must fill in request_buf pointer */
84 static int
85 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
86          void **request_buf /* returned */)
87 {
88         int rc = 0;
89
90         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
91            check for tcp and smb session status done differently
92            for those three - in the calling routine */
93         if(tcon) {
94                 if(tcon->tidStatus == CifsExiting) {
95                         /* only tree disconnect, open, and write,
96                         (and ulogoff which does not have tcon)
97                         are allowed as we start force umount */
98                         if((smb_command != SMB_COM_WRITE_ANDX) && 
99                            (smb_command != SMB_COM_OPEN_ANDX) && 
100                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
101                                 cFYI(1,("can not send cmd %d while umounting",
102                                         smb_command));
103                                 return -ENODEV;
104                         }
105                 }
106                 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
107                                   (tcon->ses->server)){
108                         struct nls_table *nls_codepage;
109                                 /* Give Demultiplex thread up to 10 seconds to 
110                                    reconnect, should be greater than cifs socket
111                                    timeout which is 7 seconds */
112                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
113                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
114                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
115                                 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
116                                         /* on "soft" mounts we wait once */
117                                         if((tcon->retry == FALSE) || 
118                                            (tcon->ses->status == CifsExiting)) {
119                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
120                                                 return -EHOSTDOWN;
121                                         } /* else "hard" mount - keep retrying
122                                              until process is killed or server
123                                              comes back on-line */
124                                 } else /* TCP session is reestablished now */
125                                         break;
126                                  
127                         }
128                         
129                         nls_codepage = load_nls_default();
130                 /* need to prevent multiple threads trying to
131                 simultaneously reconnect the same SMB session */
132                         down(&tcon->ses->sesSem);
133                         if(tcon->ses->status == CifsNeedReconnect)
134                                 rc = cifs_setup_session(0, tcon->ses, 
135                                                         nls_codepage);
136                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
137                                 mark_open_files_invalid(tcon);
138                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
139                                         , nls_codepage);
140                                 up(&tcon->ses->sesSem);
141                                 /* BB FIXME add code to check if wsize needs
142                                    update due to negotiated smb buffer size
143                                    shrinking */
144                                 if(rc == 0)
145                                         atomic_inc(&tconInfoReconnectCount);
146
147                                 cFYI(1, ("reconnect tcon rc = %d", rc));
148                                 /* Removed call to reopen open files here - 
149                                    it is safer (and faster) to reopen files
150                                    one at a time as needed in read and write */
151
152                                 /* Check if handle based operation so we 
153                                    know whether we can continue or not without
154                                    returning to caller to reset file handle */
155                                 switch(smb_command) {
156                                         case SMB_COM_READ_ANDX:
157                                         case SMB_COM_WRITE_ANDX:
158                                         case SMB_COM_CLOSE:
159                                         case SMB_COM_FIND_CLOSE2:
160                                         case SMB_COM_LOCKING_ANDX: {
161                                                 unload_nls(nls_codepage);
162                                                 return -EAGAIN;
163                                         }
164                                 }
165                         } else {
166                                 up(&tcon->ses->sesSem);
167                         }
168                         unload_nls(nls_codepage);
169
170                 } else {
171                         return -EIO;
172                 }
173         }
174         if(rc)
175                 return rc;
176
177         *request_buf = cifs_small_buf_get();
178         if (*request_buf == NULL) {
179                 /* BB should we add a retry in here if not a writepage? */
180                 return -ENOMEM;
181         }
182
183         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
184
185         if(tcon != NULL)
186                 cifs_stats_inc(&tcon->num_smbs_sent);
187
188         return rc;
189 }
190
191 #ifdef CONFIG_CIFS_EXPERIMENTAL  
192 int
193 small_smb_init_no_tc(const int smb_command, const int wct, 
194                      struct cifsSesInfo *ses, void **request_buf)
195 {
196         int rc;
197         struct smb_hdr * buffer;
198
199         rc = small_smb_init(smb_command, wct, NULL, request_buf);
200         if(rc)
201                 return rc;
202
203         buffer = (struct smb_hdr *)*request_buf;
204         buffer->Mid = GetNextMid(ses->server);
205         if (ses->capabilities & CAP_UNICODE)
206                 buffer->Flags2 |= SMBFLG2_UNICODE;
207         if (ses->capabilities & CAP_STATUS32)
208                 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
209
210         /* uid, tid can stay at zero as set in header assemble */
211
212         /* BB add support for turning on the signing when 
213         this function is used after 1st of session setup requests */
214
215         return rc;
216 }
217 #endif  /* CONFIG_CIFS_EXPERIMENTAL */
218
219 /* If the return code is zero, this function must fill in request_buf pointer */
220 static int
221 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
222          void **request_buf /* returned */ ,
223          void **response_buf /* returned */ )
224 {
225         int rc = 0;
226
227         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
228            check for tcp and smb session status done differently
229            for those three - in the calling routine */
230         if(tcon) {
231                 if(tcon->tidStatus == CifsExiting) {
232                         /* only tree disconnect, open, and write,
233                           (and ulogoff which does not have tcon)
234                           are allowed as we start force umount */
235                         if((smb_command != SMB_COM_WRITE_ANDX) &&
236                            (smb_command != SMB_COM_OPEN_ANDX) &&
237                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
238                                 cFYI(1,("can not send cmd %d while umounting",
239                                         smb_command));
240                                 return -ENODEV;
241                         }
242                 }
243
244                 if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
245                                   (tcon->ses->server)){
246                         struct nls_table *nls_codepage;
247                                 /* Give Demultiplex thread up to 10 seconds to
248                                    reconnect, should be greater than cifs socket
249                                    timeout which is 7 seconds */
250                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
251                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
252                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
253                                 if(tcon->ses->server->tcpStatus == 
254                                                 CifsNeedReconnect) {
255                                         /* on "soft" mounts we wait once */
256                                         if((tcon->retry == FALSE) || 
257                                            (tcon->ses->status == CifsExiting)) {
258                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
259                                                 return -EHOSTDOWN;
260                                         } /* else "hard" mount - keep retrying
261                                              until process is killed or server
262                                              comes on-line */
263                                 } else /* TCP session is reestablished now */
264                                         break;
265                                  
266                         }
267                         
268                         nls_codepage = load_nls_default();
269                 /* need to prevent multiple threads trying to
270                 simultaneously reconnect the same SMB session */
271                         down(&tcon->ses->sesSem);
272                         if(tcon->ses->status == CifsNeedReconnect)
273                                 rc = cifs_setup_session(0, tcon->ses, 
274                                                         nls_codepage);
275                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
276                                 mark_open_files_invalid(tcon);
277                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
278                                               tcon, nls_codepage);
279                                 up(&tcon->ses->sesSem);
280                                 /* BB FIXME add code to check if wsize needs
281                                 update due to negotiated smb buffer size
282                                 shrinking */
283                                 if(rc == 0)
284                                         atomic_inc(&tconInfoReconnectCount);
285
286                                 cFYI(1, ("reconnect tcon rc = %d", rc));
287                                 /* Removed call to reopen open files here - 
288                                    it is safer (and faster) to reopen files
289                                    one at a time as needed in read and write */
290
291                                 /* Check if handle based operation so we 
292                                    know whether we can continue or not without
293                                    returning to caller to reset file handle */
294                                 switch(smb_command) {
295                                         case SMB_COM_READ_ANDX:
296                                         case SMB_COM_WRITE_ANDX:
297                                         case SMB_COM_CLOSE:
298                                         case SMB_COM_FIND_CLOSE2:
299                                         case SMB_COM_LOCKING_ANDX: {
300                                                 unload_nls(nls_codepage);
301                                                 return -EAGAIN;
302                                         }
303                                 }
304                         } else {
305                                 up(&tcon->ses->sesSem);
306                         }
307                         unload_nls(nls_codepage);
308
309                 } else {
310                         return -EIO;
311                 }
312         }
313         if(rc)
314                 return rc;
315
316         *request_buf = cifs_buf_get();
317         if (*request_buf == NULL) {
318                 /* BB should we add a retry in here if not a writepage? */
319                 return -ENOMEM;
320         }
321     /* Although the original thought was we needed the response buf for  */
322     /* potential retries of smb operations it turns out we can determine */
323     /* from the mid flags when the request buffer can be resent without  */
324     /* having to use a second distinct buffer for the response */
325         *response_buf = *request_buf; 
326
327         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
328                         wct /*wct */ );
329
330         if(tcon != NULL)
331                 cifs_stats_inc(&tcon->num_smbs_sent);
332
333         return rc;
334 }
335
336 static int validate_t2(struct smb_t2_rsp * pSMB) 
337 {
338         int rc = -EINVAL;
339         int total_size;
340         char * pBCC;
341
342         /* check for plausible wct, bcc and t2 data and parm sizes */
343         /* check for parm and data offset going beyond end of smb */
344         if(pSMB->hdr.WordCount >= 10) {
345                 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
346                    (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
347                         /* check that bcc is at least as big as parms + data */
348                         /* check that bcc is less than negotiated smb buffer */
349                         total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
350                         if(total_size < 512) {
351                                 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
352                                 /* BCC le converted in SendReceive */
353                                 pBCC = (pSMB->hdr.WordCount * 2) + 
354                                         sizeof(struct smb_hdr) +
355                                         (char *)pSMB;
356                                 if((total_size <= (*(u16 *)pBCC)) && 
357                                    (total_size < 
358                                         CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
359                                         return 0;
360                                 }
361                                 
362                         }
363                 }
364         }
365         cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
366                 sizeof(struct smb_t2_rsp) + 16);
367         return rc;
368 }
369 int
370 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
371 {
372         NEGOTIATE_REQ *pSMB;
373         NEGOTIATE_RSP *pSMBr;
374         int rc = 0;
375         int bytes_returned;
376         struct TCP_Server_Info * server;
377         u16 count;
378
379         if(ses->server)
380                 server = ses->server;
381         else {
382                 rc = -EIO;
383                 return rc;
384         }
385         rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
386                       (void **) &pSMB, (void **) &pSMBr);
387         if (rc)
388                 return rc;
389         pSMB->hdr.Mid = GetNextMid(server);
390         pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
391         if (extended_security)
392                 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
393
394         count = strlen(protocols[0].name) + 1;
395         strncpy(pSMB->DialectsArray, protocols[0].name, 30);    
396     /* null guaranteed to be at end of source and target buffers anyway */
397
398         pSMB->hdr.smb_buf_length += count;
399         pSMB->ByteCount = cpu_to_le16(count);
400
401         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
402                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
403         if (rc == 0) {
404                 server->secMode = pSMBr->SecurityMode;
405                 if((server->secMode & SECMODE_USER) == 0)
406                         cFYI(1,("share mode security"));
407                 server->secType = NTLM; /* BB override default for
408                                            NTLMv2 or kerberos v5 */
409                 /* one byte - no need to convert this or EncryptionKeyLen
410                    from little endian */
411                 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
412                 /* probably no need to store and check maxvcs */
413                 server->maxBuf =
414                         min(le32_to_cpu(pSMBr->MaxBufferSize),
415                         (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
416                 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
417                 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
418                 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
419                 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
420                 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
421         /* BB with UTC do we ever need to be using srvr timezone? */
422                 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
423                         memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
424                                CIFS_CRYPTO_KEY_SIZE);
425                 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
426                            && (pSMBr->EncryptionKeyLength == 0)) {
427                         /* decode security blob */
428                 } else
429                         rc = -EIO;
430
431                 /* BB might be helpful to save off the domain of server here */
432
433                 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
434                         (server->capabilities & CAP_EXTENDED_SECURITY)) {
435                         count = pSMBr->ByteCount;
436                         if (count < 16)
437                                 rc = -EIO;
438                         else if (count == 16) {
439                                 server->secType = RawNTLMSSP;
440                                 if (server->socketUseCount.counter > 1) {
441                                         if (memcmp
442                                                 (server->server_GUID,
443                                                 pSMBr->u.extended_response.
444                                                 GUID, 16) != 0) {
445                                                 cFYI(1, ("server UID changed"));
446                                                 memcpy(server->
447                                                         server_GUID,
448                                                         pSMBr->u.
449                                                         extended_response.
450                                                         GUID, 16);
451                                         }
452                                 } else
453                                         memcpy(server->server_GUID,
454                                                pSMBr->u.extended_response.
455                                                GUID, 16);
456                         } else {
457                                 rc = decode_negTokenInit(pSMBr->u.
458                                                          extended_response.
459                                                          SecurityBlob,
460                                                          count - 16,
461                                                          &server->secType);
462                                 if(rc == 1) {
463                                 /* BB Need to fill struct for sessetup here */
464                                         rc = -EOPNOTSUPP;
465                                 } else {
466                                         rc = -EINVAL;
467                                 }
468                         }
469                 } else
470                         server->capabilities &= ~CAP_EXTENDED_SECURITY;
471                 if(sign_CIFS_PDUs == FALSE) {        
472                         if(server->secMode & SECMODE_SIGN_REQUIRED)
473                                 cERROR(1,
474                                  ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
475                         server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
476                 } else if(sign_CIFS_PDUs == 1) {
477                         if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
478                                 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
479                 }
480                                 
481         }
482         
483         cifs_buf_release(pSMB);
484         return rc;
485 }
486
487 int
488 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
489 {
490         struct smb_hdr *smb_buffer;
491         struct smb_hdr *smb_buffer_response; /* BB removeme BB */
492         int rc = 0;
493         int length;
494
495         cFYI(1, ("In tree disconnect"));
496         /*
497          *  If last user of the connection and
498          *  connection alive - disconnect it
499          *  If this is the last connection on the server session disconnect it
500          *  (and inside session disconnect we should check if tcp socket needs 
501          *  to be freed and kernel thread woken up).
502          */
503         if (tcon)
504                 down(&tcon->tconSem);
505         else
506                 return -EIO;
507
508         atomic_dec(&tcon->useCount);
509         if (atomic_read(&tcon->useCount) > 0) {
510                 up(&tcon->tconSem);
511                 return -EBUSY;
512         }
513
514         /* No need to return error on this operation if tid invalidated and 
515         closed on server already e.g. due to tcp session crashing */
516         if(tcon->tidStatus == CifsNeedReconnect) {
517                 up(&tcon->tconSem);
518                 return 0;  
519         }
520
521         if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {    
522                 up(&tcon->tconSem);
523                 return -EIO;
524         }
525         rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 
526                             (void **)&smb_buffer);
527         if (rc) {
528                 up(&tcon->tconSem);
529                 return rc;
530         } else {
531                 smb_buffer_response = smb_buffer; /* BB removeme BB */
532         }
533         rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
534                          &length, 0);
535         if (rc)
536                 cFYI(1, ("Tree disconnect failed %d", rc));
537
538         if (smb_buffer)
539                 cifs_small_buf_release(smb_buffer);
540         up(&tcon->tconSem);
541
542         /* No need to return error on this operation if tid invalidated and 
543         closed on server already e.g. due to tcp session crashing */
544         if (rc == -EAGAIN)
545                 rc = 0;
546
547         return rc;
548 }
549
550 int
551 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
552 {
553         struct smb_hdr *smb_buffer_response;
554         LOGOFF_ANDX_REQ *pSMB;
555         int rc = 0;
556         int length;
557
558         cFYI(1, ("In SMBLogoff for session disconnect"));
559         if (ses)
560                 down(&ses->sesSem);
561         else
562                 return -EIO;
563
564         atomic_dec(&ses->inUse);
565         if (atomic_read(&ses->inUse) > 0) {
566                 up(&ses->sesSem);
567                 return -EBUSY;
568         }
569         rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
570         if (rc) {
571                 up(&ses->sesSem);
572                 return rc;
573         }
574
575         smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
576         
577         if(ses->server) {
578                 pSMB->hdr.Mid = GetNextMid(ses->server);
579
580                 if(ses->server->secMode & 
581                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
582                         pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
583         }
584
585         pSMB->hdr.Uid = ses->Suid;
586
587         pSMB->AndXCommand = 0xFF;
588         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
589                          smb_buffer_response, &length, 0);
590         if (ses->server) {
591                 atomic_dec(&ses->server->socketUseCount);
592                 if (atomic_read(&ses->server->socketUseCount) == 0) {
593                         spin_lock(&GlobalMid_Lock);
594                         ses->server->tcpStatus = CifsExiting;
595                         spin_unlock(&GlobalMid_Lock);
596                         rc = -ESHUTDOWN;
597                 }
598         }
599         up(&ses->sesSem);
600         cifs_small_buf_release(pSMB);
601
602         /* if session dead then we do not need to do ulogoff,
603                 since server closed smb session, no sense reporting 
604                 error */
605         if (rc == -EAGAIN)
606                 rc = 0;
607         return rc;
608 }
609
610 int
611 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
612                const struct nls_table *nls_codepage, int remap)
613 {
614         DELETE_FILE_REQ *pSMB = NULL;
615         DELETE_FILE_RSP *pSMBr = NULL;
616         int rc = 0;
617         int bytes_returned;
618         int name_len;
619
620 DelFileRetry:
621         rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
622                       (void **) &pSMBr);
623         if (rc)
624                 return rc;
625
626         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
627                 name_len =
628                     cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, 
629                                      PATH_MAX, nls_codepage, remap);
630                 name_len++;     /* trailing null */
631                 name_len *= 2;
632         } else {                /* BB improve check for buffer overruns BB */
633                 name_len = strnlen(fileName, PATH_MAX);
634                 name_len++;     /* trailing null */
635                 strncpy(pSMB->fileName, fileName, name_len);
636         }
637         pSMB->SearchAttributes =
638             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
639         pSMB->BufferFormat = 0x04;
640         pSMB->hdr.smb_buf_length += name_len + 1;
641         pSMB->ByteCount = cpu_to_le16(name_len + 1);
642         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
643                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
644         cifs_stats_inc(&tcon->num_deletes);
645         if (rc) {
646                 cFYI(1, ("Error in RMFile = %d", rc));
647         } 
648
649         cifs_buf_release(pSMB);
650         if (rc == -EAGAIN)
651                 goto DelFileRetry;
652
653         return rc;
654 }
655
656 int
657 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, 
658              const struct nls_table *nls_codepage, int remap)
659 {
660         DELETE_DIRECTORY_REQ *pSMB = NULL;
661         DELETE_DIRECTORY_RSP *pSMBr = NULL;
662         int rc = 0;
663         int bytes_returned;
664         int name_len;
665
666         cFYI(1, ("In CIFSSMBRmDir"));
667 RmDirRetry:
668         rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
669                       (void **) &pSMBr);
670         if (rc)
671                 return rc;
672
673         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
674                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
675                                          PATH_MAX, nls_codepage, remap);
676                 name_len++;     /* trailing null */
677                 name_len *= 2;
678         } else {                /* BB improve check for buffer overruns BB */
679                 name_len = strnlen(dirName, PATH_MAX);
680                 name_len++;     /* trailing null */
681                 strncpy(pSMB->DirName, dirName, name_len);
682         }
683
684         pSMB->BufferFormat = 0x04;
685         pSMB->hdr.smb_buf_length += name_len + 1;
686         pSMB->ByteCount = cpu_to_le16(name_len + 1);
687         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
688                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
689         cifs_stats_inc(&tcon->num_rmdirs);
690         if (rc) {
691                 cFYI(1, ("Error in RMDir = %d", rc));
692         }
693
694         cifs_buf_release(pSMB);
695         if (rc == -EAGAIN)
696                 goto RmDirRetry;
697         return rc;
698 }
699
700 int
701 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
702              const char *name, const struct nls_table *nls_codepage, int remap)
703 {
704         int rc = 0;
705         CREATE_DIRECTORY_REQ *pSMB = NULL;
706         CREATE_DIRECTORY_RSP *pSMBr = NULL;
707         int bytes_returned;
708         int name_len;
709
710         cFYI(1, ("In CIFSSMBMkDir"));
711 MkDirRetry:
712         rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
713                       (void **) &pSMBr);
714         if (rc)
715                 return rc;
716
717         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
718                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, 
719                                             PATH_MAX, nls_codepage, remap);
720                 name_len++;     /* trailing null */
721                 name_len *= 2;
722         } else {                /* BB improve check for buffer overruns BB */
723                 name_len = strnlen(name, PATH_MAX);
724                 name_len++;     /* trailing null */
725                 strncpy(pSMB->DirName, name, name_len);
726         }
727
728         pSMB->BufferFormat = 0x04;
729         pSMB->hdr.smb_buf_length += name_len + 1;
730         pSMB->ByteCount = cpu_to_le16(name_len + 1);
731         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
732                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
733         cifs_stats_inc(&tcon->num_mkdirs);
734         if (rc) {
735                 cFYI(1, ("Error in Mkdir = %d", rc));
736         }
737
738         cifs_buf_release(pSMB);
739         if (rc == -EAGAIN)
740                 goto MkDirRetry;
741         return rc;
742 }
743
744 static __u16 convert_disposition(int disposition)
745 {
746         __u16 ofun = 0;
747
748         switch (disposition) {
749                 case FILE_SUPERSEDE:
750                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
751                         break;
752                 case FILE_OPEN:
753                         ofun = SMBOPEN_OAPPEND;
754                         break;
755                 case FILE_CREATE:
756                         ofun = SMBOPEN_OCREATE;
757                         break;
758                 case FILE_OPEN_IF:
759                         ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
760                         break;
761                 case FILE_OVERWRITE:
762                         ofun = SMBOPEN_OTRUNC;
763                         break;
764                 case FILE_OVERWRITE_IF:
765                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
766                         break;
767                 default:
768                         cFYI(1,("unknown disposition %d",disposition));
769                         ofun =  SMBOPEN_OAPPEND; /* regular open */
770         }
771         return ofun;
772 }
773
774 int
775 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
776             const char *fileName, const int openDisposition,
777             const int access_flags, const int create_options, __u16 * netfid,
778             int *pOplock, FILE_ALL_INFO * pfile_info,
779             const struct nls_table *nls_codepage, int remap)
780 {
781         int rc = -EACCES;
782         OPENX_REQ *pSMB = NULL;
783         OPENX_RSP *pSMBr = NULL;
784         int bytes_returned;
785         int name_len;
786         __u16 count;
787
788 OldOpenRetry:
789         rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
790                       (void **) &pSMBr);
791         if (rc)
792                 return rc;
793
794         pSMB->AndXCommand = 0xFF;       /* none */
795
796         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
797                 count = 1;      /* account for one byte pad to word boundary */
798                 name_len =
799                    cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
800                                     fileName, PATH_MAX, nls_codepage, remap);
801                 name_len++;     /* trailing null */
802                 name_len *= 2;
803         } else {                /* BB improve check for buffer overruns BB */
804                 count = 0;      /* no pad */
805                 name_len = strnlen(fileName, PATH_MAX);
806                 name_len++;     /* trailing null */
807                 strncpy(pSMB->fileName, fileName, name_len);
808         }
809         if (*pOplock & REQ_OPLOCK)
810                 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
811         else if (*pOplock & REQ_BATCHOPLOCK) {
812                 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
813         }
814         pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
815         /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
816         /* 0 = read
817            1 = write
818            2 = rw
819            3 = execute
820         */
821         pSMB->Mode = cpu_to_le16(2);
822         pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
823         /* set file as system file if special file such
824            as fifo and server expecting SFU style and
825            no Unix extensions */
826
827         if(create_options & CREATE_OPTION_SPECIAL)
828                 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
829         else
830                 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
831
832         /* if ((omode & S_IWUGO) == 0)
833                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
834         /*  Above line causes problems due to vfs splitting create into two
835             pieces - need to set mode after file created not while it is
836             being created */
837
838         /* BB FIXME BB */
839 /*      pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
840         /* BB FIXME END BB */
841
842         pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
843         pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
844         count += name_len;
845         pSMB->hdr.smb_buf_length += count;
846
847         pSMB->ByteCount = cpu_to_le16(count);
848         /* long_op set to 1 to allow for oplock break timeouts */
849         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
850                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
851         cifs_stats_inc(&tcon->num_opens);
852         if (rc) {
853                 cFYI(1, ("Error in Open = %d", rc));
854         } else {
855         /* BB verify if wct == 15 */
856
857 /*              *pOplock = pSMBr->OplockLevel; */  /* BB take from action field BB */
858
859                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
860                 /* Let caller know file was created so we can set the mode. */
861                 /* Do we care about the CreateAction in any other cases? */
862         /* BB FIXME BB */
863 /*              if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
864                         *pOplock |= CIFS_CREATE_ACTION; */
865         /* BB FIXME END */
866
867                 if(pfile_info) {
868                         pfile_info->CreationTime = 0; /* BB convert CreateTime*/
869                         pfile_info->LastAccessTime = 0; /* BB fixme */
870                         pfile_info->LastWriteTime = 0; /* BB fixme */
871                         pfile_info->ChangeTime = 0;  /* BB fixme */
872                         pfile_info->Attributes =
873                                 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 
874                         /* the file_info buf is endian converted by caller */
875                         pfile_info->AllocationSize =
876                                 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
877                         pfile_info->EndOfFile = pfile_info->AllocationSize;
878                         pfile_info->NumberOfLinks = cpu_to_le32(1);
879                 }
880         }
881
882         cifs_buf_release(pSMB);
883         if (rc == -EAGAIN)
884                 goto OldOpenRetry;
885         return rc;
886 }
887
888 int
889 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
890             const char *fileName, const int openDisposition,
891             const int access_flags, const int create_options, __u16 * netfid,
892             int *pOplock, FILE_ALL_INFO * pfile_info, 
893             const struct nls_table *nls_codepage, int remap)
894 {
895         int rc = -EACCES;
896         OPEN_REQ *pSMB = NULL;
897         OPEN_RSP *pSMBr = NULL;
898         int bytes_returned;
899         int name_len;
900         __u16 count;
901
902 openRetry:
903         rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
904                       (void **) &pSMBr);
905         if (rc)
906                 return rc;
907
908         pSMB->AndXCommand = 0xFF;       /* none */
909
910         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
911                 count = 1;      /* account for one byte pad to word boundary */
912                 name_len =
913                     cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
914                                      fileName, PATH_MAX, nls_codepage, remap);
915                 name_len++;     /* trailing null */
916                 name_len *= 2;
917                 pSMB->NameLength = cpu_to_le16(name_len);
918         } else {                /* BB improve check for buffer overruns BB */
919                 count = 0;      /* no pad */
920                 name_len = strnlen(fileName, PATH_MAX);
921                 name_len++;     /* trailing null */
922                 pSMB->NameLength = cpu_to_le16(name_len);
923                 strncpy(pSMB->fileName, fileName, name_len);
924         }
925         if (*pOplock & REQ_OPLOCK)
926                 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
927         else if (*pOplock & REQ_BATCHOPLOCK) {
928                 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
929         }
930         pSMB->DesiredAccess = cpu_to_le32(access_flags);
931         pSMB->AllocationSize = 0;
932         /* set file as system file if special file such
933            as fifo and server expecting SFU style and
934            no Unix extensions */
935         if(create_options & CREATE_OPTION_SPECIAL)
936                 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
937         else
938                 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
939         /* XP does not handle ATTR_POSIX_SEMANTICS */
940         /* but it helps speed up case sensitive checks for other
941         servers such as Samba */
942         if (tcon->ses->capabilities & CAP_UNIX)
943                 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
944
945         /* if ((omode & S_IWUGO) == 0)
946                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
947         /*  Above line causes problems due to vfs splitting create into two
948                 pieces - need to set mode after file created not while it is
949                 being created */
950         pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
951         pSMB->CreateDisposition = cpu_to_le32(openDisposition);
952         pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
953         /* BB Expirement with various impersonation levels and verify */
954         pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
955         pSMB->SecurityFlags =
956             SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
957
958         count += name_len;
959         pSMB->hdr.smb_buf_length += count;
960
961         pSMB->ByteCount = cpu_to_le16(count);
962         /* long_op set to 1 to allow for oplock break timeouts */
963         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
964                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
965         cifs_stats_inc(&tcon->num_opens);
966         if (rc) {
967                 cFYI(1, ("Error in Open = %d", rc));
968         } else {
969                 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
970                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
971                 /* Let caller know file was created so we can set the mode. */
972                 /* Do we care about the CreateAction in any other cases? */
973                 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
974                         *pOplock |= CIFS_CREATE_ACTION; 
975                 if(pfile_info) {
976                     memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
977                         36 /* CreationTime to Attributes */);
978                     /* the file_info buf is endian converted by caller */
979                     pfile_info->AllocationSize = pSMBr->AllocationSize;
980                     pfile_info->EndOfFile = pSMBr->EndOfFile;
981                     pfile_info->NumberOfLinks = cpu_to_le32(1);
982                 }
983         }
984
985         cifs_buf_release(pSMB);
986         if (rc == -EAGAIN)
987                 goto openRetry;
988         return rc;
989 }
990
991 int
992 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
993             const int netfid, const unsigned int count,
994             const __u64 lseek, unsigned int *nbytes, char **buf,
995             int * pbuf_type)
996 {
997         int rc = -EACCES;
998         READ_REQ *pSMB = NULL;
999         READ_RSP *pSMBr = NULL;
1000         char *pReadData = NULL;
1001         int wct;
1002         int resp_buf_type = 0;
1003         struct kvec iov[1];
1004
1005         cFYI(1,("Reading %d bytes on fid %d",count,netfid));
1006         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1007                 wct = 12;
1008         else
1009                 wct = 10; /* old style read */
1010
1011         *nbytes = 0;
1012         rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1013         if (rc)
1014                 return rc;
1015
1016         /* tcon and ses pointer are checked in smb_init */
1017         if (tcon->ses->server == NULL)
1018                 return -ECONNABORTED;
1019
1020         pSMB->AndXCommand = 0xFF;       /* none */
1021         pSMB->Fid = netfid;
1022         pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1023         if(wct == 12)
1024                 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1025         else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1026                 return -EIO;
1027
1028         pSMB->Remaining = 0;
1029         pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1030         pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1031         if(wct == 12)
1032                 pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
1033         else {
1034                 /* old style read */
1035                 struct smb_com_readx_req * pSMBW =
1036                         (struct smb_com_readx_req *)pSMB;
1037                 pSMBW->ByteCount = 0;
1038         }
1039
1040         iov[0].iov_base = (char *)pSMB;
1041         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1042         rc = SendReceive2(xid, tcon->ses, iov, 
1043                           1 /* num iovecs */,
1044                           &resp_buf_type, 0); 
1045         cifs_stats_inc(&tcon->num_reads);
1046         pSMBr = (READ_RSP *)iov[0].iov_base;
1047         if (rc) {
1048                 cERROR(1, ("Send error in read = %d", rc));
1049         } else {
1050                 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1051                 data_length = data_length << 16;
1052                 data_length += le16_to_cpu(pSMBr->DataLength);
1053                 *nbytes = data_length;
1054
1055                 /*check that DataLength would not go beyond end of SMB */
1056                 if ((data_length > CIFSMaxBufSize)
1057                                 || (data_length > count)) {
1058                         cFYI(1,("bad length %d for count %d",data_length,count));
1059                         rc = -EIO;
1060                         *nbytes = 0;
1061                 } else {
1062                         pReadData = (char *) (&pSMBr->hdr.Protocol) +
1063                             le16_to_cpu(pSMBr->DataOffset);
1064 /*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
1065                                 cERROR(1,("Faulting on read rc = %d",rc));
1066                                 rc = -EFAULT;
1067                         }*/ /* can not use copy_to_user when using page cache*/
1068                         if(*buf)
1069                                 memcpy(*buf,pReadData,data_length);
1070                 }
1071         }
1072
1073 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1074         if(*buf) {
1075                 if(resp_buf_type == CIFS_SMALL_BUFFER)
1076                         cifs_small_buf_release(iov[0].iov_base);
1077                 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1078                         cifs_buf_release(iov[0].iov_base);
1079         } else if(resp_buf_type != CIFS_NO_BUFFER) {
1080                 /* return buffer to caller to free */ 
1081                 *buf = iov[0].iov_base;         
1082                 if(resp_buf_type == CIFS_SMALL_BUFFER)
1083                         *pbuf_type = CIFS_SMALL_BUFFER;
1084                 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1085                         *pbuf_type = CIFS_LARGE_BUFFER;
1086         } /* else no valid buffer on return - leave as null */
1087
1088         /* Note: On -EAGAIN error only caller can retry on handle based calls
1089                 since file handle passed in no longer valid */
1090         return rc;
1091 }
1092
1093
1094 int
1095 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1096              const int netfid, const unsigned int count,
1097              const __u64 offset, unsigned int *nbytes, const char *buf,
1098              const char __user * ubuf, const int long_op)
1099 {
1100         int rc = -EACCES;
1101         WRITE_REQ *pSMB = NULL;
1102         WRITE_RSP *pSMBr = NULL;
1103         int bytes_returned, wct;
1104         __u32 bytes_sent;
1105         __u16 byte_count;
1106
1107         /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1108         if(tcon->ses == NULL)
1109                 return -ECONNABORTED;
1110
1111         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1112                 wct = 14;
1113         else
1114                 wct = 12;
1115
1116         rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1117                       (void **) &pSMBr);
1118         if (rc)
1119                 return rc;
1120         /* tcon and ses pointer are checked in smb_init */
1121         if (tcon->ses->server == NULL)
1122                 return -ECONNABORTED;
1123
1124         pSMB->AndXCommand = 0xFF;       /* none */
1125         pSMB->Fid = netfid;
1126         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1127         if(wct == 14) 
1128                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1129         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1130                 return -EIO;
1131         
1132         pSMB->Reserved = 0xFFFFFFFF;
1133         pSMB->WriteMode = 0;
1134         pSMB->Remaining = 0;
1135
1136         /* Can increase buffer size if buffer is big enough in some cases - ie we 
1137         can send more if LARGE_WRITE_X capability returned by the server and if
1138         our buffer is big enough or if we convert to iovecs on socket writes
1139         and eliminate the copy to the CIFS buffer */
1140         if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1141                 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1142         } else {
1143                 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1144                          & ~0xFF;
1145         }
1146
1147         if (bytes_sent > count)
1148                 bytes_sent = count;
1149         pSMB->DataOffset =
1150                 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1151         if(buf)
1152             memcpy(pSMB->Data,buf,bytes_sent);
1153         else if(ubuf) {
1154                 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1155                         cifs_buf_release(pSMB);
1156                         return -EFAULT;
1157                 }
1158         } else if (count != 0) {
1159                 /* No buffer */
1160                 cifs_buf_release(pSMB);
1161                 return -EINVAL;
1162         } /* else setting file size with write of zero bytes */
1163         if(wct == 14)
1164                 byte_count = bytes_sent + 1; /* pad */
1165         else /* wct == 12 */ {
1166                 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1167         }
1168         pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1169         pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1170         pSMB->hdr.smb_buf_length += byte_count;
1171
1172         if(wct == 14)
1173                 pSMB->ByteCount = cpu_to_le16(byte_count);
1174         else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
1175                 struct smb_com_writex_req * pSMBW = 
1176                         (struct smb_com_writex_req *)pSMB;
1177                 pSMBW->ByteCount = cpu_to_le16(byte_count);
1178         }
1179
1180         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1181                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1182         cifs_stats_inc(&tcon->num_writes);
1183         if (rc) {
1184                 cFYI(1, ("Send error in write = %d", rc));
1185                 *nbytes = 0;
1186         } else {
1187                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1188                 *nbytes = (*nbytes) << 16;
1189                 *nbytes += le16_to_cpu(pSMBr->Count);
1190         }
1191
1192         cifs_buf_release(pSMB);
1193
1194         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1195                 since file handle passed in no longer valid */
1196
1197         return rc;
1198 }
1199
1200 int
1201 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1202              const int netfid, const unsigned int count,
1203              const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1204              int n_vec, const int long_op)
1205 {
1206         int rc = -EACCES;
1207         WRITE_REQ *pSMB = NULL;
1208         int wct;
1209         int smb_hdr_len;
1210         int resp_buf_type = 0;
1211
1212         cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1213
1214         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1215                 wct = 14;
1216         else
1217                 wct = 12;
1218         rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1219         if (rc)
1220                 return rc;
1221         /* tcon and ses pointer are checked in smb_init */
1222         if (tcon->ses->server == NULL)
1223                 return -ECONNABORTED;
1224
1225         pSMB->AndXCommand = 0xFF;       /* none */
1226         pSMB->Fid = netfid;
1227         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1228         if(wct == 14)
1229                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1230         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1231                 return -EIO;
1232         pSMB->Reserved = 0xFFFFFFFF;
1233         pSMB->WriteMode = 0;
1234         pSMB->Remaining = 0;
1235
1236         pSMB->DataOffset =
1237             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1238
1239         pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1240         pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1241         smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1242         if(wct == 14)
1243                 pSMB->hdr.smb_buf_length += count+1;
1244         else /* wct == 12 */
1245                 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ 
1246         if(wct == 14)
1247                 pSMB->ByteCount = cpu_to_le16(count + 1);
1248         else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1249                 struct smb_com_writex_req * pSMBW =
1250                                 (struct smb_com_writex_req *)pSMB;
1251                 pSMBW->ByteCount = cpu_to_le16(count + 5);
1252         }
1253         iov[0].iov_base = pSMB;
1254         if(wct == 14)
1255                 iov[0].iov_len = smb_hdr_len + 4;
1256         else /* wct == 12 pad bigger by four bytes */
1257                 iov[0].iov_len = smb_hdr_len + 8;
1258         
1259
1260         rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1261                           long_op);
1262         cifs_stats_inc(&tcon->num_writes);
1263         if (rc) {
1264                 cFYI(1, ("Send error Write2 = %d", rc));
1265                 *nbytes = 0;
1266         } else if(resp_buf_type == 0) {
1267                 /* presumably this can not happen, but best to be safe */
1268                 rc = -EIO;
1269                 *nbytes = 0;
1270         } else {
1271                 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1272                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1273                 *nbytes = (*nbytes) << 16;
1274                 *nbytes += le16_to_cpu(pSMBr->Count);
1275         } 
1276
1277 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1278         if(resp_buf_type == CIFS_SMALL_BUFFER)
1279                 cifs_small_buf_release(iov[0].iov_base);
1280         else if(resp_buf_type == CIFS_LARGE_BUFFER)
1281                 cifs_buf_release(iov[0].iov_base);
1282
1283         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1284                 since file handle passed in no longer valid */
1285
1286         return rc;
1287 }
1288
1289
1290 int
1291 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1292             const __u16 smb_file_id, const __u64 len,
1293             const __u64 offset, const __u32 numUnlock,
1294             const __u32 numLock, const __u8 lockType, const int waitFlag)
1295 {
1296         int rc = 0;
1297         LOCK_REQ *pSMB = NULL;
1298         LOCK_RSP *pSMBr = NULL;
1299         int bytes_returned;
1300         int timeout = 0;
1301         __u16 count;
1302
1303         cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1304         rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1305
1306         if (rc)
1307                 return rc;
1308
1309         pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1310
1311         if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1312                 timeout = -1; /* no response expected */
1313                 pSMB->Timeout = 0;
1314         } else if (waitFlag == TRUE) {
1315                 timeout = 3;  /* blocking operation, no timeout */
1316                 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1317         } else {
1318                 pSMB->Timeout = 0;
1319         }
1320
1321         pSMB->NumberOfLocks = cpu_to_le16(numLock);
1322         pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1323         pSMB->LockType = lockType;
1324         pSMB->AndXCommand = 0xFF;       /* none */
1325         pSMB->Fid = smb_file_id; /* netfid stays le */
1326
1327         if((numLock != 0) || (numUnlock != 0)) {
1328                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1329                 /* BB where to store pid high? */
1330                 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1331                 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1332                 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1333                 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1334                 count = sizeof(LOCKING_ANDX_RANGE);
1335         } else {
1336                 /* oplock break */
1337                 count = 0;
1338         }
1339         pSMB->hdr.smb_buf_length += count;
1340         pSMB->ByteCount = cpu_to_le16(count);
1341
1342         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1343                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1344         cifs_stats_inc(&tcon->num_locks);
1345         if (rc) {
1346                 cFYI(1, ("Send error in Lock = %d", rc));
1347         }
1348         cifs_small_buf_release(pSMB);
1349
1350         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1351         since file handle passed in no longer valid */
1352         return rc;
1353 }
1354
1355 int
1356 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->smallBuf = 0;
3030                         psrch_inf->srch_entries_start = 
3031                                 (char *) &pSMBr->hdr.Protocol + 
3032                                         le16_to_cpu(pSMBr->t2.DataOffset);
3033                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3034                                le16_to_cpu(pSMBr->t2.ParameterOffset));
3035
3036                         if(parms->EndofSearch)
3037                                 psrch_inf->endOfSearch = TRUE;
3038                         else
3039                                 psrch_inf->endOfSearch = FALSE;
3040
3041                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3042                         psrch_inf->index_of_last_entry = 
3043                                 psrch_inf->entries_in_buffer;
3044                         *pnetfid = parms->SearchHandle;
3045                 } else {
3046                         cifs_buf_release(pSMB);
3047                 }
3048         }
3049
3050         return rc;
3051 }
3052
3053 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3054             __u16 searchHandle, struct cifs_search_info * psrch_inf)
3055 {
3056         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3057         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3058         T2_FNEXT_RSP_PARMS * parms;
3059         char *response_data;
3060         int rc = 0;
3061         int bytes_returned, name_len;
3062         __u16 params, byte_count;
3063
3064         cFYI(1, ("In FindNext"));
3065
3066         if(psrch_inf->endOfSearch == TRUE)
3067                 return -ENOENT;
3068
3069         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3070                 (void **) &pSMBr);
3071         if (rc)
3072                 return rc;
3073
3074         params = 14;    /* includes 2 bytes of null string, converted to LE below */
3075         byte_count = 0;
3076         pSMB->TotalDataCount = 0;       /* no EAs */
3077         pSMB->MaxParameterCount = cpu_to_le16(8);
3078         pSMB->MaxDataCount =
3079             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3080         pSMB->MaxSetupCount = 0;
3081         pSMB->Reserved = 0;
3082         pSMB->Flags = 0;
3083         pSMB->Timeout = 0;
3084         pSMB->Reserved2 = 0;
3085         pSMB->ParameterOffset =  cpu_to_le16(
3086               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3087         pSMB->DataCount = 0;
3088         pSMB->DataOffset = 0;
3089         pSMB->SetupCount = 1;
3090         pSMB->Reserved3 = 0;
3091         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3092         pSMB->SearchHandle = searchHandle;      /* always kept as le */
3093         pSMB->SearchCount =
3094                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3095         /* test for Unix extensions */
3096 /*      if (tcon->ses->capabilities & CAP_UNIX) {
3097                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3098                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3099         } else {
3100                 pSMB->InformationLevel =
3101                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3102                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3103         } */
3104         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3105         pSMB->ResumeKey = psrch_inf->resume_key;
3106         pSMB->SearchFlags =
3107               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3108
3109         name_len = psrch_inf->resume_name_len;
3110         params += name_len;
3111         if(name_len < PATH_MAX) {
3112                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3113                 byte_count += name_len;
3114                 /* 14 byte parm len above enough for 2 byte null terminator */
3115                 pSMB->ResumeFileName[name_len] = 0;
3116                 pSMB->ResumeFileName[name_len+1] = 0;
3117         } else {
3118                 rc = -EINVAL;
3119                 goto FNext2_err_exit;
3120         }
3121         byte_count = params + 1 /* pad */ ;
3122         pSMB->TotalParameterCount = cpu_to_le16(params);
3123         pSMB->ParameterCount = pSMB->TotalParameterCount;
3124         pSMB->hdr.smb_buf_length += byte_count;
3125         pSMB->ByteCount = cpu_to_le16(byte_count);
3126                                                                                               
3127         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3128                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3129         cifs_stats_inc(&tcon->num_fnext);
3130         if (rc) {
3131                 if (rc == -EBADF) {
3132                         psrch_inf->endOfSearch = TRUE;
3133                         rc = 0; /* search probably was closed at end of search above */
3134                 } else
3135                         cFYI(1, ("FindNext returned = %d", rc));
3136         } else {                /* decode response */
3137                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3138                 
3139                 if(rc == 0) {
3140                         /* BB fixme add lock for file (srch_info) struct here */
3141                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3142                                 psrch_inf->unicode = TRUE;
3143                         else
3144                                 psrch_inf->unicode = FALSE;
3145                         response_data = (char *) &pSMBr->hdr.Protocol +
3146                                le16_to_cpu(pSMBr->t2.ParameterOffset);
3147                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
3148                         response_data = (char *)&pSMBr->hdr.Protocol +
3149                                 le16_to_cpu(pSMBr->t2.DataOffset);
3150                         if(psrch_inf->smallBuf)
3151                                 cifs_small_buf_release(
3152                                         psrch_inf->ntwrk_buf_start);
3153                         else
3154                                 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3155                         psrch_inf->srch_entries_start = response_data;
3156                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
3157                         psrch_inf->smallBuf = 0;
3158                         if(parms->EndofSearch)
3159                                 psrch_inf->endOfSearch = TRUE;
3160                         else
3161                                 psrch_inf->endOfSearch = FALSE;
3162                                                                                               
3163                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3164                         psrch_inf->index_of_last_entry +=
3165                                 psrch_inf->entries_in_buffer;
3166 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3167
3168                         /* BB fixme add unlock here */
3169                 }
3170
3171         }
3172
3173         /* BB On error, should we leave previous search buf (and count and
3174         last entry fields) intact or free the previous one? */
3175
3176         /* Note: On -EAGAIN error only caller can retry on handle based calls
3177         since file handle passed in no longer valid */
3178 FNext2_err_exit:
3179         if (rc != 0)
3180                 cifs_buf_release(pSMB);
3181                                                                                               
3182         return rc;
3183 }
3184
3185 int
3186 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3187 {
3188         int rc = 0;
3189         FINDCLOSE_REQ *pSMB = NULL;
3190         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3191         int bytes_returned;
3192
3193         cFYI(1, ("In CIFSSMBFindClose"));
3194         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3195
3196         /* no sense returning error if session restarted
3197                 as file handle has been closed */
3198         if(rc == -EAGAIN)
3199                 return 0;
3200         if (rc)
3201                 return rc;
3202
3203         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
3204         pSMB->FileID = searchHandle;
3205         pSMB->ByteCount = 0;
3206         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3207                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3208         if (rc) {
3209                 cERROR(1, ("Send error in FindClose = %d", rc));
3210         }
3211         cifs_stats_inc(&tcon->num_fclose);
3212         cifs_small_buf_release(pSMB);
3213
3214         /* Since session is dead, search handle closed on server already */
3215         if (rc == -EAGAIN)
3216                 rc = 0;
3217
3218         return rc;
3219 }
3220
3221 int
3222 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3223                 const unsigned char *searchName,
3224                 __u64 * inode_number,
3225                 const struct nls_table *nls_codepage, int remap)
3226 {
3227         int rc = 0;
3228         TRANSACTION2_QPI_REQ *pSMB = NULL;
3229         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3230         int name_len, bytes_returned;
3231         __u16 params, byte_count;
3232
3233         cFYI(1,("In GetSrvInodeNum for %s",searchName));
3234         if(tcon == NULL)
3235                 return -ENODEV; 
3236
3237 GetInodeNumberRetry:
3238         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3239                       (void **) &pSMBr);
3240         if (rc)
3241                 return rc;
3242
3243
3244         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3245                 name_len =
3246                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3247                                 PATH_MAX,nls_codepage, remap);
3248                 name_len++;     /* trailing null */
3249                 name_len *= 2;
3250         } else {                /* BB improve the check for buffer overruns BB */
3251                 name_len = strnlen(searchName, PATH_MAX);
3252                 name_len++;     /* trailing null */
3253                 strncpy(pSMB->FileName, searchName, name_len);
3254         }
3255
3256         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
3257         pSMB->TotalDataCount = 0;
3258         pSMB->MaxParameterCount = cpu_to_le16(2);
3259         /* BB find exact max data count below from sess structure BB */
3260         pSMB->MaxDataCount = cpu_to_le16(4000);
3261         pSMB->MaxSetupCount = 0;
3262         pSMB->Reserved = 0;
3263         pSMB->Flags = 0;
3264         pSMB->Timeout = 0;
3265         pSMB->Reserved2 = 0;
3266         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3267                 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3268         pSMB->DataCount = 0;
3269         pSMB->DataOffset = 0;
3270         pSMB->SetupCount = 1;
3271         pSMB->Reserved3 = 0;
3272         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3273         byte_count = params + 1 /* pad */ ;
3274         pSMB->TotalParameterCount = cpu_to_le16(params);
3275         pSMB->ParameterCount = pSMB->TotalParameterCount;
3276         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3277         pSMB->Reserved4 = 0;
3278         pSMB->hdr.smb_buf_length += byte_count;
3279         pSMB->ByteCount = cpu_to_le16(byte_count);
3280
3281         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3282                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3283         if (rc) {
3284                 cFYI(1, ("error %d in QueryInternalInfo", rc));
3285         } else {
3286                 /* decode response */
3287                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3288                 if (rc || (pSMBr->ByteCount < 2))
3289                 /* BB also check enough total bytes returned */
3290                         /* If rc should we check for EOPNOSUPP and
3291                         disable the srvino flag? or in caller? */
3292                         rc = -EIO;      /* bad smb */
3293                 else {
3294                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3295                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3296                         struct file_internal_info * pfinfo;
3297                         /* BB Do we need a cast or hash here ? */
3298                         if(count < 8) {
3299                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3300                                 rc = -EIO;
3301                                 goto GetInodeNumOut;
3302                         }
3303                         pfinfo = (struct file_internal_info *)
3304                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3305                         *inode_number = pfinfo->UniqueId;
3306                 }
3307         }
3308 GetInodeNumOut:
3309         cifs_buf_release(pSMB);
3310         if (rc == -EAGAIN)
3311                 goto GetInodeNumberRetry;
3312         return rc;
3313 }
3314
3315 int
3316 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3317                 const unsigned char *searchName,
3318                 unsigned char **targetUNCs,
3319                 unsigned int *number_of_UNC_in_array,
3320                 const struct nls_table *nls_codepage, int remap)
3321 {
3322 /* TRANS2_GET_DFS_REFERRAL */
3323         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3324         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3325         struct dfs_referral_level_3 * referrals = NULL;
3326         int rc = 0;
3327         int bytes_returned;
3328         int name_len;
3329         unsigned int i;
3330         char * temp;
3331         __u16 params, byte_count;
3332         *number_of_UNC_in_array = 0;
3333         *targetUNCs = NULL;
3334
3335         cFYI(1, ("In GetDFSRefer the path %s", searchName));
3336         if (ses == NULL)
3337                 return -ENODEV;
3338 getDFSRetry:
3339         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3340                       (void **) &pSMBr);
3341         if (rc)
3342                 return rc;
3343         
3344         /* server pointer checked in called function, 
3345         but should never be null here anyway */
3346         pSMB->hdr.Mid = GetNextMid(ses->server);
3347         pSMB->hdr.Tid = ses->ipc_tid;
3348         pSMB->hdr.Uid = ses->Suid;
3349         if (ses->capabilities & CAP_STATUS32) {
3350                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3351         }
3352         if (ses->capabilities & CAP_DFS) {
3353                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3354         }
3355
3356         if (ses->capabilities & CAP_UNICODE) {
3357                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3358                 name_len =
3359                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3360                                      searchName, PATH_MAX, nls_codepage, remap);
3361                 name_len++;     /* trailing null */
3362                 name_len *= 2;
3363         } else {                /* BB improve the check for buffer overruns BB */
3364                 name_len = strnlen(searchName, PATH_MAX);
3365                 name_len++;     /* trailing null */
3366                 strncpy(pSMB->RequestFileName, searchName, name_len);
3367         }
3368
3369         params = 2 /* level */  + name_len /*includes null */ ;
3370         pSMB->TotalDataCount = 0;
3371         pSMB->DataCount = 0;
3372         pSMB->DataOffset = 0;
3373         pSMB->MaxParameterCount = 0;
3374         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3375         pSMB->MaxSetupCount = 0;
3376         pSMB->Reserved = 0;
3377         pSMB->Flags = 0;
3378         pSMB->Timeout = 0;
3379         pSMB->Reserved2 = 0;
3380         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3381         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3382         pSMB->SetupCount = 1;
3383         pSMB->Reserved3 = 0;
3384         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3385         byte_count = params + 3 /* pad */ ;
3386         pSMB->ParameterCount = cpu_to_le16(params);
3387         pSMB->TotalParameterCount = pSMB->ParameterCount;
3388         pSMB->MaxReferralLevel = cpu_to_le16(3);
3389         pSMB->hdr.smb_buf_length += byte_count;
3390         pSMB->ByteCount = cpu_to_le16(byte_count);
3391
3392         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3393                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3394         if (rc) {
3395                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3396         } else {                /* decode response */
3397 /* BB Add logic to parse referrals here */
3398                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3399
3400                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
3401                         rc = -EIO;      /* bad smb */
3402                 else {
3403                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
3404                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3405
3406                         cFYI(1,
3407                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
3408                               pSMBr->ByteCount, data_offset));
3409                         referrals = 
3410                             (struct dfs_referral_level_3 *) 
3411                                         (8 /* sizeof start of data block */ +
3412                                         data_offset +
3413                                         (char *) &pSMBr->hdr.Protocol); 
3414                         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",
3415                                 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)));
3416                         /* BB This field is actually two bytes in from start of
3417                            data block so we could do safety check that DataBlock
3418                            begins at address of pSMBr->NumberOfReferrals */
3419                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3420
3421                         /* BB Fix below so can return more than one referral */
3422                         if(*number_of_UNC_in_array > 1)
3423                                 *number_of_UNC_in_array = 1;
3424
3425                         /* get the length of the strings describing refs */
3426                         name_len = 0;
3427                         for(i=0;i<*number_of_UNC_in_array;i++) {
3428                                 /* make sure that DfsPathOffset not past end */
3429                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3430                                 if (offset > data_count) {
3431                                         /* if invalid referral, stop here and do 
3432                                         not try to copy any more */
3433                                         *number_of_UNC_in_array = i;
3434                                         break;
3435                                 } 
3436                                 temp = ((char *)referrals) + offset;
3437
3438                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3439                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
3440                                 } else {
3441                                         name_len += strnlen(temp,data_count);
3442                                 }
3443                                 referrals++;
3444                                 /* BB add check that referral pointer does not fall off end PDU */
3445                                 
3446                         }
3447                         /* BB add check for name_len bigger than bcc */
3448                         *targetUNCs = 
3449                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3450                         if(*targetUNCs == NULL) {
3451                                 rc = -ENOMEM;
3452                                 goto GetDFSRefExit;
3453                         }
3454                         /* copy the ref strings */
3455                         referrals =  
3456                             (struct dfs_referral_level_3 *) 
3457                                         (8 /* sizeof data hdr */ +
3458                                         data_offset + 
3459                                         (char *) &pSMBr->hdr.Protocol);
3460
3461                         for(i=0;i<*number_of_UNC_in_array;i++) {
3462                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3463                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3464                                         cifs_strfromUCS_le(*targetUNCs,
3465                                                 (__le16 *) temp, name_len, nls_codepage);
3466                                 } else {
3467                                         strncpy(*targetUNCs,temp,name_len);
3468                                 }
3469                                 /*  BB update target_uncs pointers */
3470                                 referrals++;
3471                         }
3472                         temp = *targetUNCs;
3473                         temp[name_len] = 0;
3474                 }
3475
3476         }
3477 GetDFSRefExit:
3478         if (pSMB)
3479                 cifs_buf_release(pSMB);
3480
3481         if (rc == -EAGAIN)
3482                 goto getDFSRetry;
3483
3484         return rc;
3485 }
3486
3487 /* Query File System Info such as free space to old servers such as Win 9x */
3488 int
3489 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3490 {
3491 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3492         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3493         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3494         FILE_SYSTEM_ALLOC_INFO *response_data;
3495         int rc = 0;
3496         int bytes_returned = 0;
3497         __u16 params, byte_count;
3498
3499         cFYI(1, ("OldQFSInfo"));
3500 oldQFSInfoRetry:
3501         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3502                 (void **) &pSMBr);
3503         if (rc)
3504                 return rc;
3505         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3506                       (void **) &pSMBr);
3507         if (rc)
3508                 return rc;
3509
3510         params = 2;     /* level */
3511         pSMB->TotalDataCount = 0;
3512         pSMB->MaxParameterCount = cpu_to_le16(2);
3513         pSMB->MaxDataCount = cpu_to_le16(1000);
3514         pSMB->MaxSetupCount = 0;
3515         pSMB->Reserved = 0;
3516         pSMB->Flags = 0;
3517         pSMB->Timeout = 0;
3518         pSMB->Reserved2 = 0;
3519         byte_count = params + 1 /* pad */ ;
3520         pSMB->TotalParameterCount = cpu_to_le16(params);
3521         pSMB->ParameterCount = pSMB->TotalParameterCount;
3522         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3523         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3524         pSMB->DataCount = 0;
3525         pSMB->DataOffset = 0;
3526         pSMB->SetupCount = 1;
3527         pSMB->Reserved3 = 0;
3528         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3529         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3530         pSMB->hdr.smb_buf_length += byte_count;
3531         pSMB->ByteCount = cpu_to_le16(byte_count);
3532
3533         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3534                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3535         if (rc) {
3536                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3537         } else {                /* decode response */
3538                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3539
3540                 if (rc || (pSMBr->ByteCount < 18))
3541                         rc = -EIO;      /* bad smb */
3542                 else {
3543                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3544                         cFYI(1,("qfsinf resp BCC: %d  Offset %d",
3545                                  pSMBr->ByteCount, data_offset));
3546
3547                         response_data =
3548                                 (FILE_SYSTEM_ALLOC_INFO *) 
3549                                 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3550                         FSData->f_bsize =
3551                                 le16_to_cpu(response_data->BytesPerSector) *
3552                                 le32_to_cpu(response_data->
3553                                         SectorsPerAllocationUnit);
3554                         FSData->f_blocks =
3555                                 le32_to_cpu(response_data->TotalAllocationUnits);
3556                         FSData->f_bfree = FSData->f_bavail =
3557                                 le32_to_cpu(response_data->FreeAllocationUnits);
3558                         cFYI(1,
3559                              ("Blocks: %lld  Free: %lld Block size %ld",
3560                               (unsigned long long)FSData->f_blocks,
3561                               (unsigned long long)FSData->f_bfree,
3562                               FSData->f_bsize));
3563                 }
3564         }
3565         cifs_buf_release(pSMB);
3566
3567         if (rc == -EAGAIN)
3568                 goto oldQFSInfoRetry;
3569
3570         return rc;
3571 }
3572
3573 int
3574 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3575 {
3576 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3577         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3578         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3579         FILE_SYSTEM_INFO *response_data;
3580         int rc = 0;
3581         int bytes_returned = 0;
3582         __u16 params, byte_count;
3583
3584         cFYI(1, ("In QFSInfo"));
3585 QFSInfoRetry:
3586         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3587                       (void **) &pSMBr);
3588         if (rc)
3589                 return rc;
3590
3591         params = 2;     /* level */
3592         pSMB->TotalDataCount = 0;
3593         pSMB->MaxParameterCount = cpu_to_le16(2);
3594         pSMB->MaxDataCount = cpu_to_le16(1000);
3595         pSMB->MaxSetupCount = 0;
3596         pSMB->Reserved = 0;
3597         pSMB->Flags = 0;
3598         pSMB->Timeout = 0;
3599         pSMB->Reserved2 = 0;
3600         byte_count = params + 1 /* pad */ ;
3601         pSMB->TotalParameterCount = cpu_to_le16(params);
3602         pSMB->ParameterCount = pSMB->TotalParameterCount;
3603         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3604         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3605         pSMB->DataCount = 0;
3606         pSMB->DataOffset = 0;
3607         pSMB->SetupCount = 1;
3608         pSMB->Reserved3 = 0;
3609         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3610         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3611         pSMB->hdr.smb_buf_length += byte_count;
3612         pSMB->ByteCount = cpu_to_le16(byte_count);
3613
3614         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3615                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3616         if (rc) {
3617                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3618         } else {                /* decode response */
3619                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3620
3621                 if (rc || (pSMBr->ByteCount < 24))
3622                         rc = -EIO;      /* bad smb */
3623                 else {
3624                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3625
3626                         response_data =
3627                             (FILE_SYSTEM_INFO
3628                              *) (((char *) &pSMBr->hdr.Protocol) +
3629                                  data_offset);
3630                         FSData->f_bsize =
3631                             le32_to_cpu(response_data->BytesPerSector) *
3632                             le32_to_cpu(response_data->
3633                                         SectorsPerAllocationUnit);
3634                         FSData->f_blocks =
3635                             le64_to_cpu(response_data->TotalAllocationUnits);
3636                         FSData->f_bfree = FSData->f_bavail =
3637                             le64_to_cpu(response_data->FreeAllocationUnits);
3638                         cFYI(1,
3639                              ("Blocks: %lld  Free: %lld Block size %ld",
3640                               (unsigned long long)FSData->f_blocks,
3641                               (unsigned long long)FSData->f_bfree,
3642                               FSData->f_bsize));
3643                 }
3644         }
3645         cifs_buf_release(pSMB);
3646
3647         if (rc == -EAGAIN)
3648                 goto QFSInfoRetry;
3649
3650         return rc;
3651 }
3652
3653 int
3654 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3655 {
3656 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3657         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3658         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3659         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3660         int rc = 0;
3661         int bytes_returned = 0;
3662         __u16 params, byte_count;
3663
3664         cFYI(1, ("In QFSAttributeInfo"));
3665 QFSAttributeRetry:
3666         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3667                       (void **) &pSMBr);
3668         if (rc)
3669                 return rc;
3670
3671         params = 2;     /* level */
3672         pSMB->TotalDataCount = 0;
3673         pSMB->MaxParameterCount = cpu_to_le16(2);
3674         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3675         pSMB->MaxSetupCount = 0;
3676         pSMB->Reserved = 0;
3677         pSMB->Flags = 0;
3678         pSMB->Timeout = 0;
3679         pSMB->Reserved2 = 0;
3680         byte_count = params + 1 /* pad */ ;
3681         pSMB->TotalParameterCount = cpu_to_le16(params);
3682         pSMB->ParameterCount = pSMB->TotalParameterCount;
3683         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3684         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3685         pSMB->DataCount = 0;
3686         pSMB->DataOffset = 0;
3687         pSMB->SetupCount = 1;
3688         pSMB->Reserved3 = 0;
3689         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3690         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3691         pSMB->hdr.smb_buf_length += byte_count;
3692         pSMB->ByteCount = cpu_to_le16(byte_count);
3693
3694         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3695                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3696         if (rc) {
3697                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3698         } else {                /* decode response */
3699                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3700
3701                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3702                         rc = -EIO;      /* bad smb */
3703                 } else {
3704                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3705                         response_data =
3706                             (FILE_SYSTEM_ATTRIBUTE_INFO
3707                              *) (((char *) &pSMBr->hdr.Protocol) +
3708                                  data_offset);
3709                         memcpy(&tcon->fsAttrInfo, response_data,
3710                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3711                 }
3712         }
3713         cifs_buf_release(pSMB);
3714
3715         if (rc == -EAGAIN)
3716                 goto QFSAttributeRetry;
3717
3718         return rc;
3719 }
3720
3721 int
3722 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3723 {
3724 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3725         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3726         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3727         FILE_SYSTEM_DEVICE_INFO *response_data;
3728         int rc = 0;
3729         int bytes_returned = 0;
3730         __u16 params, byte_count;
3731
3732         cFYI(1, ("In QFSDeviceInfo"));
3733 QFSDeviceRetry:
3734         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3735                       (void **) &pSMBr);
3736         if (rc)
3737                 return rc;
3738
3739         params = 2;     /* level */
3740         pSMB->TotalDataCount = 0;
3741         pSMB->MaxParameterCount = cpu_to_le16(2);
3742         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3743         pSMB->MaxSetupCount = 0;
3744         pSMB->Reserved = 0;
3745         pSMB->Flags = 0;
3746         pSMB->Timeout = 0;
3747         pSMB->Reserved2 = 0;
3748         byte_count = params + 1 /* pad */ ;
3749         pSMB->TotalParameterCount = cpu_to_le16(params);
3750         pSMB->ParameterCount = pSMB->TotalParameterCount;
3751         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3752         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3753
3754         pSMB->DataCount = 0;
3755         pSMB->DataOffset = 0;
3756         pSMB->SetupCount = 1;
3757         pSMB->Reserved3 = 0;
3758         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3759         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3760         pSMB->hdr.smb_buf_length += byte_count;
3761         pSMB->ByteCount = cpu_to_le16(byte_count);
3762
3763         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3764                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3765         if (rc) {
3766                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3767         } else {                /* decode response */
3768                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3769
3770                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3771                         rc = -EIO;      /* bad smb */
3772                 else {
3773                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3774                         response_data =
3775                             (FILE_SYSTEM_DEVICE_INFO *)
3776                                 (((char *) &pSMBr->hdr.Protocol) +
3777                                  data_offset);
3778                         memcpy(&tcon->fsDevInfo, response_data,
3779                                sizeof (FILE_SYSTEM_DEVICE_INFO));
3780                 }
3781         }
3782         cifs_buf_release(pSMB);
3783
3784         if (rc == -EAGAIN)
3785                 goto QFSDeviceRetry;
3786
3787         return rc;
3788 }
3789
3790 int
3791 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3792 {
3793 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
3794         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3795         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3796         FILE_SYSTEM_UNIX_INFO *response_data;
3797         int rc = 0;
3798         int bytes_returned = 0;
3799         __u16 params, byte_count;
3800
3801         cFYI(1, ("In QFSUnixInfo"));
3802 QFSUnixRetry:
3803         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3804                       (void **) &pSMBr);
3805         if (rc)
3806                 return rc;
3807
3808         params = 2;     /* level */
3809         pSMB->TotalDataCount = 0;
3810         pSMB->DataCount = 0;
3811         pSMB->DataOffset = 0;
3812         pSMB->MaxParameterCount = cpu_to_le16(2);
3813         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3814         pSMB->MaxSetupCount = 0;
3815         pSMB->Reserved = 0;
3816         pSMB->Flags = 0;
3817         pSMB->Timeout = 0;
3818         pSMB->Reserved2 = 0;
3819         byte_count = params + 1 /* pad */ ;
3820         pSMB->ParameterCount = cpu_to_le16(params);
3821         pSMB->TotalParameterCount = pSMB->ParameterCount;
3822         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3823         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3824         pSMB->SetupCount = 1;
3825         pSMB->Reserved3 = 0;
3826         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3827         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3828         pSMB->hdr.smb_buf_length += byte_count;
3829         pSMB->ByteCount = cpu_to_le16(byte_count);
3830
3831         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3832                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3833         if (rc) {
3834                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3835         } else {                /* decode response */
3836                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3837
3838                 if (rc || (pSMBr->ByteCount < 13)) {
3839                         rc = -EIO;      /* bad smb */
3840                 } else {
3841                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3842                         response_data =
3843                             (FILE_SYSTEM_UNIX_INFO
3844                              *) (((char *) &pSMBr->hdr.Protocol) +
3845                                  data_offset);
3846                         memcpy(&tcon->fsUnixInfo, response_data,
3847                                sizeof (FILE_SYSTEM_UNIX_INFO));
3848                 }
3849         }
3850         cifs_buf_release(pSMB);
3851
3852         if (rc == -EAGAIN)
3853                 goto QFSUnixRetry;
3854
3855
3856         return rc;
3857 }
3858
3859 int
3860 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3861 {
3862 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
3863         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3864         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3865         int rc = 0;
3866         int bytes_returned = 0;
3867         __u16 params, param_offset, offset, byte_count;
3868
3869         cFYI(1, ("In SETFSUnixInfo"));
3870 SETFSUnixRetry:
3871         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3872                       (void **) &pSMBr);
3873         if (rc)
3874                 return rc;
3875
3876         params = 4;     /* 2 bytes zero followed by info level. */
3877         pSMB->MaxSetupCount = 0;
3878         pSMB->Reserved = 0;
3879         pSMB->Flags = 0;
3880         pSMB->Timeout = 0;
3881         pSMB->Reserved2 = 0;
3882         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3883         offset = param_offset + params;
3884
3885         pSMB->MaxParameterCount = cpu_to_le16(4);
3886         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3887         pSMB->SetupCount = 1;
3888         pSMB->Reserved3 = 0;
3889         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3890         byte_count = 1 /* pad */ + params + 12;
3891
3892         pSMB->DataCount = cpu_to_le16(12);
3893         pSMB->ParameterCount = cpu_to_le16(params);
3894         pSMB->TotalDataCount = pSMB->DataCount;
3895         pSMB->TotalParameterCount = pSMB->ParameterCount;
3896         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3897         pSMB->DataOffset = cpu_to_le16(offset);
3898
3899         /* Params. */
3900         pSMB->FileNum = 0;
3901         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3902
3903         /* Data. */
3904         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3905         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3906         pSMB->ClientUnixCap = cpu_to_le64(cap);
3907
3908         pSMB->hdr.smb_buf_length += byte_count;
3909         pSMB->ByteCount = cpu_to_le16(byte_count);
3910
3911         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3912                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3913         if (rc) {
3914                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3915         } else {                /* decode response */
3916                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3917                 if (rc) {
3918                         rc = -EIO;      /* bad smb */
3919                 }
3920         }
3921         cifs_buf_release(pSMB);
3922
3923         if (rc == -EAGAIN)
3924                 goto SETFSUnixRetry;
3925
3926         return rc;
3927 }
3928
3929
3930
3931 int
3932 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3933                    struct kstatfs *FSData)
3934 {
3935 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
3936         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3937         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3938         FILE_SYSTEM_POSIX_INFO *response_data;
3939         int rc = 0;
3940         int bytes_returned = 0;
3941         __u16 params, byte_count;
3942
3943         cFYI(1, ("In QFSPosixInfo"));
3944 QFSPosixRetry:
3945         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3946                       (void **) &pSMBr);
3947         if (rc)
3948                 return rc;
3949
3950         params = 2;     /* level */
3951         pSMB->TotalDataCount = 0;
3952         pSMB->DataCount = 0;
3953         pSMB->DataOffset = 0;
3954         pSMB->MaxParameterCount = cpu_to_le16(2);
3955         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3956         pSMB->MaxSetupCount = 0;
3957         pSMB->Reserved = 0;
3958         pSMB->Flags = 0;
3959         pSMB->Timeout = 0;
3960         pSMB->Reserved2 = 0;
3961         byte_count = params + 1 /* pad */ ;
3962         pSMB->ParameterCount = cpu_to_le16(params);
3963         pSMB->TotalParameterCount = pSMB->ParameterCount;
3964         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3965         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3966         pSMB->SetupCount = 1;
3967         pSMB->Reserved3 = 0;
3968         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3969         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3970         pSMB->hdr.smb_buf_length += byte_count;
3971         pSMB->ByteCount = cpu_to_le16(byte_count);
3972
3973         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3974                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3975         if (rc) {
3976                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3977         } else {                /* decode response */
3978                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3979
3980                 if (rc || (pSMBr->ByteCount < 13)) {
3981                         rc = -EIO;      /* bad smb */
3982                 } else {
3983                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3984                         response_data =
3985                             (FILE_SYSTEM_POSIX_INFO
3986                              *) (((char *) &pSMBr->hdr.Protocol) +
3987                                  data_offset);
3988                         FSData->f_bsize =
3989                                         le32_to_cpu(response_data->BlockSize);
3990                         FSData->f_blocks =
3991                                         le64_to_cpu(response_data->TotalBlocks);
3992                         FSData->f_bfree =
3993                             le64_to_cpu(response_data->BlocksAvail);
3994                         if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
3995                                 FSData->f_bavail = FSData->f_bfree;
3996                         } else {
3997                                 FSData->f_bavail =
3998                                         le64_to_cpu(response_data->UserBlocksAvail);
3999                         }
4000                         if(response_data->TotalFileNodes != cpu_to_le64(-1))
4001                                 FSData->f_files =
4002                                         le64_to_cpu(response_data->TotalFileNodes);
4003                         if(response_data->FreeFileNodes != cpu_to_le64(-1))
4004                                 FSData->f_ffree =
4005                                         le64_to_cpu(response_data->FreeFileNodes);
4006                 }
4007         }
4008         cifs_buf_release(pSMB);
4009
4010         if (rc == -EAGAIN)
4011                 goto QFSPosixRetry;
4012
4013         return rc;
4014 }
4015
4016
4017 /* We can not use write of zero bytes trick to 
4018    set file size due to need for large file support.  Also note that 
4019    this SetPathInfo is preferred to SetFileInfo based method in next 
4020    routine which is only needed to work around a sharing violation bug
4021    in Samba which this routine can run into */
4022
4023 int
4024 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4025               __u64 size, int SetAllocation, 
4026               const struct nls_table *nls_codepage, int remap)
4027 {
4028         struct smb_com_transaction2_spi_req *pSMB = NULL;
4029         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4030         struct file_end_of_file_info *parm_data;
4031         int name_len;
4032         int rc = 0;
4033         int bytes_returned = 0;
4034         __u16 params, byte_count, data_count, param_offset, offset;
4035
4036         cFYI(1, ("In SetEOF"));
4037 SetEOFRetry:
4038         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4039                       (void **) &pSMBr);
4040         if (rc)
4041                 return rc;
4042
4043         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4044                 name_len =
4045                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4046                                      PATH_MAX, nls_codepage, remap);
4047                 name_len++;     /* trailing null */
4048                 name_len *= 2;
4049         } else {        /* BB improve the check for buffer overruns BB */
4050                 name_len = strnlen(fileName, PATH_MAX);
4051                 name_len++;     /* trailing null */
4052                 strncpy(pSMB->FileName, fileName, name_len);
4053         }
4054         params = 6 + name_len;
4055         data_count = sizeof (struct file_end_of_file_info);
4056         pSMB->MaxParameterCount = cpu_to_le16(2);
4057         pSMB->MaxDataCount = cpu_to_le16(4100);
4058         pSMB->MaxSetupCount = 0;
4059         pSMB->Reserved = 0;
4060         pSMB->Flags = 0;
4061         pSMB->Timeout = 0;
4062         pSMB->Reserved2 = 0;
4063         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4064                                      InformationLevel) - 4;
4065         offset = param_offset + params;
4066         if(SetAllocation) {
4067                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4068                     pSMB->InformationLevel =
4069                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4070                 else
4071                     pSMB->InformationLevel =
4072                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4073         } else /* Set File Size */  {    
4074             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4075                     pSMB->InformationLevel =
4076                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4077             else
4078                     pSMB->InformationLevel =
4079                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4080         }
4081
4082         parm_data =
4083             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4084                                        offset);
4085         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4086         pSMB->DataOffset = cpu_to_le16(offset);
4087         pSMB->SetupCount = 1;
4088         pSMB->Reserved3 = 0;
4089         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4090         byte_count = 3 /* pad */  + params + data_count;
4091         pSMB->DataCount = cpu_to_le16(data_count);
4092         pSMB->TotalDataCount = pSMB->DataCount;
4093         pSMB->ParameterCount = cpu_to_le16(params);
4094         pSMB->TotalParameterCount = pSMB->ParameterCount;
4095         pSMB->Reserved4 = 0;
4096         pSMB->hdr.smb_buf_length += byte_count;
4097         parm_data->FileSize = cpu_to_le64(size);
4098         pSMB->ByteCount = cpu_to_le16(byte_count);
4099         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4100                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4101         if (rc) {
4102                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4103         }
4104
4105         cifs_buf_release(pSMB);
4106
4107         if (rc == -EAGAIN)
4108                 goto SetEOFRetry;
4109
4110         return rc;
4111 }
4112
4113 int
4114 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
4115                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
4116 {
4117         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4118         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4119         char *data_offset;
4120         struct file_end_of_file_info *parm_data;
4121         int rc = 0;
4122         int bytes_returned = 0;
4123         __u16 params, param_offset, offset, byte_count, count;
4124
4125         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4126                         (long long)size));
4127         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4128
4129         if (rc)
4130                 return rc;
4131
4132         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4133
4134         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4135         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4136     
4137         params = 6;
4138         pSMB->MaxSetupCount = 0;
4139         pSMB->Reserved = 0;
4140         pSMB->Flags = 0;
4141         pSMB->Timeout = 0;
4142         pSMB->Reserved2 = 0;
4143         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4144         offset = param_offset + params;
4145
4146         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
4147
4148         count = sizeof(struct file_end_of_file_info);
4149         pSMB->MaxParameterCount = cpu_to_le16(2);
4150         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4151         pSMB->SetupCount = 1;
4152         pSMB->Reserved3 = 0;
4153         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4154         byte_count = 3 /* pad */  + params + count;
4155         pSMB->DataCount = cpu_to_le16(count);
4156         pSMB->ParameterCount = cpu_to_le16(params);
4157         pSMB->TotalDataCount = pSMB->DataCount;
4158         pSMB->TotalParameterCount = pSMB->ParameterCount;
4159         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4160         parm_data =
4161                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4162                         offset);
4163         pSMB->DataOffset = cpu_to_le16(offset);
4164         parm_data->FileSize = cpu_to_le64(size);
4165         pSMB->Fid = fid;
4166         if(SetAllocation) {
4167                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4168                         pSMB->InformationLevel =
4169                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4170                 else
4171                         pSMB->InformationLevel =
4172                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4173         } else /* Set File Size */  {    
4174             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4175                     pSMB->InformationLevel =
4176                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4177             else
4178                     pSMB->InformationLevel =
4179                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4180         }
4181         pSMB->Reserved4 = 0;
4182         pSMB->hdr.smb_buf_length += byte_count;
4183         pSMB->ByteCount = cpu_to_le16(byte_count);
4184         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4185                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4186         if (rc) {
4187                 cFYI(1,
4188                      ("Send error in SetFileInfo (SetFileSize) = %d",
4189                       rc));
4190         }
4191
4192         if (pSMB)
4193                 cifs_small_buf_release(pSMB);
4194
4195         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4196                 since file handle passed in no longer valid */
4197
4198         return rc;
4199 }
4200
4201 /* Some legacy servers such as NT4 require that the file times be set on 
4202    an open handle, rather than by pathname - this is awkward due to
4203    potential access conflicts on the open, but it is unavoidable for these
4204    old servers since the only other choice is to go from 100 nanosecond DCE
4205    time and resort to the original setpathinfo level which takes the ancient
4206    DOS time format with 2 second granularity */
4207 int
4208 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
4209                    __u16 fid)
4210 {
4211         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4212         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4213         char *data_offset;
4214         int rc = 0;
4215         int bytes_returned = 0;
4216         __u16 params, param_offset, offset, byte_count, count;
4217
4218         cFYI(1, ("Set Times (via SetFileInfo)"));
4219         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4220
4221         if (rc)
4222                 return rc;
4223
4224         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4225
4226         /* At this point there is no need to override the current pid
4227         with the pid of the opener, but that could change if we someday
4228         use an existing handle (rather than opening one on the fly) */
4229         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4230         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4231     
4232         params = 6;
4233         pSMB->MaxSetupCount = 0;
4234         pSMB->Reserved = 0;
4235         pSMB->Flags = 0;
4236         pSMB->Timeout = 0;
4237         pSMB->Reserved2 = 0;
4238         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4239         offset = param_offset + params;
4240
4241         data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
4242
4243         count = sizeof (FILE_BASIC_INFO);
4244         pSMB->MaxParameterCount = cpu_to_le16(2);
4245         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4246         pSMB->SetupCount = 1;
4247         pSMB->Reserved3 = 0;
4248         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4249         byte_count = 3 /* pad */  + params + count;
4250         pSMB->DataCount = cpu_to_le16(count);
4251         pSMB->ParameterCount = cpu_to_le16(params);
4252         pSMB->TotalDataCount = pSMB->DataCount;
4253         pSMB->TotalParameterCount = pSMB->ParameterCount;
4254         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4255         pSMB->DataOffset = cpu_to_le16(offset);
4256         pSMB->Fid = fid;
4257         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4258                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4259         else
4260                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4261         pSMB->Reserved4 = 0;
4262         pSMB->hdr.smb_buf_length += byte_count;
4263         pSMB->ByteCount = cpu_to_le16(byte_count);
4264         memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4265         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4266                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4267         if (rc) {
4268                 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4269         }
4270
4271         cifs_small_buf_release(pSMB);
4272
4273         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4274                 since file handle passed in no longer valid */
4275
4276         return rc;
4277 }
4278
4279
4280 int
4281 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4282                 const FILE_BASIC_INFO * data, 
4283                 const struct nls_table *nls_codepage, int remap)
4284 {
4285         TRANSACTION2_SPI_REQ *pSMB = NULL;
4286         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4287         int name_len;
4288         int rc = 0;
4289         int bytes_returned = 0;
4290         char *data_offset;
4291         __u16 params, param_offset, offset, byte_count, count;
4292
4293         cFYI(1, ("In SetTimes"));
4294
4295 SetTimesRetry:
4296         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4297                       (void **) &pSMBr);
4298         if (rc)
4299                 return rc;
4300
4301         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4302                 name_len =
4303                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4304                                      PATH_MAX, nls_codepage, remap);
4305                 name_len++;     /* trailing null */
4306                 name_len *= 2;
4307         } else {                /* BB improve the check for buffer overruns BB */
4308                 name_len = strnlen(fileName, PATH_MAX);
4309                 name_len++;     /* trailing null */
4310                 strncpy(pSMB->FileName, fileName, name_len);
4311         }
4312
4313         params = 6 + name_len;
4314         count = sizeof (FILE_BASIC_INFO);
4315         pSMB->MaxParameterCount = cpu_to_le16(2);
4316         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4317         pSMB->MaxSetupCount = 0;
4318         pSMB->Reserved = 0;
4319         pSMB->Flags = 0;
4320         pSMB->Timeout = 0;
4321         pSMB->Reserved2 = 0;
4322         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4323                                      InformationLevel) - 4;
4324         offset = param_offset + params;
4325         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4326         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4327         pSMB->DataOffset = cpu_to_le16(offset);
4328         pSMB->SetupCount = 1;
4329         pSMB->Reserved3 = 0;
4330         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4331         byte_count = 3 /* pad */  + params + count;
4332
4333         pSMB->DataCount = cpu_to_le16(count);
4334         pSMB->ParameterCount = cpu_to_le16(params);
4335         pSMB->TotalDataCount = pSMB->DataCount;
4336         pSMB->TotalParameterCount = pSMB->ParameterCount;
4337         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4338                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4339         else
4340                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4341         pSMB->Reserved4 = 0;
4342         pSMB->hdr.smb_buf_length += byte_count;
4343         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4344         pSMB->ByteCount = cpu_to_le16(byte_count);
4345         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4346                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4347         if (rc) {
4348                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4349         }
4350
4351         cifs_buf_release(pSMB);
4352
4353         if (rc == -EAGAIN)
4354                 goto SetTimesRetry;
4355
4356         return rc;
4357 }
4358
4359 /* Can not be used to set time stamps yet (due to old DOS time format) */
4360 /* Can be used to set attributes */
4361 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
4362           handling it anyway and NT4 was what we thought it would be needed for
4363           Do not delete it until we prove whether needed for Win9x though */
4364 int
4365 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4366                 __u16 dos_attrs, const struct nls_table *nls_codepage)
4367 {
4368         SETATTR_REQ *pSMB = NULL;
4369         SETATTR_RSP *pSMBr = NULL;
4370         int rc = 0;
4371         int bytes_returned;
4372         int name_len;
4373
4374         cFYI(1, ("In SetAttrLegacy"));
4375
4376 SetAttrLgcyRetry:
4377         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4378                       (void **) &pSMBr);
4379         if (rc)
4380                 return rc;
4381
4382         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4383                 name_len =
4384                         ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
4385                                 PATH_MAX, nls_codepage);
4386                 name_len++;     /* trailing null */
4387                 name_len *= 2;
4388         } else {                /* BB improve the check for buffer overruns BB */
4389                 name_len = strnlen(fileName, PATH_MAX);
4390                 name_len++;     /* trailing null */
4391                 strncpy(pSMB->fileName, fileName, name_len);
4392         }
4393         pSMB->attr = cpu_to_le16(dos_attrs);
4394         pSMB->BufferFormat = 0x04;
4395         pSMB->hdr.smb_buf_length += name_len + 1;
4396         pSMB->ByteCount = cpu_to_le16(name_len + 1);
4397         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4398                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4399         if (rc) {
4400                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4401         }
4402
4403         cifs_buf_release(pSMB);
4404
4405         if (rc == -EAGAIN)
4406                 goto SetAttrLgcyRetry;
4407
4408         return rc;
4409 }
4410 #endif /* temporarily unneeded SetAttr legacy function */
4411
4412 int
4413 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4414                     char *fileName, __u64 mode, __u64 uid, __u64 gid, 
4415                     dev_t device, const struct nls_table *nls_codepage, 
4416                     int remap)
4417 {
4418         TRANSACTION2_SPI_REQ *pSMB = NULL;
4419         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4420         int name_len;
4421         int rc = 0;
4422         int bytes_returned = 0;
4423         FILE_UNIX_BASIC_INFO *data_offset;
4424         __u16 params, param_offset, offset, count, byte_count;
4425
4426         cFYI(1, ("In SetUID/GID/Mode"));
4427 setPermsRetry:
4428         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4429                       (void **) &pSMBr);
4430         if (rc)
4431                 return rc;
4432
4433         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4434                 name_len =
4435                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4436                                      PATH_MAX, nls_codepage, remap);
4437                 name_len++;     /* trailing null */
4438                 name_len *= 2;
4439         } else {        /* BB improve the check for buffer overruns BB */
4440                 name_len = strnlen(fileName, PATH_MAX);
4441                 name_len++;     /* trailing null */
4442                 strncpy(pSMB->FileName, fileName, name_len);
4443         }
4444
4445         params = 6 + name_len;
4446         count = sizeof (FILE_UNIX_BASIC_INFO);
4447         pSMB->MaxParameterCount = cpu_to_le16(2);
4448         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4449         pSMB->MaxSetupCount = 0;
4450         pSMB->Reserved = 0;
4451         pSMB->Flags = 0;
4452         pSMB->Timeout = 0;
4453         pSMB->Reserved2 = 0;
4454         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4455                                      InformationLevel) - 4;
4456         offset = param_offset + params;
4457         data_offset =
4458             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4459                                       offset);
4460         memset(data_offset, 0, count);
4461         pSMB->DataOffset = cpu_to_le16(offset);
4462         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4463         pSMB->SetupCount = 1;
4464         pSMB->Reserved3 = 0;
4465         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4466         byte_count = 3 /* pad */  + params + count;
4467         pSMB->ParameterCount = cpu_to_le16(params);
4468         pSMB->DataCount = cpu_to_le16(count);
4469         pSMB->TotalParameterCount = pSMB->ParameterCount;
4470         pSMB->TotalDataCount = pSMB->DataCount;
4471         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4472         pSMB->Reserved4 = 0;
4473         pSMB->hdr.smb_buf_length += byte_count;
4474         data_offset->Uid = cpu_to_le64(uid);
4475         data_offset->Gid = cpu_to_le64(gid);
4476         /* better to leave device as zero when it is  */
4477         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4478         data_offset->DevMinor = cpu_to_le64(MINOR(device));
4479         data_offset->Permissions = cpu_to_le64(mode);
4480     
4481         if(S_ISREG(mode))
4482                 data_offset->Type = cpu_to_le32(UNIX_FILE);
4483         else if(S_ISDIR(mode))
4484                 data_offset->Type = cpu_to_le32(UNIX_DIR);
4485         else if(S_ISLNK(mode))
4486                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4487         else if(S_ISCHR(mode))
4488                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4489         else if(S_ISBLK(mode))
4490                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4491         else if(S_ISFIFO(mode))
4492                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4493         else if(S_ISSOCK(mode))
4494                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4495
4496
4497         pSMB->ByteCount = cpu_to_le16(byte_count);
4498         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4499                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4500         if (rc) {
4501                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4502         }
4503
4504         if (pSMB)
4505                 cifs_buf_release(pSMB);
4506         if (rc == -EAGAIN)
4507                 goto setPermsRetry;
4508         return rc;
4509 }
4510
4511 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
4512                   const int notify_subdirs, const __u16 netfid,
4513                   __u32 filter, struct file * pfile, int multishot, 
4514                   const struct nls_table *nls_codepage)
4515 {
4516         int rc = 0;
4517         struct smb_com_transaction_change_notify_req * pSMB = NULL;
4518         struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4519         struct dir_notify_req *dnotify_req;
4520         int bytes_returned;
4521
4522         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4523         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4524                       (void **) &pSMBr);
4525         if (rc)
4526                 return rc;
4527
4528         pSMB->TotalParameterCount = 0 ;
4529         pSMB->TotalDataCount = 0;
4530         pSMB->MaxParameterCount = cpu_to_le32(2);
4531         /* BB find exact data count max from sess structure BB */
4532         pSMB->MaxDataCount = 0; /* same in little endian or be */
4533 /* BB VERIFY verify which is correct for above BB */
4534         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4535                                              MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4536
4537         pSMB->MaxSetupCount = 4;
4538         pSMB->Reserved = 0;
4539         pSMB->ParameterOffset = 0;
4540         pSMB->DataCount = 0;
4541         pSMB->DataOffset = 0;
4542         pSMB->SetupCount = 4; /* single byte does not need le conversion */
4543         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4544         pSMB->ParameterCount = pSMB->TotalParameterCount;
4545         if(notify_subdirs)
4546                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4547         pSMB->Reserved2 = 0;
4548         pSMB->CompletionFilter = cpu_to_le32(filter);
4549         pSMB->Fid = netfid; /* file handle always le */
4550         pSMB->ByteCount = 0;
4551
4552         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4553                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4554         if (rc) {
4555                 cFYI(1, ("Error in Notify = %d", rc));
4556         } else {
4557                 /* Add file to outstanding requests */
4558                 /* BB change to kmem cache alloc */     
4559                 dnotify_req = (struct dir_notify_req *) kmalloc(
4560                                                 sizeof(struct dir_notify_req),
4561                                                  GFP_KERNEL);
4562                 if(dnotify_req) {
4563                         dnotify_req->Pid = pSMB->hdr.Pid;
4564                         dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4565                         dnotify_req->Mid = pSMB->hdr.Mid;
4566                         dnotify_req->Tid = pSMB->hdr.Tid;
4567                         dnotify_req->Uid = pSMB->hdr.Uid;
4568                         dnotify_req->netfid = netfid;
4569                         dnotify_req->pfile = pfile;
4570                         dnotify_req->filter = filter;
4571                         dnotify_req->multishot = multishot;
4572                         spin_lock(&GlobalMid_Lock);
4573                         list_add_tail(&dnotify_req->lhead, 
4574                                         &GlobalDnotifyReqList);
4575                         spin_unlock(&GlobalMid_Lock);
4576                 } else 
4577                         rc = -ENOMEM;
4578         }
4579         cifs_buf_release(pSMB);
4580         return rc;      
4581 }
4582 #ifdef CONFIG_CIFS_XATTR
4583 ssize_t
4584 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4585                  const unsigned char *searchName,
4586                  char * EAData, size_t buf_size,
4587                  const struct nls_table *nls_codepage, int remap)
4588 {
4589                 /* BB assumes one setup word */
4590         TRANSACTION2_QPI_REQ *pSMB = NULL;
4591         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4592         int rc = 0;
4593         int bytes_returned;
4594         int name_len;
4595         struct fea * temp_fea;
4596         char * temp_ptr;
4597         __u16 params, byte_count;
4598
4599         cFYI(1, ("In Query All EAs path %s", searchName));
4600 QAllEAsRetry:
4601         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4602                       (void **) &pSMBr);
4603         if (rc)
4604                 return rc;
4605
4606         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4607                 name_len =
4608                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4609                                      PATH_MAX, nls_codepage, remap);
4610                 name_len++;     /* trailing null */
4611                 name_len *= 2;
4612         } else {        /* BB improve the check for buffer overruns BB */
4613                 name_len = strnlen(searchName, PATH_MAX);
4614                 name_len++;     /* trailing null */
4615                 strncpy(pSMB->FileName, searchName, name_len);
4616         }
4617
4618         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4619         pSMB->TotalDataCount = 0;
4620         pSMB->MaxParameterCount = cpu_to_le16(2);
4621         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4622         pSMB->MaxSetupCount = 0;
4623         pSMB->Reserved = 0;
4624         pSMB->Flags = 0;
4625         pSMB->Timeout = 0;
4626         pSMB->Reserved2 = 0;
4627         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4628         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4629         pSMB->DataCount = 0;
4630         pSMB->DataOffset = 0;
4631         pSMB->SetupCount = 1;
4632         pSMB->Reserved3 = 0;
4633         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4634         byte_count = params + 1 /* pad */ ;
4635         pSMB->TotalParameterCount = cpu_to_le16(params);
4636         pSMB->ParameterCount = pSMB->TotalParameterCount;
4637         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4638         pSMB->Reserved4 = 0;
4639         pSMB->hdr.smb_buf_length += byte_count;
4640         pSMB->ByteCount = cpu_to_le16(byte_count);
4641
4642         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4643                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4644         if (rc) {
4645                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4646         } else {                /* decode response */
4647                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4648
4649                 /* BB also check enough total bytes returned */
4650                 /* BB we need to improve the validity checking
4651                 of these trans2 responses */
4652                 if (rc || (pSMBr->ByteCount < 4)) 
4653                         rc = -EIO;      /* bad smb */
4654            /* else if (pFindData){
4655                         memcpy((char *) pFindData,
4656                                (char *) &pSMBr->hdr.Protocol +
4657                                data_offset, kl);
4658                 }*/ else {
4659                         /* check that length of list is not more than bcc */
4660                         /* check that each entry does not go beyond length
4661                            of list */
4662                         /* check that each element of each entry does not
4663                            go beyond end of list */
4664                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4665                         struct fealist * ea_response_data;
4666                         rc = 0;
4667                         /* validate_trans2_offsets() */
4668                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4669                         ea_response_data = (struct fealist *)
4670                                 (((char *) &pSMBr->hdr.Protocol) +
4671                                 data_offset);
4672                         name_len = le32_to_cpu(ea_response_data->list_len);
4673                         cFYI(1,("ea length %d", name_len));
4674                         if(name_len <= 8) {
4675                         /* returned EA size zeroed at top of function */
4676                                 cFYI(1,("empty EA list returned from server"));
4677                         } else {
4678                                 /* account for ea list len */
4679                                 name_len -= 4;
4680                                 temp_fea = ea_response_data->list;
4681                                 temp_ptr = (char *)temp_fea;
4682                                 while(name_len > 0) {
4683                                         __u16 value_len;
4684                                         name_len -= 4;
4685                                         temp_ptr += 4;
4686                                         rc += temp_fea->name_len;
4687                                 /* account for prefix user. and trailing null */
4688                                         rc = rc + 5 + 1; 
4689                                         if(rc<(int)buf_size) {
4690                                                 memcpy(EAData,"user.",5);
4691                                                 EAData+=5;
4692                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
4693                                                 EAData+=temp_fea->name_len;
4694                                                 /* null terminate name */
4695                                                 *EAData = 0;
4696                                                 EAData = EAData + 1;
4697                                         } else if(buf_size == 0) {
4698                                                 /* skip copy - calc size only */
4699                                         } else {
4700                                                 /* stop before overrun buffer */
4701                                                 rc = -ERANGE;
4702                                                 break;
4703                                         }
4704                                         name_len -= temp_fea->name_len;
4705                                         temp_ptr += temp_fea->name_len;
4706                                         /* account for trailing null */
4707                                         name_len--;
4708                                         temp_ptr++;
4709                                         value_len = le16_to_cpu(temp_fea->value_len);
4710                                         name_len -= value_len;
4711                                         temp_ptr += value_len;
4712                                         /* BB check that temp_ptr is still within smb BB*/
4713                                 /* no trailing null to account for in value len */
4714                                         /* go on to next EA */
4715                                         temp_fea = (struct fea *)temp_ptr;
4716                                 }
4717                         }
4718                 }
4719         }
4720         if (pSMB)
4721                 cifs_buf_release(pSMB);
4722         if (rc == -EAGAIN)
4723                 goto QAllEAsRetry;
4724
4725         return (ssize_t)rc;
4726 }
4727
4728 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4729                 const unsigned char * searchName,const unsigned char * ea_name,
4730                 unsigned char * ea_value, size_t buf_size, 
4731                 const struct nls_table *nls_codepage, int remap)
4732 {
4733         TRANSACTION2_QPI_REQ *pSMB = NULL;
4734         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4735         int rc = 0;
4736         int bytes_returned;
4737         int name_len;
4738         struct fea * temp_fea;
4739         char * temp_ptr;
4740         __u16 params, byte_count;
4741
4742         cFYI(1, ("In Query EA path %s", searchName));
4743 QEARetry:
4744         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4745                       (void **) &pSMBr);
4746         if (rc)
4747                 return rc;
4748
4749         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4750                 name_len =
4751                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4752                                      PATH_MAX, nls_codepage, remap);
4753                 name_len++;     /* trailing null */
4754                 name_len *= 2;
4755         } else {        /* BB improve the check for buffer overruns BB */
4756                 name_len = strnlen(searchName, PATH_MAX);
4757                 name_len++;     /* trailing null */
4758                 strncpy(pSMB->FileName, searchName, name_len);
4759         }
4760
4761         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4762         pSMB->TotalDataCount = 0;
4763         pSMB->MaxParameterCount = cpu_to_le16(2);
4764         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4765         pSMB->MaxSetupCount = 0;
4766         pSMB->Reserved = 0;
4767         pSMB->Flags = 0;
4768         pSMB->Timeout = 0;
4769         pSMB->Reserved2 = 0;
4770         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4771         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4772         pSMB->DataCount = 0;
4773         pSMB->DataOffset = 0;
4774         pSMB->SetupCount = 1;
4775         pSMB->Reserved3 = 0;
4776         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4777         byte_count = params + 1 /* pad */ ;
4778         pSMB->TotalParameterCount = cpu_to_le16(params);
4779         pSMB->ParameterCount = pSMB->TotalParameterCount;
4780         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4781         pSMB->Reserved4 = 0;
4782         pSMB->hdr.smb_buf_length += byte_count;
4783         pSMB->ByteCount = cpu_to_le16(byte_count);
4784
4785         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4786                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4787         if (rc) {
4788                 cFYI(1, ("Send error in Query EA = %d", rc));
4789         } else {                /* decode response */
4790                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4791
4792                 /* BB also check enough total bytes returned */
4793                 /* BB we need to improve the validity checking
4794                 of these trans2 responses */
4795                 if (rc || (pSMBr->ByteCount < 4)) 
4796                         rc = -EIO;      /* bad smb */
4797            /* else if (pFindData){
4798                         memcpy((char *) pFindData,
4799                                (char *) &pSMBr->hdr.Protocol +
4800                                data_offset, kl);
4801                 }*/ else {
4802                         /* check that length of list is not more than bcc */
4803                         /* check that each entry does not go beyond length
4804                            of list */
4805                         /* check that each element of each entry does not
4806                            go beyond end of list */
4807                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4808                         struct fealist * ea_response_data;
4809                         rc = -ENODATA;
4810                         /* validate_trans2_offsets() */
4811                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4812                         ea_response_data = (struct fealist *)
4813                                 (((char *) &pSMBr->hdr.Protocol) +
4814                                 data_offset);
4815                         name_len = le32_to_cpu(ea_response_data->list_len);
4816                         cFYI(1,("ea length %d", name_len));
4817                         if(name_len <= 8) {
4818                         /* returned EA size zeroed at top of function */
4819                                 cFYI(1,("empty EA list returned from server"));
4820                         } else {
4821                                 /* account for ea list len */
4822                                 name_len -= 4;
4823                                 temp_fea = ea_response_data->list;
4824                                 temp_ptr = (char *)temp_fea;
4825                                 /* loop through checking if we have a matching
4826                                 name and then return the associated value */
4827                                 while(name_len > 0) {
4828                                         __u16 value_len;
4829                                         name_len -= 4;
4830                                         temp_ptr += 4;
4831                                         value_len = le16_to_cpu(temp_fea->value_len);
4832                                 /* BB validate that value_len falls within SMB, 
4833                                 even though maximum for name_len is 255 */ 
4834                                         if(memcmp(temp_fea->name,ea_name,
4835                                                   temp_fea->name_len) == 0) {
4836                                                 /* found a match */
4837                                                 rc = value_len;
4838                                 /* account for prefix user. and trailing null */
4839                                                 if(rc<=(int)buf_size) {
4840                                                         memcpy(ea_value,
4841                                                                 temp_fea->name+temp_fea->name_len+1,
4842                                                                 rc);
4843                                                         /* ea values, unlike ea names,
4844                                                         are not null terminated */
4845                                                 } else if(buf_size == 0) {
4846                                                 /* skip copy - calc size only */
4847                                                 } else {
4848                                                         /* stop before overrun buffer */
4849                                                         rc = -ERANGE;
4850                                                 }
4851                                                 break;
4852                                         }
4853                                         name_len -= temp_fea->name_len;
4854                                         temp_ptr += temp_fea->name_len;
4855                                         /* account for trailing null */
4856                                         name_len--;
4857                                         temp_ptr++;
4858                                         name_len -= value_len;
4859                                         temp_ptr += value_len;
4860                                 /* no trailing null to account for in value len */
4861                                         /* go on to next EA */
4862                                         temp_fea = (struct fea *)temp_ptr;
4863                                 }
4864                         } 
4865                 }
4866         }
4867         if (pSMB)
4868                 cifs_buf_release(pSMB);
4869         if (rc == -EAGAIN)
4870                 goto QEARetry;
4871
4872         return (ssize_t)rc;
4873 }
4874
4875 int
4876 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4877                 const char * ea_name, const void * ea_value, 
4878                 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4879                 int remap)
4880 {
4881         struct smb_com_transaction2_spi_req *pSMB = NULL;
4882         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4883         struct fealist *parm_data;
4884         int name_len;
4885         int rc = 0;
4886         int bytes_returned = 0;
4887         __u16 params, param_offset, byte_count, offset, count;
4888
4889         cFYI(1, ("In SetEA"));
4890 SetEARetry:
4891         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4892                       (void **) &pSMBr);
4893         if (rc)
4894                 return rc;
4895
4896         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4897                 name_len =
4898                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4899                                      PATH_MAX, nls_codepage, remap);
4900                 name_len++;     /* trailing null */
4901                 name_len *= 2;
4902         } else {                /* BB improve the check for buffer overruns BB */
4903                 name_len = strnlen(fileName, PATH_MAX);
4904                 name_len++;     /* trailing null */
4905                 strncpy(pSMB->FileName, fileName, name_len);
4906         }
4907
4908         params = 6 + name_len;
4909
4910         /* done calculating parms using name_len of file name,
4911         now use name_len to calculate length of ea name
4912         we are going to create in the inode xattrs */
4913         if(ea_name == NULL)
4914                 name_len = 0;
4915         else
4916                 name_len = strnlen(ea_name,255);
4917
4918         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4919         pSMB->MaxParameterCount = cpu_to_le16(2);
4920         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4921         pSMB->MaxSetupCount = 0;
4922         pSMB->Reserved = 0;
4923         pSMB->Flags = 0;
4924         pSMB->Timeout = 0;
4925         pSMB->Reserved2 = 0;
4926         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4927                                      InformationLevel) - 4;
4928         offset = param_offset + params;
4929         pSMB->InformationLevel =
4930                 cpu_to_le16(SMB_SET_FILE_EA);
4931
4932         parm_data =
4933                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4934                                        offset);
4935         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4936         pSMB->DataOffset = cpu_to_le16(offset);
4937         pSMB->SetupCount = 1;
4938         pSMB->Reserved3 = 0;
4939         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4940         byte_count = 3 /* pad */  + params + count;
4941         pSMB->DataCount = cpu_to_le16(count);
4942         parm_data->list_len = cpu_to_le32(count);
4943         parm_data->list[0].EA_flags = 0;
4944         /* we checked above that name len is less than 255 */
4945         parm_data->list[0].name_len = (__u8)name_len;;
4946         /* EA names are always ASCII */
4947         if(ea_name)
4948                 strncpy(parm_data->list[0].name,ea_name,name_len);
4949         parm_data->list[0].name[name_len] = 0;
4950         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4951         /* caller ensures that ea_value_len is less than 64K but
4952         we need to ensure that it fits within the smb */
4953
4954         /*BB add length check that it would fit in negotiated SMB buffer size BB */
4955         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4956         if(ea_value_len)
4957                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4958
4959         pSMB->TotalDataCount = pSMB->DataCount;
4960         pSMB->ParameterCount = cpu_to_le16(params);
4961         pSMB->TotalParameterCount = pSMB->ParameterCount;
4962         pSMB->Reserved4 = 0;
4963         pSMB->hdr.smb_buf_length += byte_count;
4964         pSMB->ByteCount = cpu_to_le16(byte_count);
4965         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4966                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4967         if (rc) {
4968                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4969         }
4970
4971         cifs_buf_release(pSMB);
4972
4973         if (rc == -EAGAIN)
4974                 goto SetEARetry;
4975
4976         return rc;
4977 }
4978
4979 #endif