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