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