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