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