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