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