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