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