]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - fs/cifs/cifssmb.c
[CIFS] CIFS writepage improvements - eliminate double copy
[linux-2.6-omap-h63xx.git] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2005
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   Contains the routines for constructing the SMB PDUs themselves
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
25  /* These are mostly routines that operate on a pathname, or on a tree id     */
26  /* (mounted volume), but there are eight handle based routines which must be */
27  /* treated slightly different for reconnection purposes since we never want  */
28  /* to reuse a stale file handle and the caller knows the file handle */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsproto.h"
38 #include "cifs_unicode.h"
39 #include "cifs_debug.h"
40
41 #ifdef CONFIG_CIFS_POSIX
42 static struct {
43         int index;
44         char *name;
45 } protocols[] = {
46         {CIFS_PROT, "\2NT LM 0.12"}, 
47         {CIFS_PROT, "\2POSIX 2"},
48         {BAD_PROT, "\2"}
49 };
50 #else
51 static struct {
52         int index;
53         char *name;
54 } protocols[] = {
55         {CIFS_PROT, "\2NT LM 0.12"}, 
56         {BAD_PROT, "\2"}
57 };
58 #endif
59
60
61 /* Mark as invalid, all open files on tree connections since they
62    were closed when session to server was lost */
63 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
64 {
65         struct cifsFileInfo *open_file = NULL;
66         struct list_head * tmp;
67         struct list_head * tmp1;
68
69 /* list all files open on tree connection and mark them invalid */
70         write_lock(&GlobalSMBSeslock);
71         list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
72                 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
73                 if(open_file) {
74                         open_file->invalidHandle = TRUE;
75                 }
76         }
77         write_unlock(&GlobalSMBSeslock);
78         /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
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
955 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
956              const int netfid, const unsigned int count,
957              const __u64 offset, unsigned int *nbytes, const char *buf,
958              const int long_op)
959 {
960         int rc = -EACCES;
961         WRITE_REQ *pSMB = NULL;
962         int bytes_returned;
963         int smb_hdr_len;
964         __u32 bytes_sent;
965         __u16 byte_count;
966
967         cERROR(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
968         rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
969         if (rc)
970                 return rc;
971         /* tcon and ses pointer are checked in smb_init */
972         if (tcon->ses->server == NULL)
973                 return -ECONNABORTED;
974
975         pSMB->AndXCommand = 0xFF;       /* none */
976         pSMB->Fid = netfid;
977         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
978         pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
979         pSMB->Reserved = 0xFFFFFFFF;
980         pSMB->WriteMode = 0;
981         pSMB->Remaining = 0;
982
983         /* Can increase buffer size if buffer is big enough in some cases - ie 
984         can send more if LARGE_WRITE_X capability returned by the server and if
985         our buffer is big enough or if we convert to iovecs on socket writes
986         and eliminate the copy to the CIFS buffer */
987         if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
988                 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
989         } else {
990                 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
991                          & ~0xFF;
992         }
993
994         if (bytes_sent > count)
995                 bytes_sent = count;
996         pSMB->DataOffset =
997             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
998
999         byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1000         pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1001         pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1002         smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1003         pSMB->hdr.smb_buf_length += bytes_sent+1;
1004         pSMB->ByteCount = cpu_to_le16(byte_count);
1005
1006         rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
1007                           buf, bytes_sent, &bytes_returned, long_op);
1008         if (rc) {
1009                 cFYI(1, ("Send error in write = %d", rc));
1010                 *nbytes = 0;
1011         } else {
1012                 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1013                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1014                 *nbytes = (*nbytes) << 16;
1015                 *nbytes += le16_to_cpu(pSMBr->Count);
1016         }
1017
1018         cifs_small_buf_release(pSMB);
1019
1020         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1021                 since file handle passed in no longer valid */
1022
1023         return rc;
1024 }
1025
1026
1027 #endif /* CIFS_EXPERIMENTAL */
1028
1029 int
1030 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1031             const __u16 smb_file_id, const __u64 len,
1032             const __u64 offset, const __u32 numUnlock,
1033             const __u32 numLock, const __u8 lockType, const int waitFlag)
1034 {
1035         int rc = 0;
1036         LOCK_REQ *pSMB = NULL;
1037         LOCK_RSP *pSMBr = NULL;
1038         int bytes_returned;
1039         int timeout = 0;
1040         __u16 count;
1041
1042         cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1043         rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1044
1045         if (rc)
1046                 return rc;
1047
1048         pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1049
1050         if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1051                 timeout = -1; /* no response expected */
1052                 pSMB->Timeout = 0;
1053         } else if (waitFlag == TRUE) {
1054                 timeout = 3;  /* blocking operation, no timeout */
1055                 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1056         } else {
1057                 pSMB->Timeout = 0;
1058         }
1059
1060         pSMB->NumberOfLocks = cpu_to_le16(numLock);
1061         pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1062         pSMB->LockType = lockType;
1063         pSMB->AndXCommand = 0xFF;       /* none */
1064         pSMB->Fid = smb_file_id; /* netfid stays le */
1065
1066         if((numLock != 0) || (numUnlock != 0)) {
1067                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1068                 /* BB where to store pid high? */
1069                 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1070                 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1071                 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1072                 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1073                 count = sizeof(LOCKING_ANDX_RANGE);
1074         } else {
1075                 /* oplock break */
1076                 count = 0;
1077         }
1078         pSMB->hdr.smb_buf_length += count;
1079         pSMB->ByteCount = cpu_to_le16(count);
1080
1081         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1082                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1083
1084         if (rc) {
1085                 cFYI(1, ("Send error in Lock = %d", rc));
1086         }
1087         cifs_small_buf_release(pSMB);
1088
1089         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1090         since file handle passed in no longer valid */
1091         return rc;
1092 }
1093
1094 int
1095 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1096 {
1097         int rc = 0;
1098         CLOSE_REQ *pSMB = NULL;
1099         CLOSE_RSP *pSMBr = NULL;
1100         int bytes_returned;
1101         cFYI(1, ("In CIFSSMBClose"));
1102
1103 /* do not retry on dead session on close */
1104         rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1105         if(rc == -EAGAIN)
1106                 return 0;
1107         if (rc)
1108                 return rc;
1109
1110         pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1111
1112         pSMB->FileID = (__u16) smb_file_id;
1113         pSMB->LastWriteTime = 0;
1114         pSMB->ByteCount = 0;
1115         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1116                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1117         if (rc) {
1118                 if(rc!=-EINTR) {
1119                         /* EINTR is expected when user ctl-c to kill app */
1120                         cERROR(1, ("Send error in Close = %d", rc));
1121                 }
1122         }
1123
1124         cifs_small_buf_release(pSMB);
1125
1126         /* Since session is dead, file will be closed on server already */
1127         if(rc == -EAGAIN)
1128                 rc = 0;
1129
1130         return rc;
1131 }
1132
1133 int
1134 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1135               const char *fromName, const char *toName,
1136               const struct nls_table *nls_codepage, int remap)
1137 {
1138         int rc = 0;
1139         RENAME_REQ *pSMB = NULL;
1140         RENAME_RSP *pSMBr = NULL;
1141         int bytes_returned;
1142         int name_len, name_len2;
1143         __u16 count;
1144
1145         cFYI(1, ("In CIFSSMBRename"));
1146 renameRetry:
1147         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1148                       (void **) &pSMBr);
1149         if (rc)
1150                 return rc;
1151
1152         pSMB->BufferFormat = 0x04;
1153         pSMB->SearchAttributes =
1154             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1155                         ATTR_DIRECTORY);
1156
1157         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1158                 name_len =
1159                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, 
1160                                      PATH_MAX, nls_codepage, remap);
1161                 name_len++;     /* trailing null */
1162                 name_len *= 2;
1163                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1164         /* protocol requires ASCII signature byte on Unicode string */
1165                 pSMB->OldFileName[name_len + 1] = 0x00;
1166                 name_len2 =
1167                     cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1168                                      toName, PATH_MAX, nls_codepage, remap);
1169                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1170                 name_len2 *= 2; /* convert to bytes */
1171         } else {                /* BB improve the check for buffer overruns BB */
1172                 name_len = strnlen(fromName, PATH_MAX);
1173                 name_len++;     /* trailing null */
1174                 strncpy(pSMB->OldFileName, fromName, name_len);
1175                 name_len2 = strnlen(toName, PATH_MAX);
1176                 name_len2++;    /* trailing null */
1177                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1178                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1179                 name_len2++;    /* trailing null */
1180                 name_len2++;    /* signature byte */
1181         }
1182
1183         count = 1 /* 1st signature byte */  + name_len + name_len2;
1184         pSMB->hdr.smb_buf_length += count;
1185         pSMB->ByteCount = cpu_to_le16(count);
1186
1187         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1188                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1189         if (rc) {
1190                 cFYI(1, ("Send error in rename = %d", rc));
1191         } 
1192
1193 #ifdef CONFIG_CIFS_STATS
1194           else {
1195                 atomic_inc(&tcon->num_renames);
1196         }
1197 #endif
1198
1199         cifs_buf_release(pSMB);
1200
1201         if (rc == -EAGAIN)
1202                 goto renameRetry;
1203
1204         return rc;
1205 }
1206
1207 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
1208                 int netfid, char * target_name, 
1209                 const struct nls_table * nls_codepage, int remap)
1210 {
1211         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1212         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1213         struct set_file_rename * rename_info;
1214         char *data_offset;
1215         char dummy_string[30];
1216         int rc = 0;
1217         int bytes_returned = 0;
1218         int len_of_str;
1219         __u16 params, param_offset, offset, count, byte_count;
1220
1221         cFYI(1, ("Rename to File by handle"));
1222         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1223                         (void **) &pSMBr);
1224         if (rc)
1225                 return rc;
1226
1227         params = 6;
1228         pSMB->MaxSetupCount = 0;
1229         pSMB->Reserved = 0;
1230         pSMB->Flags = 0;
1231         pSMB->Timeout = 0;
1232         pSMB->Reserved2 = 0;
1233         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1234         offset = param_offset + params;
1235
1236         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1237         rename_info = (struct set_file_rename *) data_offset;
1238         pSMB->MaxParameterCount = cpu_to_le16(2);
1239         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1240         pSMB->SetupCount = 1;
1241         pSMB->Reserved3 = 0;
1242         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1243         byte_count = 3 /* pad */  + params;
1244         pSMB->ParameterCount = cpu_to_le16(params);
1245         pSMB->TotalParameterCount = pSMB->ParameterCount;
1246         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1247         pSMB->DataOffset = cpu_to_le16(offset);
1248         /* construct random name ".cifs_tmp<inodenum><mid>" */
1249         rename_info->overwrite = cpu_to_le32(1);
1250         rename_info->root_fid  = 0;
1251         /* unicode only call */
1252         if(target_name == NULL) {
1253                 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1254                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1255                                         dummy_string, 24, nls_codepage, remap);
1256         } else {
1257                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1258                                         target_name, PATH_MAX, nls_codepage, remap);
1259         }
1260         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1261         count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1262         byte_count += count;
1263         pSMB->DataCount = cpu_to_le16(count);
1264         pSMB->TotalDataCount = pSMB->DataCount;
1265         pSMB->Fid = netfid;
1266         pSMB->InformationLevel =
1267                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1268         pSMB->Reserved4 = 0;
1269         pSMB->hdr.smb_buf_length += byte_count;
1270         pSMB->ByteCount = cpu_to_le16(byte_count);
1271         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1272                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1273         if (rc) {
1274                 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1275         }
1276 #ifdef CONFIG_CIFS_STATS
1277           else {
1278                 atomic_inc(&pTcon->num_t2renames);
1279         }
1280 #endif
1281         cifs_buf_release(pSMB);
1282
1283         /* Note: On -EAGAIN error only caller can retry on handle based calls
1284                 since file handle passed in no longer valid */
1285
1286         return rc;
1287 }
1288
1289 int
1290 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
1291             const __u16 target_tid, const char *toName, const int flags,
1292             const struct nls_table *nls_codepage, int remap)
1293 {
1294         int rc = 0;
1295         COPY_REQ *pSMB = NULL;
1296         COPY_RSP *pSMBr = NULL;
1297         int bytes_returned;
1298         int name_len, name_len2;
1299         __u16 count;
1300
1301         cFYI(1, ("In CIFSSMBCopy"));
1302 copyRetry:
1303         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1304                         (void **) &pSMBr);
1305         if (rc)
1306                 return rc;
1307
1308         pSMB->BufferFormat = 0x04;
1309         pSMB->Tid2 = target_tid;
1310
1311         pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1312
1313         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1314                 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, 
1315                                             fromName, PATH_MAX, nls_codepage,
1316                                             remap);
1317                 name_len++;     /* trailing null */
1318                 name_len *= 2;
1319                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1320                 /* protocol requires ASCII signature byte on Unicode string */
1321                 pSMB->OldFileName[name_len + 1] = 0x00;
1322                 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1323                                 toName, PATH_MAX, nls_codepage, remap);
1324                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1325                 name_len2 *= 2; /* convert to bytes */
1326         } else {                /* BB improve the check for buffer overruns BB */
1327                 name_len = strnlen(fromName, PATH_MAX);
1328                 name_len++;     /* trailing null */
1329                 strncpy(pSMB->OldFileName, fromName, name_len);
1330                 name_len2 = strnlen(toName, PATH_MAX);
1331                 name_len2++;    /* trailing null */
1332                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1333                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1334                 name_len2++;    /* trailing null */
1335                 name_len2++;    /* signature byte */
1336         }
1337
1338         count = 1 /* 1st signature byte */  + name_len + name_len2;
1339         pSMB->hdr.smb_buf_length += count;
1340         pSMB->ByteCount = cpu_to_le16(count);
1341
1342         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1343                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1344         if (rc) {
1345                 cFYI(1, ("Send error in copy = %d with %d files copied",
1346                         rc, le16_to_cpu(pSMBr->CopyCount)));
1347         }
1348         if (pSMB)
1349                 cifs_buf_release(pSMB);
1350
1351         if (rc == -EAGAIN)
1352                 goto copyRetry;
1353
1354         return rc;
1355 }
1356
1357 int
1358 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1359                       const char *fromName, const char *toName,
1360                       const struct nls_table *nls_codepage)
1361 {
1362         TRANSACTION2_SPI_REQ *pSMB = NULL;
1363         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1364         char *data_offset;
1365         int name_len;
1366         int name_len_target;
1367         int rc = 0;
1368         int bytes_returned = 0;
1369         __u16 params, param_offset, offset, byte_count;
1370
1371         cFYI(1, ("In Symlink Unix style"));
1372 createSymLinkRetry:
1373         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1374                       (void **) &pSMBr);
1375         if (rc)
1376                 return rc;
1377
1378         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1379                 name_len =
1380                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1381                                   /* find define for this maxpathcomponent */
1382                                   , nls_codepage);
1383                 name_len++;     /* trailing null */
1384                 name_len *= 2;
1385
1386         } else {                /* BB improve the check for buffer overruns BB */
1387                 name_len = strnlen(fromName, PATH_MAX);
1388                 name_len++;     /* trailing null */
1389                 strncpy(pSMB->FileName, fromName, name_len);
1390         }
1391         params = 6 + name_len;
1392         pSMB->MaxSetupCount = 0;
1393         pSMB->Reserved = 0;
1394         pSMB->Flags = 0;
1395         pSMB->Timeout = 0;
1396         pSMB->Reserved2 = 0;
1397         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1398                                      InformationLevel) - 4;
1399         offset = param_offset + params;
1400
1401         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1402         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1403                 name_len_target =
1404                     cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1405                                   /* find define for this maxpathcomponent */
1406                                   , nls_codepage);
1407                 name_len_target++;      /* trailing null */
1408                 name_len_target *= 2;
1409         } else {                /* BB improve the check for buffer overruns BB */
1410                 name_len_target = strnlen(toName, PATH_MAX);
1411                 name_len_target++;      /* trailing null */
1412                 strncpy(data_offset, toName, name_len_target);
1413         }
1414
1415         pSMB->MaxParameterCount = cpu_to_le16(2);
1416         /* BB find exact max on data count below from sess */
1417         pSMB->MaxDataCount = cpu_to_le16(1000);
1418         pSMB->SetupCount = 1;
1419         pSMB->Reserved3 = 0;
1420         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1421         byte_count = 3 /* pad */  + params + name_len_target;
1422         pSMB->DataCount = cpu_to_le16(name_len_target);
1423         pSMB->ParameterCount = cpu_to_le16(params);
1424         pSMB->TotalDataCount = pSMB->DataCount;
1425         pSMB->TotalParameterCount = pSMB->ParameterCount;
1426         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1427         pSMB->DataOffset = cpu_to_le16(offset);
1428         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1429         pSMB->Reserved4 = 0;
1430         pSMB->hdr.smb_buf_length += byte_count;
1431         pSMB->ByteCount = cpu_to_le16(byte_count);
1432         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1433                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1434         if (rc) {
1435                 cFYI(1,
1436                      ("Send error in SetPathInfo (create symlink) = %d",
1437                       rc));
1438         }
1439
1440         if (pSMB)
1441                 cifs_buf_release(pSMB);
1442
1443         if (rc == -EAGAIN)
1444                 goto createSymLinkRetry;
1445
1446         return rc;
1447 }
1448
1449 int
1450 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1451                        const char *fromName, const char *toName,
1452                        const struct nls_table *nls_codepage, int remap)
1453 {
1454         TRANSACTION2_SPI_REQ *pSMB = NULL;
1455         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1456         char *data_offset;
1457         int name_len;
1458         int name_len_target;
1459         int rc = 0;
1460         int bytes_returned = 0;
1461         __u16 params, param_offset, offset, byte_count;
1462
1463         cFYI(1, ("In Create Hard link Unix style"));
1464 createHardLinkRetry:
1465         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1466                       (void **) &pSMBr);
1467         if (rc)
1468                 return rc;
1469
1470         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1471                 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1472                                             PATH_MAX, nls_codepage, remap);
1473                 name_len++;     /* trailing null */
1474                 name_len *= 2;
1475
1476         } else {                /* BB improve the check for buffer overruns BB */
1477                 name_len = strnlen(toName, PATH_MAX);
1478                 name_len++;     /* trailing null */
1479                 strncpy(pSMB->FileName, toName, name_len);
1480         }
1481         params = 6 + name_len;
1482         pSMB->MaxSetupCount = 0;
1483         pSMB->Reserved = 0;
1484         pSMB->Flags = 0;
1485         pSMB->Timeout = 0;
1486         pSMB->Reserved2 = 0;
1487         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1488                                      InformationLevel) - 4;
1489         offset = param_offset + params;
1490
1491         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1492         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1493                 name_len_target =
1494                     cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1495                                      nls_codepage, remap);
1496                 name_len_target++;      /* trailing null */
1497                 name_len_target *= 2;
1498         } else {                /* BB improve the check for buffer overruns BB */
1499                 name_len_target = strnlen(fromName, PATH_MAX);
1500                 name_len_target++;      /* trailing null */
1501                 strncpy(data_offset, fromName, name_len_target);
1502         }
1503
1504         pSMB->MaxParameterCount = cpu_to_le16(2);
1505         /* BB find exact max on data count below from sess*/
1506         pSMB->MaxDataCount = cpu_to_le16(1000);
1507         pSMB->SetupCount = 1;
1508         pSMB->Reserved3 = 0;
1509         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1510         byte_count = 3 /* pad */  + params + name_len_target;
1511         pSMB->ParameterCount = cpu_to_le16(params);
1512         pSMB->TotalParameterCount = pSMB->ParameterCount;
1513         pSMB->DataCount = cpu_to_le16(name_len_target);
1514         pSMB->TotalDataCount = pSMB->DataCount;
1515         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1516         pSMB->DataOffset = cpu_to_le16(offset);
1517         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1518         pSMB->Reserved4 = 0;
1519         pSMB->hdr.smb_buf_length += byte_count;
1520         pSMB->ByteCount = cpu_to_le16(byte_count);
1521         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1522                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1523         if (rc) {
1524                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1525         }
1526
1527         cifs_buf_release(pSMB);
1528         if (rc == -EAGAIN)
1529                 goto createHardLinkRetry;
1530
1531         return rc;
1532 }
1533
1534 int
1535 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1536                    const char *fromName, const char *toName,
1537                    const struct nls_table *nls_codepage, int remap)
1538 {
1539         int rc = 0;
1540         NT_RENAME_REQ *pSMB = NULL;
1541         RENAME_RSP *pSMBr = NULL;
1542         int bytes_returned;
1543         int name_len, name_len2;
1544         __u16 count;
1545
1546         cFYI(1, ("In CIFSCreateHardLink"));
1547 winCreateHardLinkRetry:
1548
1549         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1550                       (void **) &pSMBr);
1551         if (rc)
1552                 return rc;
1553
1554         pSMB->SearchAttributes =
1555             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1556                         ATTR_DIRECTORY);
1557         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1558         pSMB->ClusterCount = 0;
1559
1560         pSMB->BufferFormat = 0x04;
1561
1562         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1563                 name_len =
1564                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1565                                      PATH_MAX, nls_codepage, remap);
1566                 name_len++;     /* trailing null */
1567                 name_len *= 2;
1568                 pSMB->OldFileName[name_len] = 0;        /* pad */
1569                 pSMB->OldFileName[name_len + 1] = 0x04; 
1570                 name_len2 =
1571                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1572                                      toName, PATH_MAX, nls_codepage, remap);
1573                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1574                 name_len2 *= 2; /* convert to bytes */
1575         } else {                /* BB improve the check for buffer overruns BB */
1576                 name_len = strnlen(fromName, PATH_MAX);
1577                 name_len++;     /* trailing null */
1578                 strncpy(pSMB->OldFileName, fromName, name_len);
1579                 name_len2 = strnlen(toName, PATH_MAX);
1580                 name_len2++;    /* trailing null */
1581                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
1582                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1583                 name_len2++;    /* trailing null */
1584                 name_len2++;    /* signature byte */
1585         }
1586
1587         count = 1 /* string type byte */  + name_len + name_len2;
1588         pSMB->hdr.smb_buf_length += count;
1589         pSMB->ByteCount = cpu_to_le16(count);
1590
1591         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1592                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1593         if (rc) {
1594                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1595         }
1596         cifs_buf_release(pSMB);
1597         if (rc == -EAGAIN)
1598                 goto winCreateHardLinkRetry;
1599
1600         return rc;
1601 }
1602
1603 int
1604 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1605                         const unsigned char *searchName,
1606                         char *symlinkinfo, const int buflen,
1607                         const struct nls_table *nls_codepage)
1608 {
1609 /* SMB_QUERY_FILE_UNIX_LINK */
1610         TRANSACTION2_QPI_REQ *pSMB = NULL;
1611         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1612         int rc = 0;
1613         int bytes_returned;
1614         int name_len;
1615         __u16 params, byte_count;
1616
1617         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1618
1619 querySymLinkRetry:
1620         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1621                       (void **) &pSMBr);
1622         if (rc)
1623                 return rc;
1624
1625         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1626                 name_len =
1627                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1628                                   /* find define for this maxpathcomponent */
1629                                   , nls_codepage);
1630                 name_len++;     /* trailing null */
1631                 name_len *= 2;
1632         } else {                /* BB improve the check for buffer overruns BB */
1633                 name_len = strnlen(searchName, PATH_MAX);
1634                 name_len++;     /* trailing null */
1635                 strncpy(pSMB->FileName, searchName, name_len);
1636         }
1637
1638         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1639         pSMB->TotalDataCount = 0;
1640         pSMB->MaxParameterCount = cpu_to_le16(2);
1641         /* BB find exact max data count below from sess structure BB */
1642         pSMB->MaxDataCount = cpu_to_le16(4000);
1643         pSMB->MaxSetupCount = 0;
1644         pSMB->Reserved = 0;
1645         pSMB->Flags = 0;
1646         pSMB->Timeout = 0;
1647         pSMB->Reserved2 = 0;
1648         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1649         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1650         pSMB->DataCount = 0;
1651         pSMB->DataOffset = 0;
1652         pSMB->SetupCount = 1;
1653         pSMB->Reserved3 = 0;
1654         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1655         byte_count = params + 1 /* pad */ ;
1656         pSMB->TotalParameterCount = cpu_to_le16(params);
1657         pSMB->ParameterCount = pSMB->TotalParameterCount;
1658         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1659         pSMB->Reserved4 = 0;
1660         pSMB->hdr.smb_buf_length += byte_count;
1661         pSMB->ByteCount = cpu_to_le16(byte_count);
1662
1663         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1664                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1665         if (rc) {
1666                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1667         } else {
1668                 /* decode response */
1669
1670                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1671                 if (rc || (pSMBr->ByteCount < 2))
1672                 /* BB also check enough total bytes returned */
1673                         rc = -EIO;      /* bad smb */
1674                 else {
1675                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1676                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1677
1678                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1679                                 name_len = UniStrnlen((wchar_t *) ((char *)
1680                                         &pSMBr->hdr.Protocol +data_offset),
1681                                         min_t(const int, buflen,count) / 2);
1682                         /* BB FIXME investigate remapping reserved chars here */
1683                                 cifs_strfromUCS_le(symlinkinfo,
1684                                         (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1685                                                 data_offset),
1686                                         name_len, nls_codepage);
1687                         } else {
1688                                 strncpy(symlinkinfo,
1689                                         (char *) &pSMBr->hdr.Protocol + 
1690                                                 data_offset,
1691                                         min_t(const int, buflen, count));
1692                         }
1693                         symlinkinfo[buflen] = 0;
1694         /* just in case so calling code does not go off the end of buffer */
1695                 }
1696         }
1697         cifs_buf_release(pSMB);
1698         if (rc == -EAGAIN)
1699                 goto querySymLinkRetry;
1700         return rc;
1701 }
1702
1703 int
1704 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1705                         const unsigned char *searchName,
1706                         char *symlinkinfo, const int buflen,__u16 fid,
1707                         const struct nls_table *nls_codepage)
1708 {
1709         int rc = 0;
1710         int bytes_returned;
1711         int name_len;
1712         struct smb_com_transaction_ioctl_req * pSMB;
1713         struct smb_com_transaction_ioctl_rsp * pSMBr;
1714
1715         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1716         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1717                       (void **) &pSMBr);
1718         if (rc)
1719                 return rc;
1720
1721         pSMB->TotalParameterCount = 0 ;
1722         pSMB->TotalDataCount = 0;
1723         pSMB->MaxParameterCount = cpu_to_le32(2);
1724         /* BB find exact data count max from sess structure BB */
1725         pSMB->MaxDataCount = cpu_to_le32(4000);
1726         pSMB->MaxSetupCount = 4;
1727         pSMB->Reserved = 0;
1728         pSMB->ParameterOffset = 0;
1729         pSMB->DataCount = 0;
1730         pSMB->DataOffset = 0;
1731         pSMB->SetupCount = 4;
1732         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1733         pSMB->ParameterCount = pSMB->TotalParameterCount;
1734         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1735         pSMB->IsFsctl = 1; /* FSCTL */
1736         pSMB->IsRootFlag = 0;
1737         pSMB->Fid = fid; /* file handle always le */
1738         pSMB->ByteCount = 0;
1739
1740         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1741                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1742         if (rc) {
1743                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1744         } else {                /* decode response */
1745                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1746                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1747                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1748                 /* BB also check enough total bytes returned */
1749                         rc = -EIO;      /* bad smb */
1750                 else {
1751                         if(data_count && (data_count < 2048)) {
1752                                 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1753
1754                                 struct reparse_data * reparse_buf = (struct reparse_data *)
1755                                         ((char *)&pSMBr->hdr.Protocol + data_offset);
1756                                 if((char*)reparse_buf >= end_of_smb) {
1757                                         rc = -EIO;
1758                                         goto qreparse_out;
1759                                 }
1760                                 if((reparse_buf->LinkNamesBuf + 
1761                                         reparse_buf->TargetNameOffset +
1762                                         reparse_buf->TargetNameLen) >
1763                                                 end_of_smb) {
1764                                         cFYI(1,("reparse buf extended beyond SMB"));
1765                                         rc = -EIO;
1766                                         goto qreparse_out;
1767                                 }
1768                                 
1769                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1770                                         name_len = UniStrnlen((wchar_t *)
1771                                                         (reparse_buf->LinkNamesBuf + 
1772                                                         reparse_buf->TargetNameOffset),
1773                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
1774                                         cifs_strfromUCS_le(symlinkinfo,
1775                                                 (wchar_t *) (reparse_buf->LinkNamesBuf + 
1776                                                 reparse_buf->TargetNameOffset),
1777                                                 name_len, nls_codepage);
1778                                 } else { /* ASCII names */
1779                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
1780                                                 reparse_buf->TargetNameOffset, 
1781                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
1782                                 }
1783                         } else {
1784                                 rc = -EIO;
1785                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1786                         }
1787                         symlinkinfo[buflen] = 0; /* just in case so the caller
1788                                         does not go off the end of the buffer */
1789                         cFYI(1,("readlink result - %s ",symlinkinfo));
1790                 }
1791         }
1792 qreparse_out:
1793         if (pSMB)
1794                 cifs_buf_release(pSMB);
1795
1796         /* Note: On -EAGAIN error only caller can retry on handle based calls
1797                 since file handle passed in no longer valid */
1798
1799         return rc;
1800 }
1801
1802 #ifdef CONFIG_CIFS_POSIX
1803
1804 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1805 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1806 {
1807         /* u8 cifs fields do not need le conversion */
1808         ace->e_perm = (__u16)cifs_ace->cifs_e_perm; 
1809         ace->e_tag  = (__u16)cifs_ace->cifs_e_tag;
1810         ace->e_id   = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1811         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1812
1813         return;
1814 }
1815
1816 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
1817 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1818                                 const int acl_type,const int size_of_data_area)
1819 {
1820         int size =  0;
1821         int i;
1822         __u16 count;
1823         struct cifs_posix_ace * pACE;
1824         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1825         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1826
1827         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1828                 return -EOPNOTSUPP;
1829
1830         if(acl_type & ACL_TYPE_ACCESS) {
1831                 count = le16_to_cpu(cifs_acl->access_entry_count);
1832                 pACE = &cifs_acl->ace_array[0];
1833                 size = sizeof(struct cifs_posix_acl);
1834                 size += sizeof(struct cifs_posix_ace) * count;
1835                 /* check if we would go beyond end of SMB */
1836                 if(size_of_data_area < size) {
1837                         cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
1838                         return -EINVAL;
1839                 }
1840         } else if(acl_type & ACL_TYPE_DEFAULT) {
1841                 count = le16_to_cpu(cifs_acl->access_entry_count);
1842                 size = sizeof(struct cifs_posix_acl);
1843                 size += sizeof(struct cifs_posix_ace) * count;
1844 /* skip past access ACEs to get to default ACEs */
1845                 pACE = &cifs_acl->ace_array[count];
1846                 count = le16_to_cpu(cifs_acl->default_entry_count);
1847                 size += sizeof(struct cifs_posix_ace) * count;
1848                 /* check if we would go beyond end of SMB */
1849                 if(size_of_data_area < size)
1850                         return -EINVAL;
1851         } else {
1852                 /* illegal type */
1853                 return -EINVAL;
1854         }
1855
1856         size = posix_acl_xattr_size(count);
1857         if((buflen == 0) || (local_acl == NULL)) {
1858                 /* used to query ACL EA size */                         
1859         } else if(size > buflen) {
1860                 return -ERANGE;
1861         } else /* buffer big enough */ {
1862                 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
1863                 for(i = 0;i < count ;i++) {
1864                         cifs_convert_ace(&local_acl->a_entries[i],pACE);
1865                         pACE ++;
1866                 }
1867         }
1868         return size;
1869 }
1870
1871 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
1872                         const posix_acl_xattr_entry * local_ace)
1873 {
1874         __u16 rc = 0; /* 0 = ACL converted ok */
1875
1876         cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
1877         cifs_ace->cifs_e_tag =  (__u8)cpu_to_le16(local_ace->e_tag);
1878         /* BB is there a better way to handle the large uid? */
1879         if(local_ace->e_id == -1) {
1880         /* Probably no need to le convert -1 on any arch but can not hurt */
1881                 cifs_ace->cifs_uid = cpu_to_le64(-1);
1882         } else 
1883                 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
1884         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
1885         return rc;
1886 }
1887
1888 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
1889 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
1890                 const int acl_type)
1891 {
1892         __u16 rc = 0;
1893         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
1894         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
1895         int count;
1896         int i;
1897
1898         if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1899                 return 0;
1900
1901         count = posix_acl_xattr_count((size_t)buflen);
1902         cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
1903                 count,buflen,local_acl->a_version));
1904         if(local_acl->a_version != 2) {
1905                 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
1906                 return 0;
1907         }
1908         cifs_acl->version = cpu_to_le16(1);
1909         if(acl_type == ACL_TYPE_ACCESS) 
1910                 cifs_acl->access_entry_count = count;
1911         else if(acl_type == ACL_TYPE_DEFAULT)
1912                 cifs_acl->default_entry_count = count;
1913         else {
1914                 cFYI(1,("unknown ACL type %d",acl_type));
1915                 return 0;
1916         }
1917         for(i=0;i<count;i++) {
1918                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
1919                                         &local_acl->a_entries[i]);
1920                 if(rc != 0) {
1921                         /* ACE not converted */
1922                         break;
1923                 }
1924         }
1925         if(rc == 0) {
1926                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
1927                 rc += sizeof(struct cifs_posix_acl);
1928                 /* BB add check to make sure ACL does not overflow SMB */
1929         }
1930         return rc;
1931 }
1932
1933 int
1934 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
1935                         const unsigned char *searchName,
1936                         char *acl_inf, const int buflen, const int acl_type,
1937                         const struct nls_table *nls_codepage, int remap)
1938 {
1939 /* SMB_QUERY_POSIX_ACL */
1940         TRANSACTION2_QPI_REQ *pSMB = NULL;
1941         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1942         int rc = 0;
1943         int bytes_returned;
1944         int name_len;
1945         __u16 params, byte_count;
1946                                                                                                                                              
1947         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
1948
1949 queryAclRetry:
1950         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1951                 (void **) &pSMBr);
1952         if (rc)
1953                 return rc;
1954                                                                                                                                              
1955         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1956                 name_len =
1957                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
1958                                          PATH_MAX, nls_codepage, remap);
1959                 name_len++;     /* trailing null */
1960                 name_len *= 2;
1961                 pSMB->FileName[name_len] = 0;
1962                 pSMB->FileName[name_len+1] = 0;
1963         } else {                /* BB improve the check for buffer overruns BB */
1964                 name_len = strnlen(searchName, PATH_MAX);
1965                 name_len++;     /* trailing null */
1966                 strncpy(pSMB->FileName, searchName, name_len);
1967         }
1968
1969         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1970         pSMB->TotalDataCount = 0;
1971         pSMB->MaxParameterCount = cpu_to_le16(2);
1972         /* BB find exact max data count below from sess structure BB */
1973         pSMB->MaxDataCount = cpu_to_le16(4000);
1974         pSMB->MaxSetupCount = 0;
1975         pSMB->Reserved = 0;
1976         pSMB->Flags = 0;
1977         pSMB->Timeout = 0;
1978         pSMB->Reserved2 = 0;
1979         pSMB->ParameterOffset = cpu_to_le16(
1980                 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1981         pSMB->DataCount = 0;
1982         pSMB->DataOffset = 0;
1983         pSMB->SetupCount = 1;
1984         pSMB->Reserved3 = 0;
1985         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1986         byte_count = params + 1 /* pad */ ;
1987         pSMB->TotalParameterCount = cpu_to_le16(params);
1988         pSMB->ParameterCount = pSMB->TotalParameterCount;
1989         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
1990         pSMB->Reserved4 = 0;
1991         pSMB->hdr.smb_buf_length += byte_count;
1992         pSMB->ByteCount = cpu_to_le16(byte_count);
1993
1994         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1995                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1996         if (rc) {
1997                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
1998         } else {
1999                 /* decode response */
2000  
2001                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2002                 if (rc || (pSMBr->ByteCount < 2))
2003                 /* BB also check enough total bytes returned */
2004                         rc = -EIO;      /* bad smb */
2005                 else {
2006                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2007                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2008                         rc = cifs_copy_posix_acl(acl_inf,
2009                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2010                                 buflen,acl_type,count);
2011                 }
2012         }
2013         cifs_buf_release(pSMB);
2014         if (rc == -EAGAIN)
2015                 goto queryAclRetry;
2016         return rc;
2017 }
2018
2019 int
2020 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2021                         const unsigned char *fileName,
2022                         const char *local_acl, const int buflen, 
2023                         const int acl_type,
2024                         const struct nls_table *nls_codepage, int remap)
2025 {
2026         struct smb_com_transaction2_spi_req *pSMB = NULL;
2027         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2028         char *parm_data;
2029         int name_len;
2030         int rc = 0;
2031         int bytes_returned = 0;
2032         __u16 params, byte_count, data_count, param_offset, offset;
2033
2034         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2035 setAclRetry:
2036         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2037                       (void **) &pSMBr);
2038         if (rc)
2039                 return rc;
2040         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2041                 name_len =
2042                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
2043                                       PATH_MAX, nls_codepage, remap);
2044                 name_len++;     /* trailing null */
2045                 name_len *= 2;
2046         } else {                /* BB improve the check for buffer overruns BB */
2047                 name_len = strnlen(fileName, PATH_MAX);
2048                 name_len++;     /* trailing null */
2049                 strncpy(pSMB->FileName, fileName, name_len);
2050         }
2051         params = 6 + name_len;
2052         pSMB->MaxParameterCount = cpu_to_le16(2);
2053         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2054         pSMB->MaxSetupCount = 0;
2055         pSMB->Reserved = 0;
2056         pSMB->Flags = 0;
2057         pSMB->Timeout = 0;
2058         pSMB->Reserved2 = 0;
2059         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2060                                      InformationLevel) - 4;
2061         offset = param_offset + params;
2062         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2063         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2064
2065         /* convert to on the wire format for POSIX ACL */
2066         data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2067
2068         if(data_count == 0) {
2069                 rc = -EOPNOTSUPP;
2070                 goto setACLerrorExit;
2071         }
2072         pSMB->DataOffset = cpu_to_le16(offset);
2073         pSMB->SetupCount = 1;
2074         pSMB->Reserved3 = 0;
2075         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2076         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2077         byte_count = 3 /* pad */  + params + data_count;
2078         pSMB->DataCount = cpu_to_le16(data_count);
2079         pSMB->TotalDataCount = pSMB->DataCount;
2080         pSMB->ParameterCount = cpu_to_le16(params);
2081         pSMB->TotalParameterCount = pSMB->ParameterCount;
2082         pSMB->Reserved4 = 0;
2083         pSMB->hdr.smb_buf_length += byte_count;
2084         pSMB->ByteCount = cpu_to_le16(byte_count);
2085         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2086                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2087         if (rc) {
2088                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2089         }
2090
2091 setACLerrorExit:
2092         cifs_buf_release(pSMB);
2093         if (rc == -EAGAIN)
2094                 goto setAclRetry;
2095         return rc;
2096 }
2097
2098 /* BB fix tabs in this function FIXME BB */
2099 int
2100 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2101                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2102 {
2103         int rc = 0;
2104         struct smb_t2_qfi_req *pSMB = NULL;
2105         struct smb_t2_qfi_rsp *pSMBr = NULL;
2106         int bytes_returned;
2107         __u16 params, byte_count;
2108
2109         cFYI(1,("In GetExtAttr"));
2110         if(tcon == NULL)
2111                 return -ENODEV;
2112
2113 GetExtAttrRetry:
2114         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2115                       (void **) &pSMBr);
2116         if (rc)
2117                 return rc;
2118
2119         params = 2 /* level */ +2 /* fid */;
2120         pSMB->t2.TotalDataCount = 0;
2121         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2122         /* BB find exact max data count below from sess structure BB */
2123         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2124         pSMB->t2.MaxSetupCount = 0;
2125         pSMB->t2.Reserved = 0;
2126         pSMB->t2.Flags = 0;
2127         pSMB->t2.Timeout = 0;
2128         pSMB->t2.Reserved2 = 0;
2129         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2130                         Fid) - 4);
2131         pSMB->t2.DataCount = 0;
2132         pSMB->t2.DataOffset = 0;
2133         pSMB->t2.SetupCount = 1;
2134         pSMB->t2.Reserved3 = 0;
2135         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2136         byte_count = params + 1 /* pad */ ;
2137         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2138         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2139         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2140         pSMB->Pad = 0;
2141         pSMB->Fid = netfid;
2142         pSMB->hdr.smb_buf_length += byte_count;
2143         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2144
2145         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2146                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2147         if (rc) {
2148                 cFYI(1, ("error %d in GetExtAttr", rc));
2149         } else {
2150                 /* decode response */
2151                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2152                 if (rc || (pSMBr->ByteCount < 2))
2153                 /* BB also check enough total bytes returned */
2154                         /* If rc should we check for EOPNOSUPP and
2155                         disable the srvino flag? or in caller? */
2156                         rc = -EIO;      /* bad smb */
2157                 else {
2158                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2159                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2160                         struct file_chattr_info * pfinfo;
2161                         /* BB Do we need a cast or hash here ? */
2162                         if(count != 16) {
2163                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
2164                                 rc = -EIO;
2165                                 goto GetExtAttrOut;
2166                         }
2167                         pfinfo = (struct file_chattr_info *)
2168                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2169                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2170                         *pMask = le64_to_cpu(pfinfo->mask);
2171                 }
2172         }
2173 GetExtAttrOut:
2174         cifs_buf_release(pSMB);
2175         if (rc == -EAGAIN)
2176                 goto GetExtAttrRetry;
2177         return rc;
2178 }
2179
2180
2181 #endif /* CONFIG_POSIX */
2182
2183 int
2184 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2185                  const unsigned char *searchName,
2186                  FILE_ALL_INFO * pFindData,
2187                  const struct nls_table *nls_codepage, int remap)
2188 {
2189 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2190         TRANSACTION2_QPI_REQ *pSMB = NULL;
2191         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2192         int rc = 0;
2193         int bytes_returned;
2194         int name_len;
2195         __u16 params, byte_count;
2196
2197 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2198 QPathInfoRetry:
2199         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2200                       (void **) &pSMBr);
2201         if (rc)
2202                 return rc;
2203
2204         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2205                 name_len =
2206                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2207                                      PATH_MAX, nls_codepage, remap);
2208                 name_len++;     /* trailing null */
2209                 name_len *= 2;
2210         } else {                /* BB improve the check for buffer overruns BB */
2211                 name_len = strnlen(searchName, PATH_MAX);
2212                 name_len++;     /* trailing null */
2213                 strncpy(pSMB->FileName, searchName, name_len);
2214         }
2215
2216         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2217         pSMB->TotalDataCount = 0;
2218         pSMB->MaxParameterCount = cpu_to_le16(2);
2219         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2220         pSMB->MaxSetupCount = 0;
2221         pSMB->Reserved = 0;
2222         pSMB->Flags = 0;
2223         pSMB->Timeout = 0;
2224         pSMB->Reserved2 = 0;
2225         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2226         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2227         pSMB->DataCount = 0;
2228         pSMB->DataOffset = 0;
2229         pSMB->SetupCount = 1;
2230         pSMB->Reserved3 = 0;
2231         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2232         byte_count = params + 1 /* pad */ ;
2233         pSMB->TotalParameterCount = cpu_to_le16(params);
2234         pSMB->ParameterCount = pSMB->TotalParameterCount;
2235         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2236         pSMB->Reserved4 = 0;
2237         pSMB->hdr.smb_buf_length += byte_count;
2238         pSMB->ByteCount = cpu_to_le16(byte_count);
2239
2240         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2241                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2242         if (rc) {
2243                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2244         } else {                /* decode response */
2245                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2246
2247                 if (rc || (pSMBr->ByteCount < 40)) 
2248                         rc = -EIO;      /* bad smb */
2249                 else if (pFindData){
2250                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2251                         memcpy((char *) pFindData,
2252                                (char *) &pSMBr->hdr.Protocol +
2253                                data_offset, sizeof (FILE_ALL_INFO));
2254                 } else
2255                     rc = -ENOMEM;
2256         }
2257         cifs_buf_release(pSMB);
2258         if (rc == -EAGAIN)
2259                 goto QPathInfoRetry;
2260
2261         return rc;
2262 }
2263
2264 int
2265 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2266                      const unsigned char *searchName,
2267                      FILE_UNIX_BASIC_INFO * pFindData,
2268                      const struct nls_table *nls_codepage, int remap)
2269 {
2270 /* SMB_QUERY_FILE_UNIX_BASIC */
2271         TRANSACTION2_QPI_REQ *pSMB = NULL;
2272         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2273         int rc = 0;
2274         int bytes_returned = 0;
2275         int name_len;
2276         __u16 params, byte_count;
2277
2278         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2279 UnixQPathInfoRetry:
2280         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2281                       (void **) &pSMBr);
2282         if (rc)
2283                 return rc;
2284
2285         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2286                 name_len =
2287                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2288                                   PATH_MAX, nls_codepage, remap);
2289                 name_len++;     /* trailing null */
2290                 name_len *= 2;
2291         } else {                /* BB improve the check for buffer overruns BB */
2292                 name_len = strnlen(searchName, PATH_MAX);
2293                 name_len++;     /* trailing null */
2294                 strncpy(pSMB->FileName, searchName, name_len);
2295         }
2296
2297         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2298         pSMB->TotalDataCount = 0;
2299         pSMB->MaxParameterCount = cpu_to_le16(2);
2300         /* BB find exact max SMB PDU from sess structure BB */
2301         pSMB->MaxDataCount = cpu_to_le16(4000); 
2302         pSMB->MaxSetupCount = 0;
2303         pSMB->Reserved = 0;
2304         pSMB->Flags = 0;
2305         pSMB->Timeout = 0;
2306         pSMB->Reserved2 = 0;
2307         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2308         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2309         pSMB->DataCount = 0;
2310         pSMB->DataOffset = 0;
2311         pSMB->SetupCount = 1;
2312         pSMB->Reserved3 = 0;
2313         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2314         byte_count = params + 1 /* pad */ ;
2315         pSMB->TotalParameterCount = cpu_to_le16(params);
2316         pSMB->ParameterCount = pSMB->TotalParameterCount;
2317         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2318         pSMB->Reserved4 = 0;
2319         pSMB->hdr.smb_buf_length += byte_count;
2320         pSMB->ByteCount = cpu_to_le16(byte_count);
2321
2322         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2323                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2324         if (rc) {
2325                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2326         } else {                /* decode response */
2327                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2328
2329                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2330                         rc = -EIO;      /* bad smb */
2331                 } else {
2332                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2333                         memcpy((char *) pFindData,
2334                                (char *) &pSMBr->hdr.Protocol +
2335                                data_offset,
2336                                sizeof (FILE_UNIX_BASIC_INFO));
2337                 }
2338         }
2339         cifs_buf_release(pSMB);
2340         if (rc == -EAGAIN)
2341                 goto UnixQPathInfoRetry;
2342
2343         return rc;
2344 }
2345
2346 #if 0  /* function unused at present */
2347 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2348                const char *searchName, FILE_ALL_INFO * findData,
2349                const struct nls_table *nls_codepage)
2350 {
2351 /* level 257 SMB_ */
2352         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2353         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2354         int rc = 0;
2355         int bytes_returned;
2356         int name_len;
2357         __u16 params, byte_count;
2358
2359         cFYI(1, ("In FindUnique"));
2360 findUniqueRetry:
2361         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2362                       (void **) &pSMBr);
2363         if (rc)
2364                 return rc;
2365
2366         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2367                 name_len =
2368                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2369                                   /* find define for this maxpathcomponent */
2370                                   , nls_codepage);
2371                 name_len++;     /* trailing null */
2372                 name_len *= 2;
2373         } else {                /* BB improve the check for buffer overruns BB */
2374                 name_len = strnlen(searchName, PATH_MAX);
2375                 name_len++;     /* trailing null */
2376                 strncpy(pSMB->FileName, searchName, name_len);
2377         }
2378
2379         params = 12 + name_len /* includes null */ ;
2380         pSMB->TotalDataCount = 0;       /* no EAs */
2381         pSMB->MaxParameterCount = cpu_to_le16(2);
2382         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2383         pSMB->MaxSetupCount = 0;
2384         pSMB->Reserved = 0;
2385         pSMB->Flags = 0;
2386         pSMB->Timeout = 0;
2387         pSMB->Reserved2 = 0;
2388         pSMB->ParameterOffset = cpu_to_le16(
2389          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2390         pSMB->DataCount = 0;
2391         pSMB->DataOffset = 0;
2392         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
2393         pSMB->Reserved3 = 0;
2394         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2395         byte_count = params + 1 /* pad */ ;
2396         pSMB->TotalParameterCount = cpu_to_le16(params);
2397         pSMB->ParameterCount = pSMB->TotalParameterCount;
2398         pSMB->SearchAttributes =
2399             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2400                         ATTR_DIRECTORY);
2401         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
2402         pSMB->SearchFlags = cpu_to_le16(1);
2403         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2404         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
2405         pSMB->hdr.smb_buf_length += byte_count;
2406         pSMB->ByteCount = cpu_to_le16(byte_count);
2407
2408         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2409                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2410
2411         if (rc) {
2412                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2413         } else {                /* decode response */
2414
2415                 /* BB fill in */
2416         }
2417
2418         cifs_buf_release(pSMB);
2419         if (rc == -EAGAIN)
2420                 goto findUniqueRetry;
2421
2422         return rc;
2423 }
2424 #endif /* end unused (temporarily) function */
2425
2426 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2427 int
2428 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2429               const char *searchName, 
2430               const struct nls_table *nls_codepage,
2431               __u16 *   pnetfid,
2432               struct cifs_search_info * psrch_inf, int remap)
2433 {
2434 /* level 257 SMB_ */
2435         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2436         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2437         T2_FFIRST_RSP_PARMS * parms;
2438         int rc = 0;
2439         int bytes_returned = 0;
2440         int name_len;
2441         __u16 params, byte_count;
2442
2443         cFYI(1, ("In FindFirst for %s",searchName));
2444
2445 findFirstRetry:
2446         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2447                       (void **) &pSMBr);
2448         if (rc)
2449                 return rc;
2450
2451         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2452                 name_len =
2453                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2454                                  PATH_MAX, nls_codepage, remap);
2455                 /* We can not add the asterik earlier in case
2456                 it got remapped to 0xF03A as if it were part of the
2457                 directory name instead of a wildcard */
2458                 name_len *= 2;
2459                 pSMB->FileName[name_len] = '\\';
2460                 pSMB->FileName[name_len+1] = 0;
2461                 pSMB->FileName[name_len+2] = '*';
2462                 pSMB->FileName[name_len+3] = 0;
2463                 name_len += 4; /* now the trailing null */
2464                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2465                 pSMB->FileName[name_len+1] = 0;
2466                 name_len += 2;
2467         } else {        /* BB add check for overrun of SMB buf BB */
2468                 name_len = strnlen(searchName, PATH_MAX);
2469 /* BB fix here and in unicode clause above ie
2470                 if(name_len > buffersize-header)
2471                         free buffer exit; BB */
2472                 strncpy(pSMB->FileName, searchName, name_len);
2473                 pSMB->FileName[name_len] = '\\';
2474                 pSMB->FileName[name_len+1] = '*';
2475                 pSMB->FileName[name_len+2] = 0;
2476                 name_len += 3;
2477         }
2478
2479         params = 12 + name_len /* includes null */ ;
2480         pSMB->TotalDataCount = 0;       /* no EAs */
2481         pSMB->MaxParameterCount = cpu_to_le16(10);
2482         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2483                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2484         pSMB->MaxSetupCount = 0;
2485         pSMB->Reserved = 0;
2486         pSMB->Flags = 0;
2487         pSMB->Timeout = 0;
2488         pSMB->Reserved2 = 0;
2489         byte_count = params + 1 /* pad */ ;
2490         pSMB->TotalParameterCount = cpu_to_le16(params);
2491         pSMB->ParameterCount = pSMB->TotalParameterCount;
2492         pSMB->ParameterOffset = cpu_to_le16(
2493           offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2494         pSMB->DataCount = 0;
2495         pSMB->DataOffset = 0;
2496         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
2497         pSMB->Reserved3 = 0;
2498         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2499         pSMB->SearchAttributes =
2500             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2501                         ATTR_DIRECTORY);
2502         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2503         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
2504                 CIFS_SEARCH_RETURN_RESUME);
2505         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2506
2507         /* BB what should we set StorageType to? Does it matter? BB */
2508         pSMB->SearchStorageType = 0;
2509         pSMB->hdr.smb_buf_length += byte_count;
2510         pSMB->ByteCount = cpu_to_le16(byte_count);
2511
2512         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2513                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2514
2515         if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2516                 /* BB Add code to handle unsupported level rc */
2517                 cFYI(1, ("Error in FindFirst = %d", rc));
2518
2519                 if (pSMB)
2520                         cifs_buf_release(pSMB);
2521
2522                 /* BB eventually could optimize out free and realloc of buf */
2523                 /*    for this case */
2524                 if (rc == -EAGAIN)
2525                         goto findFirstRetry;
2526         } else { /* decode response */
2527                 /* BB remember to free buffer if error BB */
2528                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2529                 if(rc == 0) {
2530                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2531                                 psrch_inf->unicode = TRUE;
2532                         else
2533                                 psrch_inf->unicode = FALSE;
2534
2535                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2536                         psrch_inf->srch_entries_start = 
2537                                 (char *) &pSMBr->hdr.Protocol + 
2538                                         le16_to_cpu(pSMBr->t2.DataOffset);
2539                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2540                                le16_to_cpu(pSMBr->t2.ParameterOffset));
2541
2542                         if(parms->EndofSearch)
2543                                 psrch_inf->endOfSearch = TRUE;
2544                         else
2545                                 psrch_inf->endOfSearch = FALSE;
2546
2547                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2548                         psrch_inf->index_of_last_entry = 
2549                                 psrch_inf->entries_in_buffer;
2550                         *pnetfid = parms->SearchHandle;
2551                 } else {
2552                         cifs_buf_release(pSMB);
2553                 }
2554         }
2555
2556         return rc;
2557 }
2558
2559 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2560             __u16 searchHandle, struct cifs_search_info * psrch_inf)
2561 {
2562         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2563         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2564         T2_FNEXT_RSP_PARMS * parms;
2565         char *response_data;
2566         int rc = 0;
2567         int bytes_returned, name_len;
2568         __u16 params, byte_count;
2569
2570         cFYI(1, ("In FindNext"));
2571
2572         if(psrch_inf->endOfSearch == TRUE)
2573                 return -ENOENT;
2574
2575         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2576                 (void **) &pSMBr);
2577         if (rc)
2578                 return rc;
2579
2580         params = 14;    /* includes 2 bytes of null string, converted to LE below */
2581         byte_count = 0;
2582         pSMB->TotalDataCount = 0;       /* no EAs */
2583         pSMB->MaxParameterCount = cpu_to_le16(8);
2584         pSMB->MaxDataCount =
2585             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2586         pSMB->MaxSetupCount = 0;
2587         pSMB->Reserved = 0;
2588         pSMB->Flags = 0;
2589         pSMB->Timeout = 0;
2590         pSMB->Reserved2 = 0;
2591         pSMB->ParameterOffset =  cpu_to_le16(
2592               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2593         pSMB->DataCount = 0;
2594         pSMB->DataOffset = 0;
2595         pSMB->SetupCount = 1;
2596         pSMB->Reserved3 = 0;
2597         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2598         pSMB->SearchHandle = searchHandle;      /* always kept as le */
2599         pSMB->SearchCount =
2600                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2601         /* test for Unix extensions */
2602 /*      if (tcon->ses->capabilities & CAP_UNIX) {
2603                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2604                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2605         } else {
2606                 pSMB->InformationLevel =
2607                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2608                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2609         } */
2610         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2611         pSMB->ResumeKey = psrch_inf->resume_key;
2612         pSMB->SearchFlags =
2613               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2614
2615         name_len = psrch_inf->resume_name_len;
2616         params += name_len;
2617         if(name_len < PATH_MAX) {
2618                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2619                 byte_count += name_len;
2620         } else {
2621                 rc = -EINVAL;
2622                 goto FNext2_err_exit;
2623         }
2624         byte_count = params + 1 /* pad */ ;
2625         pSMB->TotalParameterCount = cpu_to_le16(params);
2626         pSMB->ParameterCount = pSMB->TotalParameterCount;
2627         pSMB->hdr.smb_buf_length += byte_count;
2628         pSMB->ByteCount = cpu_to_le16(byte_count);
2629                                                                                               
2630         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2631                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2632                                                                                               
2633         if (rc) {
2634                 if (rc == -EBADF) {
2635                         psrch_inf->endOfSearch = TRUE;
2636                         rc = 0; /* search probably was closed at end of search above */
2637                 } else
2638                         cFYI(1, ("FindNext returned = %d", rc));
2639         } else {                /* decode response */
2640                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2641                 
2642                 if(rc == 0) {
2643                         /* BB fixme add lock for file (srch_info) struct here */
2644                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2645                                 psrch_inf->unicode = TRUE;
2646                         else
2647                                 psrch_inf->unicode = FALSE;
2648                         response_data = (char *) &pSMBr->hdr.Protocol +
2649                                le16_to_cpu(pSMBr->t2.ParameterOffset);
2650                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
2651                         response_data = (char *)&pSMBr->hdr.Protocol +
2652                                 le16_to_cpu(pSMBr->t2.DataOffset);
2653                         cifs_buf_release(psrch_inf->ntwrk_buf_start);
2654                         psrch_inf->srch_entries_start = response_data;
2655                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
2656                         if(parms->EndofSearch)
2657                                 psrch_inf->endOfSearch = TRUE;
2658                         else
2659                                 psrch_inf->endOfSearch = FALSE;
2660                                                                                               
2661                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2662                         psrch_inf->index_of_last_entry +=
2663                                 psrch_inf->entries_in_buffer;
2664 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2665
2666                         /* BB fixme add unlock here */
2667                 }
2668
2669         }
2670
2671         /* BB On error, should we leave previous search buf (and count and
2672         last entry fields) intact or free the previous one? */
2673
2674         /* Note: On -EAGAIN error only caller can retry on handle based calls
2675         since file handle passed in no longer valid */
2676 FNext2_err_exit:
2677         if (rc != 0)
2678                 cifs_buf_release(pSMB);
2679                                                                                               
2680         return rc;
2681 }
2682
2683 int
2684 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2685 {
2686         int rc = 0;
2687         FINDCLOSE_REQ *pSMB = NULL;
2688         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2689         int bytes_returned;
2690
2691         cFYI(1, ("In CIFSSMBFindClose"));
2692         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2693
2694         /* no sense returning error if session restarted
2695                 as file handle has been closed */
2696         if(rc == -EAGAIN)
2697                 return 0;
2698         if (rc)
2699                 return rc;
2700
2701         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
2702         pSMB->FileID = searchHandle;
2703         pSMB->ByteCount = 0;
2704         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2705                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2706         if (rc) {
2707                 cERROR(1, ("Send error in FindClose = %d", rc));
2708         }
2709         cifs_small_buf_release(pSMB);
2710
2711         /* Since session is dead, search handle closed on server already */
2712         if (rc == -EAGAIN)
2713                 rc = 0;
2714
2715         return rc;
2716 }
2717
2718 #ifdef CONFIG_CIFS_EXPERIMENTAL
2719 int
2720 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2721                 const unsigned char *searchName,
2722                 __u64 * inode_number,
2723                 const struct nls_table *nls_codepage, int remap)
2724 {
2725         int rc = 0;
2726         TRANSACTION2_QPI_REQ *pSMB = NULL;
2727         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2728         int name_len, bytes_returned;
2729         __u16 params, byte_count;
2730
2731         cFYI(1,("In GetSrvInodeNum for %s",searchName));
2732         if(tcon == NULL)
2733                 return -ENODEV; 
2734
2735 GetInodeNumberRetry:
2736         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2737                       (void **) &pSMBr);
2738         if (rc)
2739                 return rc;
2740
2741
2742         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2743                 name_len =
2744                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2745                                 PATH_MAX,nls_codepage, remap);
2746                 name_len++;     /* trailing null */
2747                 name_len *= 2;
2748         } else {                /* BB improve the check for buffer overruns BB */
2749                 name_len = strnlen(searchName, PATH_MAX);
2750                 name_len++;     /* trailing null */
2751                 strncpy(pSMB->FileName, searchName, name_len);
2752         }
2753
2754         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2755         pSMB->TotalDataCount = 0;
2756         pSMB->MaxParameterCount = cpu_to_le16(2);
2757         /* BB find exact max data count below from sess structure BB */
2758         pSMB->MaxDataCount = cpu_to_le16(4000);
2759         pSMB->MaxSetupCount = 0;
2760         pSMB->Reserved = 0;
2761         pSMB->Flags = 0;
2762         pSMB->Timeout = 0;
2763         pSMB->Reserved2 = 0;
2764         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2765                 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2766         pSMB->DataCount = 0;
2767         pSMB->DataOffset = 0;
2768         pSMB->SetupCount = 1;
2769         pSMB->Reserved3 = 0;
2770         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2771         byte_count = params + 1 /* pad */ ;
2772         pSMB->TotalParameterCount = cpu_to_le16(params);
2773         pSMB->ParameterCount = pSMB->TotalParameterCount;
2774         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
2775         pSMB->Reserved4 = 0;
2776         pSMB->hdr.smb_buf_length += byte_count;
2777         pSMB->ByteCount = cpu_to_le16(byte_count);
2778
2779         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2780                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2781         if (rc) {
2782                 cFYI(1, ("error %d in QueryInternalInfo", rc));
2783         } else {
2784                 /* decode response */
2785                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2786                 if (rc || (pSMBr->ByteCount < 2))
2787                 /* BB also check enough total bytes returned */
2788                         /* If rc should we check for EOPNOSUPP and
2789                         disable the srvino flag? or in caller? */
2790                         rc = -EIO;      /* bad smb */
2791                 else {
2792                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2793                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2794                         struct file_internal_info * pfinfo;
2795                         /* BB Do we need a cast or hash here ? */
2796                         if(count < 8) {
2797                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
2798                                 rc = -EIO;
2799                                 goto GetInodeNumOut;
2800                         }
2801                         pfinfo = (struct file_internal_info *)
2802                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2803                         *inode_number = pfinfo->UniqueId;
2804                 }
2805         }
2806 GetInodeNumOut:
2807         cifs_buf_release(pSMB);
2808         if (rc == -EAGAIN)
2809                 goto GetInodeNumberRetry;
2810         return rc;
2811 }
2812 #endif /* CIFS_EXPERIMENTAL */
2813
2814 int
2815 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2816                 const unsigned char *searchName,
2817                 unsigned char **targetUNCs,
2818                 unsigned int *number_of_UNC_in_array,
2819                 const struct nls_table *nls_codepage, int remap)
2820 {
2821 /* TRANS2_GET_DFS_REFERRAL */
2822         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2823         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2824         struct dfs_referral_level_3 * referrals = NULL;
2825         int rc = 0;
2826         int bytes_returned;
2827         int name_len;
2828         unsigned int i;
2829         char * temp;
2830         __u16 params, byte_count;
2831         *number_of_UNC_in_array = 0;
2832         *targetUNCs = NULL;
2833
2834         cFYI(1, ("In GetDFSRefer the path %s", searchName));
2835         if (ses == NULL)
2836                 return -ENODEV;
2837 getDFSRetry:
2838         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2839                       (void **) &pSMBr);
2840         if (rc)
2841                 return rc;
2842
2843         pSMB->hdr.Tid = ses->ipc_tid;
2844         pSMB->hdr.Uid = ses->Suid;
2845         if (ses->capabilities & CAP_STATUS32) {
2846                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2847         }
2848         if (ses->capabilities & CAP_DFS) {
2849                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2850         }
2851
2852         if (ses->capabilities & CAP_UNICODE) {
2853                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2854                 name_len =
2855                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
2856                                      searchName, PATH_MAX, nls_codepage, remap);
2857                 name_len++;     /* trailing null */
2858                 name_len *= 2;
2859         } else {                /* BB improve the check for buffer overruns BB */
2860                 name_len = strnlen(searchName, PATH_MAX);
2861                 name_len++;     /* trailing null */
2862                 strncpy(pSMB->RequestFileName, searchName, name_len);
2863         }
2864
2865         params = 2 /* level */  + name_len /*includes null */ ;
2866         pSMB->TotalDataCount = 0;
2867         pSMB->DataCount = 0;
2868         pSMB->DataOffset = 0;
2869         pSMB->MaxParameterCount = 0;
2870         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2871         pSMB->MaxSetupCount = 0;
2872         pSMB->Reserved = 0;
2873         pSMB->Flags = 0;
2874         pSMB->Timeout = 0;
2875         pSMB->Reserved2 = 0;
2876         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2877         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2878         pSMB->SetupCount = 1;
2879         pSMB->Reserved3 = 0;
2880         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2881         byte_count = params + 3 /* pad */ ;
2882         pSMB->ParameterCount = cpu_to_le16(params);
2883         pSMB->TotalParameterCount = pSMB->ParameterCount;
2884         pSMB->MaxReferralLevel = cpu_to_le16(3);
2885         pSMB->hdr.smb_buf_length += byte_count;
2886         pSMB->ByteCount = cpu_to_le16(byte_count);
2887
2888         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2889                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2890         if (rc) {
2891                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2892         } else {                /* decode response */
2893 /* BB Add logic to parse referrals here */
2894                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2895
2896                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
2897                         rc = -EIO;      /* bad smb */
2898                 else {
2899                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
2900                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2901
2902                         cFYI(1,
2903                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
2904                               pSMBr->ByteCount, data_offset));
2905                         referrals = 
2906                             (struct dfs_referral_level_3 *) 
2907                                         (8 /* sizeof start of data block */ +
2908                                         data_offset +
2909                                         (char *) &pSMBr->hdr.Protocol); 
2910                         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",
2911                                 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)));
2912                         /* BB This field is actually two bytes in from start of
2913                            data block so we could do safety check that DataBlock
2914                            begins at address of pSMBr->NumberOfReferrals */
2915                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2916
2917                         /* BB Fix below so can return more than one referral */
2918                         if(*number_of_UNC_in_array > 1)
2919                                 *number_of_UNC_in_array = 1;
2920
2921                         /* get the length of the strings describing refs */
2922                         name_len = 0;
2923                         for(i=0;i<*number_of_UNC_in_array;i++) {
2924                                 /* make sure that DfsPathOffset not past end */
2925                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2926                                 if (offset > data_count) {
2927                                         /* if invalid referral, stop here and do 
2928                                         not try to copy any more */
2929                                         *number_of_UNC_in_array = i;
2930                                         break;
2931                                 } 
2932                                 temp = ((char *)referrals) + offset;
2933
2934                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2935                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
2936                                 } else {
2937                                         name_len += strnlen(temp,data_count);
2938                                 }
2939                                 referrals++;
2940                                 /* BB add check that referral pointer does not fall off end PDU */
2941                                 
2942                         }
2943                         /* BB add check for name_len bigger than bcc */
2944                         *targetUNCs = 
2945                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2946                         if(*targetUNCs == NULL) {
2947                                 rc = -ENOMEM;
2948                                 goto GetDFSRefExit;
2949                         }
2950                         /* copy the ref strings */
2951                         referrals =  
2952                             (struct dfs_referral_level_3 *) 
2953                                         (8 /* sizeof data hdr */ +
2954                                         data_offset + 
2955                                         (char *) &pSMBr->hdr.Protocol);
2956
2957                         for(i=0;i<*number_of_UNC_in_array;i++) {
2958                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
2959                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2960                                         cifs_strfromUCS_le(*targetUNCs,
2961                                                 (wchar_t *) temp, name_len, nls_codepage);
2962                                 } else {
2963                                         strncpy(*targetUNCs,temp,name_len);
2964                                 }
2965                                 /*  BB update target_uncs pointers */
2966                                 referrals++;
2967                         }
2968                         temp = *targetUNCs;
2969                         temp[name_len] = 0;
2970                 }
2971
2972         }
2973 GetDFSRefExit:
2974         if (pSMB)
2975                 cifs_buf_release(pSMB);
2976
2977         if (rc == -EAGAIN)
2978                 goto getDFSRetry;
2979
2980         return rc;
2981 }
2982
2983 int
2984 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
2985 {
2986 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
2987         TRANSACTION2_QFSI_REQ *pSMB = NULL;
2988         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2989         FILE_SYSTEM_INFO *response_data;
2990         int rc = 0;
2991         int bytes_returned = 0;
2992         __u16 params, byte_count;
2993
2994         cFYI(1, ("In QFSInfo"));
2995 QFSInfoRetry:
2996         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2997                       (void **) &pSMBr);
2998         if (rc)
2999                 return rc;
3000
3001         params = 2;     /* level */
3002         pSMB->TotalDataCount = 0;
3003         pSMB->MaxParameterCount = cpu_to_le16(2);
3004         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3005         pSMB->MaxSetupCount = 0;
3006         pSMB->Reserved = 0;
3007         pSMB->Flags = 0;
3008         pSMB->Timeout = 0;
3009         pSMB->Reserved2 = 0;
3010         byte_count = params + 1 /* pad */ ;
3011         pSMB->TotalParameterCount = cpu_to_le16(params);
3012         pSMB->ParameterCount = pSMB->TotalParameterCount;
3013         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3014         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3015         pSMB->DataCount = 0;
3016         pSMB->DataOffset = 0;
3017         pSMB->SetupCount = 1;
3018         pSMB->Reserved3 = 0;
3019         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3020         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3021         pSMB->hdr.smb_buf_length += byte_count;
3022         pSMB->ByteCount = cpu_to_le16(byte_count);
3023
3024         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3025                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3026         if (rc) {
3027                 cERROR(1, ("Send error in QFSInfo = %d", rc));
3028         } else {                /* decode response */
3029                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3030
3031                 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3032                         rc = -EIO;      /* bad smb */
3033                 else {
3034                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3035                         cFYI(1,
3036                                 ("Decoding qfsinfo response.  BCC: %d  Offset %d",
3037                                 pSMBr->ByteCount, data_offset));
3038
3039                         response_data =
3040                             (FILE_SYSTEM_INFO
3041                              *) (((char *) &pSMBr->hdr.Protocol) +
3042                                  data_offset);
3043                         FSData->f_bsize =
3044                             le32_to_cpu(response_data->BytesPerSector) *
3045                             le32_to_cpu(response_data->
3046                                         SectorsPerAllocationUnit);
3047                         FSData->f_blocks =
3048                             le64_to_cpu(response_data->TotalAllocationUnits);
3049                         FSData->f_bfree = FSData->f_bavail =
3050                             le64_to_cpu(response_data->FreeAllocationUnits);
3051                         cFYI(1,
3052                              ("Blocks: %lld  Free: %lld Block size %ld",
3053                               (unsigned long long)FSData->f_blocks,
3054                               (unsigned long long)FSData->f_bfree,
3055                               FSData->f_bsize));
3056                 }
3057         }
3058         cifs_buf_release(pSMB);
3059
3060         if (rc == -EAGAIN)
3061                 goto QFSInfoRetry;
3062
3063         return rc;
3064 }
3065
3066 int
3067 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3068 {
3069 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3070         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3071         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3072         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3073         int rc = 0;
3074         int bytes_returned = 0;
3075         __u16 params, byte_count;
3076
3077         cFYI(1, ("In QFSAttributeInfo"));
3078 QFSAttributeRetry:
3079         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3080                       (void **) &pSMBr);
3081         if (rc)
3082                 return rc;
3083
3084         params = 2;     /* level */
3085         pSMB->TotalDataCount = 0;
3086         pSMB->MaxParameterCount = cpu_to_le16(2);
3087         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3088         pSMB->MaxSetupCount = 0;
3089         pSMB->Reserved = 0;
3090         pSMB->Flags = 0;
3091         pSMB->Timeout = 0;
3092         pSMB->Reserved2 = 0;
3093         byte_count = params + 1 /* pad */ ;
3094         pSMB->TotalParameterCount = cpu_to_le16(params);
3095         pSMB->ParameterCount = pSMB->TotalParameterCount;
3096         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3097         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3098         pSMB->DataCount = 0;
3099         pSMB->DataOffset = 0;
3100         pSMB->SetupCount = 1;
3101         pSMB->Reserved3 = 0;
3102         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3103         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3104         pSMB->hdr.smb_buf_length += byte_count;
3105         pSMB->ByteCount = cpu_to_le16(byte_count);
3106
3107         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3108                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3109         if (rc) {
3110                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3111         } else {                /* decode response */
3112                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3113
3114                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3115                         rc = -EIO;      /* bad smb */
3116                 } else {
3117                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3118                         response_data =
3119                             (FILE_SYSTEM_ATTRIBUTE_INFO
3120                              *) (((char *) &pSMBr->hdr.Protocol) +
3121                                  data_offset);
3122                         memcpy(&tcon->fsAttrInfo, response_data,
3123                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3124                 }
3125         }
3126         cifs_buf_release(pSMB);
3127
3128         if (rc == -EAGAIN)
3129                 goto QFSAttributeRetry;
3130
3131         return rc;
3132 }
3133
3134 int
3135 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3136 {
3137 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3138         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3139         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3140         FILE_SYSTEM_DEVICE_INFO *response_data;
3141         int rc = 0;
3142         int bytes_returned = 0;
3143         __u16 params, byte_count;
3144
3145         cFYI(1, ("In QFSDeviceInfo"));
3146 QFSDeviceRetry:
3147         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3148                       (void **) &pSMBr);
3149         if (rc)
3150                 return rc;
3151
3152         params = 2;     /* level */
3153         pSMB->TotalDataCount = 0;
3154         pSMB->MaxParameterCount = cpu_to_le16(2);
3155         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3156         pSMB->MaxSetupCount = 0;
3157         pSMB->Reserved = 0;
3158         pSMB->Flags = 0;
3159         pSMB->Timeout = 0;
3160         pSMB->Reserved2 = 0;
3161         byte_count = params + 1 /* pad */ ;
3162         pSMB->TotalParameterCount = cpu_to_le16(params);
3163         pSMB->ParameterCount = pSMB->TotalParameterCount;
3164         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3165         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3166
3167         pSMB->DataCount = 0;
3168         pSMB->DataOffset = 0;
3169         pSMB->SetupCount = 1;
3170         pSMB->Reserved3 = 0;
3171         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3172         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3173         pSMB->hdr.smb_buf_length += byte_count;
3174         pSMB->ByteCount = cpu_to_le16(byte_count);
3175
3176         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3177                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3178         if (rc) {
3179                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3180         } else {                /* decode response */
3181                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3182
3183                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3184                         rc = -EIO;      /* bad smb */
3185                 else {
3186                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3187                         response_data =
3188                             (FILE_SYSTEM_DEVICE_INFO *)
3189                                 (((char *) &pSMBr->hdr.Protocol) +
3190                                  data_offset);
3191                         memcpy(&tcon->fsDevInfo, response_data,
3192                                sizeof (FILE_SYSTEM_DEVICE_INFO));
3193                 }
3194         }
3195         cifs_buf_release(pSMB);
3196
3197         if (rc == -EAGAIN)
3198                 goto QFSDeviceRetry;
3199
3200         return rc;
3201 }
3202
3203 int
3204 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3205 {
3206 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
3207         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3208         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3209         FILE_SYSTEM_UNIX_INFO *response_data;
3210         int rc = 0;
3211         int bytes_returned = 0;
3212         __u16 params, byte_count;
3213
3214         cFYI(1, ("In QFSUnixInfo"));
3215 QFSUnixRetry:
3216         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3217                       (void **) &pSMBr);
3218         if (rc)
3219                 return rc;
3220
3221         params = 2;     /* level */
3222         pSMB->TotalDataCount = 0;
3223         pSMB->DataCount = 0;
3224         pSMB->DataOffset = 0;
3225         pSMB->MaxParameterCount = cpu_to_le16(2);
3226         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3227         pSMB->MaxSetupCount = 0;
3228         pSMB->Reserved = 0;
3229         pSMB->Flags = 0;
3230         pSMB->Timeout = 0;
3231         pSMB->Reserved2 = 0;
3232         byte_count = params + 1 /* pad */ ;
3233         pSMB->ParameterCount = cpu_to_le16(params);
3234         pSMB->TotalParameterCount = pSMB->ParameterCount;
3235         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3236         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3237         pSMB->SetupCount = 1;
3238         pSMB->Reserved3 = 0;
3239         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3240         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3241         pSMB->hdr.smb_buf_length += byte_count;
3242         pSMB->ByteCount = cpu_to_le16(byte_count);
3243
3244         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3245                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3246         if (rc) {
3247                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3248         } else {                /* decode response */
3249                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3250
3251                 if (rc || (pSMBr->ByteCount < 13)) {
3252                         rc = -EIO;      /* bad smb */
3253                 } else {
3254                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3255                         response_data =
3256                             (FILE_SYSTEM_UNIX_INFO
3257                              *) (((char *) &pSMBr->hdr.Protocol) +
3258                                  data_offset);
3259                         memcpy(&tcon->fsUnixInfo, response_data,
3260                                sizeof (FILE_SYSTEM_UNIX_INFO));
3261                 }
3262         }
3263         cifs_buf_release(pSMB);
3264
3265         if (rc == -EAGAIN)
3266                 goto QFSUnixRetry;
3267
3268
3269         return rc;
3270 }
3271
3272
3273 int
3274 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3275                    struct kstatfs *FSData)
3276 {
3277 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
3278         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3279         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3280         FILE_SYSTEM_POSIX_INFO *response_data;
3281         int rc = 0;
3282         int bytes_returned = 0;
3283         __u16 params, byte_count;
3284
3285         cFYI(1, ("In QFSPosixInfo"));
3286 QFSPosixRetry:
3287         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3288                       (void **) &pSMBr);
3289         if (rc)
3290                 return rc;
3291
3292         params = 2;     /* level */
3293         pSMB->TotalDataCount = 0;
3294         pSMB->DataCount = 0;
3295         pSMB->DataOffset = 0;
3296         pSMB->MaxParameterCount = cpu_to_le16(2);
3297         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3298         pSMB->MaxSetupCount = 0;
3299         pSMB->Reserved = 0;
3300         pSMB->Flags = 0;
3301         pSMB->Timeout = 0;
3302         pSMB->Reserved2 = 0;
3303         byte_count = params + 1 /* pad */ ;
3304         pSMB->ParameterCount = cpu_to_le16(params);
3305         pSMB->TotalParameterCount = pSMB->ParameterCount;
3306         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3307         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3308         pSMB->SetupCount = 1;
3309         pSMB->Reserved3 = 0;
3310         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3311         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3312         pSMB->hdr.smb_buf_length += byte_count;
3313         pSMB->ByteCount = cpu_to_le16(byte_count);
3314
3315         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3316                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3317         if (rc) {
3318                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3319         } else {                /* decode response */
3320                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3321
3322                 if (rc || (pSMBr->ByteCount < 13)) {
3323                         rc = -EIO;      /* bad smb */
3324                 } else {
3325                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3326                         response_data =
3327                             (FILE_SYSTEM_POSIX_INFO
3328                              *) (((char *) &pSMBr->hdr.Protocol) +
3329                                  data_offset);
3330                         FSData->f_bsize =
3331                                         le32_to_cpu(response_data->BlockSize);
3332                         FSData->f_blocks =
3333                                         le64_to_cpu(response_data->TotalBlocks);
3334                         FSData->f_bfree =
3335                             le64_to_cpu(response_data->BlocksAvail);
3336                         if(response_data->UserBlocksAvail == -1) {
3337                                 FSData->f_bavail = FSData->f_bfree;
3338                         } else {
3339                                 FSData->f_bavail =
3340                                         le64_to_cpu(response_data->UserBlocksAvail);
3341                         }
3342                         if(response_data->TotalFileNodes != -1)
3343                                 FSData->f_files =
3344                                         le64_to_cpu(response_data->TotalFileNodes);
3345                         if(response_data->FreeFileNodes != -1)
3346                                 FSData->f_ffree =
3347                                         le64_to_cpu(response_data->FreeFileNodes);
3348                 }
3349         }
3350         cifs_buf_release(pSMB);
3351
3352         if (rc == -EAGAIN)
3353                 goto QFSPosixRetry;
3354
3355         return rc;
3356 }
3357
3358
3359 /* We can not use write of zero bytes trick to 
3360    set file size due to need for large file support.  Also note that 
3361    this SetPathInfo is preferred to SetFileInfo based method in next 
3362    routine which is only needed to work around a sharing violation bug
3363    in Samba which this routine can run into */
3364
3365 int
3366 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3367               __u64 size, int SetAllocation, 
3368               const struct nls_table *nls_codepage, int remap)
3369 {
3370         struct smb_com_transaction2_spi_req *pSMB = NULL;
3371         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3372         struct file_end_of_file_info *parm_data;
3373         int name_len;
3374         int rc = 0;
3375         int bytes_returned = 0;
3376         __u16 params, byte_count, data_count, param_offset, offset;
3377
3378         cFYI(1, ("In SetEOF"));
3379 SetEOFRetry:
3380         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3381                       (void **) &pSMBr);
3382         if (rc)
3383                 return rc;
3384
3385         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3386                 name_len =
3387                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3388                                      PATH_MAX, nls_codepage, remap);
3389                 name_len++;     /* trailing null */
3390                 name_len *= 2;
3391         } else {                /* BB improve the check for buffer overruns BB */
3392                 name_len = strnlen(fileName, PATH_MAX);
3393                 name_len++;     /* trailing null */
3394                 strncpy(pSMB->FileName, fileName, name_len);
3395         }
3396         params = 6 + name_len;
3397         data_count = sizeof (struct file_end_of_file_info);
3398         pSMB->MaxParameterCount = cpu_to_le16(2);
3399         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3400         pSMB->MaxSetupCount = 0;
3401         pSMB->Reserved = 0;
3402         pSMB->Flags = 0;
3403         pSMB->Timeout = 0;
3404         pSMB->Reserved2 = 0;
3405         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3406                                      InformationLevel) - 4;
3407         offset = param_offset + params;
3408         if(SetAllocation) {
3409                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3410                     pSMB->InformationLevel =
3411                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3412                 else
3413                     pSMB->InformationLevel =
3414                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3415         } else /* Set File Size */  {    
3416             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3417                     pSMB->InformationLevel =
3418                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3419             else
3420                     pSMB->InformationLevel =
3421                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3422         }
3423
3424         parm_data =
3425             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3426                                        offset);
3427         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3428         pSMB->DataOffset = cpu_to_le16(offset);
3429         pSMB->SetupCount = 1;
3430         pSMB->Reserved3 = 0;
3431         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3432         byte_count = 3 /* pad */  + params + data_count;
3433         pSMB->DataCount = cpu_to_le16(data_count);
3434         pSMB->TotalDataCount = pSMB->DataCount;
3435         pSMB->ParameterCount = cpu_to_le16(params);
3436         pSMB->TotalParameterCount = pSMB->ParameterCount;
3437         pSMB->Reserved4 = 0;
3438         pSMB->hdr.smb_buf_length += byte_count;
3439         parm_data->FileSize = cpu_to_le64(size);
3440         pSMB->ByteCount = cpu_to_le16(byte_count);
3441         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3442                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3443         if (rc) {
3444                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3445         }
3446
3447         cifs_buf_release(pSMB);
3448
3449         if (rc == -EAGAIN)
3450                 goto SetEOFRetry;
3451
3452         return rc;
3453 }
3454
3455 int
3456 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
3457                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
3458 {
3459         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
3460         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3461         char *data_offset;
3462         struct file_end_of_file_info *parm_data;
3463         int rc = 0;
3464         int bytes_returned = 0;
3465         __u16 params, param_offset, offset, byte_count, count;
3466
3467         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3468                         (long long)size));
3469         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3470
3471         if (rc)
3472                 return rc;
3473
3474         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3475
3476         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3477         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3478     
3479         params = 6;
3480         pSMB->MaxSetupCount = 0;
3481         pSMB->Reserved = 0;
3482         pSMB->Flags = 0;
3483         pSMB->Timeout = 0;
3484         pSMB->Reserved2 = 0;
3485         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3486         offset = param_offset + params;
3487
3488         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
3489
3490         count = sizeof(struct file_end_of_file_info);
3491         pSMB->MaxParameterCount = cpu_to_le16(2);
3492         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3493         pSMB->SetupCount = 1;
3494         pSMB->Reserved3 = 0;
3495         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3496         byte_count = 3 /* pad */  + params + count;
3497         pSMB->DataCount = cpu_to_le16(count);
3498         pSMB->ParameterCount = cpu_to_le16(params);
3499         pSMB->TotalDataCount = pSMB->DataCount;
3500         pSMB->TotalParameterCount = pSMB->ParameterCount;
3501         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3502         parm_data =
3503                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3504                         offset);
3505         pSMB->DataOffset = cpu_to_le16(offset);
3506         parm_data->FileSize = cpu_to_le64(size);
3507         pSMB->Fid = fid;
3508         if(SetAllocation) {
3509                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3510                         pSMB->InformationLevel =
3511                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3512                 else
3513                         pSMB->InformationLevel =
3514                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3515         } else /* Set File Size */  {    
3516             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3517                     pSMB->InformationLevel =
3518                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3519             else
3520                     pSMB->InformationLevel =
3521                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3522         }
3523         pSMB->Reserved4 = 0;
3524         pSMB->hdr.smb_buf_length += byte_count;
3525         pSMB->ByteCount = cpu_to_le16(byte_count);
3526         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3527                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3528         if (rc) {
3529                 cFYI(1,
3530                      ("Send error in SetFileInfo (SetFileSize) = %d",
3531                       rc));
3532         }
3533
3534         if (pSMB)
3535                 cifs_small_buf_release(pSMB);
3536
3537         /* Note: On -EAGAIN error only caller can retry on handle based calls 
3538                 since file handle passed in no longer valid */
3539
3540         return rc;
3541 }
3542
3543 /* Some legacy servers such as NT4 require that the file times be set on 
3544    an open handle, rather than by pathname - this is awkward due to
3545    potential access conflicts on the open, but it is unavoidable for these
3546    old servers since the only other choice is to go from 100 nanosecond DCE
3547    time and resort to the original setpathinfo level which takes the ancient
3548    DOS time format with 2 second granularity */
3549 int
3550 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
3551                    __u16 fid)
3552 {
3553         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
3554         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3555         char *data_offset;
3556         int rc = 0;
3557         int bytes_returned = 0;
3558         __u16 params, param_offset, offset, byte_count, count;
3559
3560         cFYI(1, ("Set Times (via SetFileInfo)"));
3561         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3562
3563         if (rc)
3564                 return rc;
3565
3566         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3567
3568         /* At this point there is no need to override the current pid
3569         with the pid of the opener, but that could change if we someday
3570         use an existing handle (rather than opening one on the fly) */
3571         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3572         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3573     
3574         params = 6;
3575         pSMB->MaxSetupCount = 0;
3576         pSMB->Reserved = 0;
3577         pSMB->Flags = 0;
3578         pSMB->Timeout = 0;
3579         pSMB->Reserved2 = 0;
3580         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3581         offset = param_offset + params;
3582
3583         data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
3584
3585         count = sizeof (FILE_BASIC_INFO);
3586         pSMB->MaxParameterCount = cpu_to_le16(2);
3587         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3588         pSMB->SetupCount = 1;
3589         pSMB->Reserved3 = 0;
3590         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3591         byte_count = 3 /* pad */  + params + count;
3592         pSMB->DataCount = cpu_to_le16(count);
3593         pSMB->ParameterCount = cpu_to_le16(params);
3594         pSMB->TotalDataCount = pSMB->DataCount;
3595         pSMB->TotalParameterCount = pSMB->ParameterCount;
3596         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3597         pSMB->DataOffset = cpu_to_le16(offset);
3598         pSMB->Fid = fid;
3599         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3600                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3601         else
3602                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3603         pSMB->Reserved4 = 0;
3604         pSMB->hdr.smb_buf_length += byte_count;
3605         pSMB->ByteCount = cpu_to_le16(byte_count);
3606         memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3607         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3608                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3609         if (rc) {
3610                 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3611         }
3612
3613         cifs_small_buf_release(pSMB);
3614
3615         /* Note: On -EAGAIN error only caller can retry on handle based calls 
3616                 since file handle passed in no longer valid */
3617
3618         return rc;
3619 }
3620
3621
3622 int
3623 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3624                 const FILE_BASIC_INFO * data, 
3625                 const struct nls_table *nls_codepage, int remap)
3626 {
3627         TRANSACTION2_SPI_REQ *pSMB = NULL;
3628         TRANSACTION2_SPI_RSP *pSMBr = NULL;
3629         int name_len;
3630         int rc = 0;
3631         int bytes_returned = 0;
3632         char *data_offset;
3633         __u16 params, param_offset, offset, byte_count, count;
3634
3635         cFYI(1, ("In SetTimes"));
3636
3637 SetTimesRetry:
3638         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3639                       (void **) &pSMBr);
3640         if (rc)
3641                 return rc;
3642
3643         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3644                 name_len =
3645                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3646                                      PATH_MAX, nls_codepage, remap);
3647                 name_len++;     /* trailing null */
3648                 name_len *= 2;
3649         } else {                /* BB improve the check for buffer overruns BB */
3650                 name_len = strnlen(fileName, PATH_MAX);
3651                 name_len++;     /* trailing null */
3652                 strncpy(pSMB->FileName, fileName, name_len);
3653         }
3654
3655         params = 6 + name_len;
3656         count = sizeof (FILE_BASIC_INFO);
3657         pSMB->MaxParameterCount = cpu_to_le16(2);
3658         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3659         pSMB->MaxSetupCount = 0;
3660         pSMB->Reserved = 0;
3661         pSMB->Flags = 0;
3662         pSMB->Timeout = 0;
3663         pSMB->Reserved2 = 0;
3664         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3665                                      InformationLevel) - 4;
3666         offset = param_offset + params;
3667         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3668         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3669         pSMB->DataOffset = cpu_to_le16(offset);
3670         pSMB->SetupCount = 1;
3671         pSMB->Reserved3 = 0;
3672         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3673         byte_count = 3 /* pad */  + params + count;
3674
3675         pSMB->DataCount = cpu_to_le16(count);
3676         pSMB->ParameterCount = cpu_to_le16(params);
3677         pSMB->TotalDataCount = pSMB->DataCount;
3678         pSMB->TotalParameterCount = pSMB->ParameterCount;
3679         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3680                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3681         else
3682                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3683         pSMB->Reserved4 = 0;
3684         pSMB->hdr.smb_buf_length += byte_count;
3685         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3686         pSMB->ByteCount = cpu_to_le16(byte_count);
3687         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3688                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3689         if (rc) {
3690                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3691         }
3692
3693         cifs_buf_release(pSMB);
3694
3695         if (rc == -EAGAIN)
3696                 goto SetTimesRetry;
3697
3698         return rc;
3699 }
3700
3701 /* Can not be used to set time stamps yet (due to old DOS time format) */
3702 /* Can be used to set attributes */
3703 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
3704           handling it anyway and NT4 was what we thought it would be needed for
3705           Do not delete it until we prove whether needed for Win9x though */
3706 int
3707 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3708                 __u16 dos_attrs, const struct nls_table *nls_codepage)
3709 {
3710         SETATTR_REQ *pSMB = NULL;
3711         SETATTR_RSP *pSMBr = NULL;
3712         int rc = 0;
3713         int bytes_returned;
3714         int name_len;
3715
3716         cFYI(1, ("In SetAttrLegacy"));
3717
3718 SetAttrLgcyRetry:
3719         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
3720                       (void **) &pSMBr);
3721         if (rc)
3722                 return rc;
3723
3724         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3725                 name_len =
3726                         ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
3727                                 PATH_MAX, nls_codepage);
3728                 name_len++;     /* trailing null */
3729                 name_len *= 2;
3730         } else {                /* BB improve the check for buffer overruns BB */
3731                 name_len = strnlen(fileName, PATH_MAX);
3732                 name_len++;     /* trailing null */
3733                 strncpy(pSMB->fileName, fileName, name_len);
3734         }
3735         pSMB->attr = cpu_to_le16(dos_attrs);
3736         pSMB->BufferFormat = 0x04;
3737         pSMB->hdr.smb_buf_length += name_len + 1;
3738         pSMB->ByteCount = cpu_to_le16(name_len + 1);
3739         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3740                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3741         if (rc) {
3742                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
3743         }
3744
3745         cifs_buf_release(pSMB);
3746
3747         if (rc == -EAGAIN)
3748                 goto SetAttrLgcyRetry;
3749
3750         return rc;
3751 }
3752 #endif /* temporarily unneeded SetAttr legacy function */
3753
3754 int
3755 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
3756                     char *fileName, __u64 mode, __u64 uid, __u64 gid, 
3757                     dev_t device, const struct nls_table *nls_codepage, 
3758                     int remap)
3759 {
3760         TRANSACTION2_SPI_REQ *pSMB = NULL;
3761         TRANSACTION2_SPI_RSP *pSMBr = NULL;
3762         int name_len;
3763         int rc = 0;
3764         int bytes_returned = 0;
3765         FILE_UNIX_BASIC_INFO *data_offset;
3766         __u16 params, param_offset, offset, count, byte_count;
3767
3768         cFYI(1, ("In SetUID/GID/Mode"));
3769 setPermsRetry:
3770         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3771                       (void **) &pSMBr);
3772         if (rc)
3773                 return rc;
3774
3775         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3776                 name_len =
3777                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
3778                                      PATH_MAX, nls_codepage, remap);
3779                 name_len++;     /* trailing null */
3780                 name_len *= 2;
3781         } else {                /* BB improve the check for buffer overruns BB */
3782                 name_len = strnlen(fileName, PATH_MAX);
3783                 name_len++;     /* trailing null */
3784                 strncpy(pSMB->FileName, fileName, name_len);
3785         }
3786
3787         params = 6 + name_len;
3788         count = sizeof (FILE_UNIX_BASIC_INFO);
3789         pSMB->MaxParameterCount = cpu_to_le16(2);
3790         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3791         pSMB->MaxSetupCount = 0;
3792         pSMB->Reserved = 0;
3793         pSMB->Flags = 0;
3794         pSMB->Timeout = 0;
3795         pSMB->Reserved2 = 0;
3796         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3797                                      InformationLevel) - 4;
3798         offset = param_offset + params;
3799         data_offset =
3800             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3801                                       offset);
3802         memset(data_offset, 0, count);
3803         pSMB->DataOffset = cpu_to_le16(offset);
3804         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3805         pSMB->SetupCount = 1;
3806         pSMB->Reserved3 = 0;
3807         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3808         byte_count = 3 /* pad */  + params + count;
3809         pSMB->ParameterCount = cpu_to_le16(params);
3810         pSMB->DataCount = cpu_to_le16(count);
3811         pSMB->TotalParameterCount = pSMB->ParameterCount;
3812         pSMB->TotalDataCount = pSMB->DataCount;
3813         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3814         pSMB->Reserved4 = 0;
3815         pSMB->hdr.smb_buf_length += byte_count;
3816         data_offset->Uid = cpu_to_le64(uid);
3817         data_offset->Gid = cpu_to_le64(gid);
3818         /* better to leave device as zero when it is  */
3819         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3820         data_offset->DevMinor = cpu_to_le64(MINOR(device));
3821         data_offset->Permissions = cpu_to_le64(mode);
3822     
3823         if(S_ISREG(mode))
3824                 data_offset->Type = cpu_to_le32(UNIX_FILE);
3825         else if(S_ISDIR(mode))
3826                 data_offset->Type = cpu_to_le32(UNIX_DIR);
3827         else if(S_ISLNK(mode))
3828                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3829         else if(S_ISCHR(mode))
3830                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3831         else if(S_ISBLK(mode))
3832                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3833         else if(S_ISFIFO(mode))
3834                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
3835         else if(S_ISSOCK(mode))
3836                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3837
3838
3839         pSMB->ByteCount = cpu_to_le16(byte_count);
3840         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3841                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3842         if (rc) {
3843                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3844         }
3845
3846         if (pSMB)
3847                 cifs_buf_release(pSMB);
3848         if (rc == -EAGAIN)
3849                 goto setPermsRetry;
3850         return rc;
3851 }
3852
3853 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
3854                         const int notify_subdirs, const __u16 netfid,
3855                         __u32 filter, const struct nls_table *nls_codepage)
3856 {
3857         int rc = 0;
3858         struct smb_com_transaction_change_notify_req * pSMB = NULL;
3859         struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
3860         int bytes_returned;
3861
3862         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3863         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3864                       (void **) &pSMBr);
3865         if (rc)
3866                 return rc;
3867
3868         pSMB->TotalParameterCount = 0 ;
3869         pSMB->TotalDataCount = 0;
3870         pSMB->MaxParameterCount = cpu_to_le32(2);
3871         /* BB find exact data count max from sess structure BB */
3872         pSMB->MaxDataCount = 0; /* same in little endian or be */
3873         pSMB->MaxSetupCount = 4;
3874         pSMB->Reserved = 0;
3875         pSMB->ParameterOffset = 0;
3876         pSMB->DataCount = 0;
3877         pSMB->DataOffset = 0;
3878         pSMB->SetupCount = 4; /* single byte does not need le conversion */
3879         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
3880         pSMB->ParameterCount = pSMB->TotalParameterCount;
3881         if(notify_subdirs)
3882                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
3883         pSMB->Reserved2 = 0;
3884         pSMB->CompletionFilter = cpu_to_le32(filter);
3885         pSMB->Fid = netfid; /* file handle always le */
3886         pSMB->ByteCount = 0;
3887
3888         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3889                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
3890         if (rc) {
3891                 cFYI(1, ("Error in Notify = %d", rc));
3892         }
3893         cifs_buf_release(pSMB);
3894         return rc;      
3895 }
3896 #ifdef CONFIG_CIFS_XATTR
3897 ssize_t
3898 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3899                  const unsigned char *searchName,
3900                  char * EAData, size_t buf_size,
3901                  const struct nls_table *nls_codepage, int remap)
3902 {
3903                 /* BB assumes one setup word */
3904         TRANSACTION2_QPI_REQ *pSMB = NULL;
3905         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3906         int rc = 0;
3907         int bytes_returned;
3908         int name_len;
3909         struct fea * temp_fea;
3910         char * temp_ptr;
3911         __u16 params, byte_count;
3912
3913         cFYI(1, ("In Query All EAs path %s", searchName));
3914 QAllEAsRetry:
3915         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3916                       (void **) &pSMBr);
3917         if (rc)
3918                 return rc;
3919
3920         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3921                 name_len =
3922                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
3923                                      PATH_MAX, nls_codepage, remap);
3924                 name_len++;     /* trailing null */
3925                 name_len *= 2;
3926         } else {        /* BB improve the check for buffer overruns BB */
3927                 name_len = strnlen(searchName, PATH_MAX);
3928                 name_len++;     /* trailing null */
3929                 strncpy(pSMB->FileName, searchName, name_len);
3930         }
3931
3932         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3933         pSMB->TotalDataCount = 0;
3934         pSMB->MaxParameterCount = cpu_to_le16(2);
3935         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3936         pSMB->MaxSetupCount = 0;
3937         pSMB->Reserved = 0;
3938         pSMB->Flags = 0;
3939         pSMB->Timeout = 0;
3940         pSMB->Reserved2 = 0;
3941         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3942         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3943         pSMB->DataCount = 0;
3944         pSMB->DataOffset = 0;
3945         pSMB->SetupCount = 1;
3946         pSMB->Reserved3 = 0;
3947         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3948         byte_count = params + 1 /* pad */ ;
3949         pSMB->TotalParameterCount = cpu_to_le16(params);
3950         pSMB->ParameterCount = pSMB->TotalParameterCount;
3951         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3952         pSMB->Reserved4 = 0;
3953         pSMB->hdr.smb_buf_length += byte_count;
3954         pSMB->ByteCount = cpu_to_le16(byte_count);
3955
3956         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3957                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3958         if (rc) {
3959                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
3960         } else {                /* decode response */
3961                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3962
3963                 /* BB also check enough total bytes returned */
3964                 /* BB we need to improve the validity checking
3965                 of these trans2 responses */
3966                 if (rc || (pSMBr->ByteCount < 4)) 
3967                         rc = -EIO;      /* bad smb */
3968            /* else if (pFindData){
3969                         memcpy((char *) pFindData,
3970                                (char *) &pSMBr->hdr.Protocol +
3971                                data_offset, kl);
3972                 }*/ else {
3973                         /* check that length of list is not more than bcc */
3974                         /* check that each entry does not go beyond length
3975                            of list */
3976                         /* check that each element of each entry does not
3977                            go beyond end of list */
3978                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3979                         struct fealist * ea_response_data;
3980                         rc = 0;
3981                         /* validate_trans2_offsets() */
3982                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
3983                         ea_response_data = (struct fealist *)
3984                                 (((char *) &pSMBr->hdr.Protocol) +
3985                                 data_offset);
3986                         name_len = le32_to_cpu(ea_response_data->list_len);
3987                         cFYI(1,("ea length %d", name_len));
3988                         if(name_len <= 8) {
3989                         /* returned EA size zeroed at top of function */
3990                                 cFYI(1,("empty EA list returned from server"));
3991                         } else {
3992                                 /* account for ea list len */
3993                                 name_len -= 4;
3994                                 temp_fea = ea_response_data->list;
3995                                 temp_ptr = (char *)temp_fea;
3996                                 while(name_len > 0) {
3997                                         __u16 value_len;
3998                                         name_len -= 4;
3999                                         temp_ptr += 4;
4000                                         rc += temp_fea->name_len;
4001                                 /* account for prefix user. and trailing null */
4002                                         rc = rc + 5 + 1; 
4003                                         if(rc<(int)buf_size) {
4004                                                 memcpy(EAData,"user.",5);
4005                                                 EAData+=5;
4006                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
4007                                                 EAData+=temp_fea->name_len;
4008                                                 /* null terminate name */
4009                                                 *EAData = 0;
4010                                                 EAData = EAData + 1;
4011                                         } else if(buf_size == 0) {
4012                                                 /* skip copy - calc size only */
4013                                         } else {
4014                                                 /* stop before overrun buffer */
4015                                                 rc = -ERANGE;
4016                                                 break;
4017                                         }
4018                                         name_len -= temp_fea->name_len;
4019                                         temp_ptr += temp_fea->name_len;
4020                                         /* account for trailing null */
4021                                         name_len--;
4022                                         temp_ptr++;
4023                                         value_len = le16_to_cpu(temp_fea->value_len);
4024                                         name_len -= value_len;
4025                                         temp_ptr += value_len;
4026                                         /* BB check that temp_ptr is still within smb BB*/
4027                                 /* no trailing null to account for in value len */
4028                                         /* go on to next EA */
4029                                         temp_fea = (struct fea *)temp_ptr;
4030                                 }
4031                         }
4032                 }
4033         }
4034         if (pSMB)
4035                 cifs_buf_release(pSMB);
4036         if (rc == -EAGAIN)
4037                 goto QAllEAsRetry;
4038
4039         return (ssize_t)rc;
4040 }
4041
4042 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4043                 const unsigned char * searchName,const unsigned char * ea_name,
4044                 unsigned char * ea_value, size_t buf_size, 
4045                 const struct nls_table *nls_codepage, int remap)
4046 {
4047         TRANSACTION2_QPI_REQ *pSMB = NULL;
4048         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4049         int rc = 0;
4050         int bytes_returned;
4051         int name_len;
4052         struct fea * temp_fea;
4053         char * temp_ptr;
4054         __u16 params, byte_count;
4055
4056         cFYI(1, ("In Query EA path %s", searchName));
4057 QEARetry:
4058         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4059                       (void **) &pSMBr);
4060         if (rc)
4061                 return rc;
4062
4063         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4064                 name_len =
4065                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4066                                      PATH_MAX, nls_codepage, remap);
4067                 name_len++;     /* trailing null */
4068                 name_len *= 2;
4069         } else {        /* BB improve the check for buffer overruns BB */
4070                 name_len = strnlen(searchName, PATH_MAX);
4071                 name_len++;     /* trailing null */
4072                 strncpy(pSMB->FileName, searchName, name_len);
4073         }
4074
4075         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4076         pSMB->TotalDataCount = 0;
4077         pSMB->MaxParameterCount = cpu_to_le16(2);
4078         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4079         pSMB->MaxSetupCount = 0;
4080         pSMB->Reserved = 0;
4081         pSMB->Flags = 0;
4082         pSMB->Timeout = 0;
4083         pSMB->Reserved2 = 0;
4084         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4085         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4086         pSMB->DataCount = 0;
4087         pSMB->DataOffset = 0;
4088         pSMB->SetupCount = 1;
4089         pSMB->Reserved3 = 0;
4090         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4091         byte_count = params + 1 /* pad */ ;
4092         pSMB->TotalParameterCount = cpu_to_le16(params);
4093         pSMB->ParameterCount = pSMB->TotalParameterCount;
4094         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4095         pSMB->Reserved4 = 0;
4096         pSMB->hdr.smb_buf_length += byte_count;
4097         pSMB->ByteCount = cpu_to_le16(byte_count);
4098
4099         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4100                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4101         if (rc) {
4102                 cFYI(1, ("Send error in Query EA = %d", rc));
4103         } else {                /* decode response */
4104                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4105
4106                 /* BB also check enough total bytes returned */
4107                 /* BB we need to improve the validity checking
4108                 of these trans2 responses */
4109                 if (rc || (pSMBr->ByteCount < 4)) 
4110                         rc = -EIO;      /* bad smb */
4111            /* else if (pFindData){
4112                         memcpy((char *) pFindData,
4113                                (char *) &pSMBr->hdr.Protocol +
4114                                data_offset, kl);
4115                 }*/ else {
4116                         /* check that length of list is not more than bcc */
4117                         /* check that each entry does not go beyond length
4118                            of list */
4119                         /* check that each element of each entry does not
4120                            go beyond end of list */
4121                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4122                         struct fealist * ea_response_data;
4123                         rc = -ENODATA;
4124                         /* validate_trans2_offsets() */
4125                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4126                         ea_response_data = (struct fealist *)
4127                                 (((char *) &pSMBr->hdr.Protocol) +
4128                                 data_offset);
4129                         name_len = le32_to_cpu(ea_response_data->list_len);
4130                         cFYI(1,("ea length %d", name_len));
4131                         if(name_len <= 8) {
4132                         /* returned EA size zeroed at top of function */
4133                                 cFYI(1,("empty EA list returned from server"));
4134                         } else {
4135                                 /* account for ea list len */
4136                                 name_len -= 4;
4137                                 temp_fea = ea_response_data->list;
4138                                 temp_ptr = (char *)temp_fea;
4139                                 /* loop through checking if we have a matching
4140                                 name and then return the associated value */
4141                                 while(name_len > 0) {
4142                                         __u16 value_len;
4143                                         name_len -= 4;
4144                                         temp_ptr += 4;
4145                                         value_len = le16_to_cpu(temp_fea->value_len);
4146                                 /* BB validate that value_len falls within SMB, 
4147                                 even though maximum for name_len is 255 */ 
4148                                         if(memcmp(temp_fea->name,ea_name,
4149                                                   temp_fea->name_len) == 0) {
4150                                                 /* found a match */
4151                                                 rc = value_len;
4152                                 /* account for prefix user. and trailing null */
4153                                                 if(rc<=(int)buf_size) {
4154                                                         memcpy(ea_value,
4155                                                                 temp_fea->name+temp_fea->name_len+1,
4156                                                                 rc);
4157                                                         /* ea values, unlike ea names,
4158                                                         are not null terminated */
4159                                                 } else if(buf_size == 0) {
4160                                                 /* skip copy - calc size only */
4161                                                 } else {
4162                                                         /* stop before overrun buffer */
4163                                                         rc = -ERANGE;
4164                                                 }
4165                                                 break;
4166                                         }
4167                                         name_len -= temp_fea->name_len;
4168                                         temp_ptr += temp_fea->name_len;
4169                                         /* account for trailing null */
4170                                         name_len--;
4171                                         temp_ptr++;
4172                                         name_len -= value_len;
4173                                         temp_ptr += value_len;
4174                                 /* no trailing null to account for in value len */
4175                                         /* go on to next EA */
4176                                         temp_fea = (struct fea *)temp_ptr;
4177                                 }
4178                         } 
4179                 }
4180         }
4181         if (pSMB)
4182                 cifs_buf_release(pSMB);
4183         if (rc == -EAGAIN)
4184                 goto QEARetry;
4185
4186         return (ssize_t)rc;
4187 }
4188
4189 int
4190 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4191                 const char * ea_name, const void * ea_value, 
4192                 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4193                 int remap)
4194 {
4195         struct smb_com_transaction2_spi_req *pSMB = NULL;
4196         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4197         struct fealist *parm_data;
4198         int name_len;
4199         int rc = 0;
4200         int bytes_returned = 0;
4201         __u16 params, param_offset, byte_count, offset, count;
4202
4203         cFYI(1, ("In SetEA"));
4204 SetEARetry:
4205         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4206                       (void **) &pSMBr);
4207         if (rc)
4208                 return rc;
4209
4210         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4211                 name_len =
4212                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4213                                      PATH_MAX, nls_codepage, remap);
4214                 name_len++;     /* trailing null */
4215                 name_len *= 2;
4216         } else {                /* BB improve the check for buffer overruns BB */
4217                 name_len = strnlen(fileName, PATH_MAX);
4218                 name_len++;     /* trailing null */
4219                 strncpy(pSMB->FileName, fileName, name_len);
4220         }
4221
4222         params = 6 + name_len;
4223
4224         /* done calculating parms using name_len of file name,
4225         now use name_len to calculate length of ea name
4226         we are going to create in the inode xattrs */
4227         if(ea_name == NULL)
4228                 name_len = 0;
4229         else
4230                 name_len = strnlen(ea_name,255);
4231
4232         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4233         pSMB->MaxParameterCount = cpu_to_le16(2);
4234         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4235         pSMB->MaxSetupCount = 0;
4236         pSMB->Reserved = 0;
4237         pSMB->Flags = 0;
4238         pSMB->Timeout = 0;
4239         pSMB->Reserved2 = 0;
4240         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4241                                      InformationLevel) - 4;
4242         offset = param_offset + params;
4243         pSMB->InformationLevel =
4244                 cpu_to_le16(SMB_SET_FILE_EA);
4245
4246         parm_data =
4247                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4248                                        offset);
4249         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4250         pSMB->DataOffset = cpu_to_le16(offset);
4251         pSMB->SetupCount = 1;
4252         pSMB->Reserved3 = 0;
4253         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4254         byte_count = 3 /* pad */  + params + count;
4255         pSMB->DataCount = cpu_to_le16(count);
4256         parm_data->list_len = cpu_to_le32(count);
4257         parm_data->list[0].EA_flags = 0;
4258         /* we checked above that name len is less than 255 */
4259         parm_data->list[0].name_len = (__u8)name_len;;
4260         /* EA names are always ASCII */
4261         if(ea_name)
4262                 strncpy(parm_data->list[0].name,ea_name,name_len);
4263         parm_data->list[0].name[name_len] = 0;
4264         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4265         /* caller ensures that ea_value_len is less than 64K but
4266         we need to ensure that it fits within the smb */
4267
4268         /*BB add length check that it would fit in negotiated SMB buffer size BB */
4269         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4270         if(ea_value_len)
4271                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4272
4273         pSMB->TotalDataCount = pSMB->DataCount;
4274         pSMB->ParameterCount = cpu_to_le16(params);
4275         pSMB->TotalParameterCount = pSMB->ParameterCount;
4276         pSMB->Reserved4 = 0;
4277         pSMB->hdr.smb_buf_length += byte_count;
4278         pSMB->ByteCount = cpu_to_le16(byte_count);
4279         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4280                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4281         if (rc) {
4282                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4283         }
4284
4285         cifs_buf_release(pSMB);
4286
4287         if (rc == -EAGAIN)
4288                 goto SetEARetry;
4289
4290         return rc;
4291 }
4292
4293 #endif