]> git.karo-electronics.de Git - karo-tx-linux.git/blob - fs/cifs/cifssmb.c
[PATCH] Fix handling spurious page fault for hugetlb region
[karo-tx-linux.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
2400                 /* BB fill in */
2401         }
2402
2403         cifs_buf_release(pSMB);
2404         if (rc == -EAGAIN)
2405                 goto findUniqueRetry;
2406
2407         return rc;
2408 }
2409 #endif /* end unused (temporarily) function */
2410
2411 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2412 int
2413 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2414               const char *searchName, 
2415               const struct nls_table *nls_codepage,
2416               __u16 *   pnetfid,
2417               struct cifs_search_info * psrch_inf, int remap)
2418 {
2419 /* level 257 SMB_ */
2420         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2421         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2422         T2_FFIRST_RSP_PARMS * parms;
2423         int rc = 0;
2424         int bytes_returned = 0;
2425         int name_len;
2426         __u16 params, byte_count;
2427
2428         cFYI(1, ("In FindFirst for %s",searchName));
2429
2430 findFirstRetry:
2431         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2432                       (void **) &pSMBr);
2433         if (rc)
2434                 return rc;
2435
2436         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2437                 name_len =
2438                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2439                                  PATH_MAX, nls_codepage, remap);
2440                 /* We can not add the asterik earlier in case
2441                 it got remapped to 0xF03A as if it were part of the
2442                 directory name instead of a wildcard */
2443                 name_len *= 2;
2444                 pSMB->FileName[name_len] = '\\';
2445                 pSMB->FileName[name_len+1] = 0;
2446                 pSMB->FileName[name_len+2] = '*';
2447                 pSMB->FileName[name_len+3] = 0;
2448                 name_len += 4; /* now the trailing null */
2449                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2450                 pSMB->FileName[name_len+1] = 0;
2451                 name_len += 2;
2452         } else {        /* BB add check for overrun of SMB buf BB */
2453                 name_len = strnlen(searchName, PATH_MAX);
2454 /* BB fix here and in unicode clause above ie
2455                 if(name_len > buffersize-header)
2456                         free buffer exit; BB */
2457                 strncpy(pSMB->FileName, searchName, name_len);
2458                 pSMB->FileName[name_len] = '\\';
2459                 pSMB->FileName[name_len+1] = '*';
2460                 pSMB->FileName[name_len+2] = 0;
2461                 name_len += 3;
2462         }
2463
2464         params = 12 + name_len /* includes null */ ;
2465         pSMB->TotalDataCount = 0;       /* no EAs */
2466         pSMB->MaxParameterCount = cpu_to_le16(10);
2467         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2468                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2469         pSMB->MaxSetupCount = 0;
2470         pSMB->Reserved = 0;
2471         pSMB->Flags = 0;
2472         pSMB->Timeout = 0;
2473         pSMB->Reserved2 = 0;
2474         byte_count = params + 1 /* pad */ ;
2475         pSMB->TotalParameterCount = cpu_to_le16(params);
2476         pSMB->ParameterCount = pSMB->TotalParameterCount;
2477         pSMB->ParameterOffset = cpu_to_le16(
2478           offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2479         pSMB->DataCount = 0;
2480         pSMB->DataOffset = 0;
2481         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
2482         pSMB->Reserved3 = 0;
2483         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2484         pSMB->SearchAttributes =
2485             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2486                         ATTR_DIRECTORY);
2487         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2488         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
2489                 CIFS_SEARCH_RETURN_RESUME);
2490         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2491
2492         /* BB what should we set StorageType to? Does it matter? BB */
2493         pSMB->SearchStorageType = 0;
2494         pSMB->hdr.smb_buf_length += byte_count;
2495         pSMB->ByteCount = cpu_to_le16(byte_count);
2496
2497         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2498                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2499
2500         if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2501                 /* BB Add code to handle unsupported level rc */
2502                 cFYI(1, ("Error in FindFirst = %d", rc));
2503
2504                 if (pSMB)
2505                         cifs_buf_release(pSMB);
2506
2507                 /* BB eventually could optimize out free and realloc of buf */
2508                 /*    for this case */
2509                 if (rc == -EAGAIN)
2510                         goto findFirstRetry;
2511         } else { /* decode response */
2512                 /* BB remember to free buffer if error BB */
2513                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2514                 if(rc == 0) {
2515                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2516                                 psrch_inf->unicode = TRUE;
2517                         else
2518                                 psrch_inf->unicode = FALSE;
2519
2520                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2521                         psrch_inf->srch_entries_start = 
2522                                 (char *) &pSMBr->hdr.Protocol + 
2523                                         le16_to_cpu(pSMBr->t2.DataOffset);
2524                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2525                                le16_to_cpu(pSMBr->t2.ParameterOffset));
2526
2527                         if(parms->EndofSearch)
2528                                 psrch_inf->endOfSearch = TRUE;
2529                         else
2530                                 psrch_inf->endOfSearch = FALSE;
2531
2532                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2533                         psrch_inf->index_of_last_entry = 
2534                                 psrch_inf->entries_in_buffer;
2535                         *pnetfid = parms->SearchHandle;
2536                 } else {
2537                         cifs_buf_release(pSMB);
2538                 }
2539         }
2540
2541         return rc;
2542 }
2543
2544 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2545             __u16 searchHandle, struct cifs_search_info * psrch_inf)
2546 {
2547         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2548         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2549         T2_FNEXT_RSP_PARMS * parms;
2550         char *response_data;
2551         int rc = 0;
2552         int bytes_returned, name_len;
2553         __u16 params, byte_count;
2554
2555         cFYI(1, ("In FindNext"));
2556
2557         if(psrch_inf->endOfSearch == TRUE)
2558                 return -ENOENT;
2559
2560         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2561                 (void **) &pSMBr);
2562         if (rc)
2563                 return rc;
2564
2565         params = 14;    /* includes 2 bytes of null string, converted to LE below */
2566         byte_count = 0;
2567         pSMB->TotalDataCount = 0;       /* no EAs */
2568         pSMB->MaxParameterCount = cpu_to_le16(8);
2569         pSMB->MaxDataCount =
2570             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2571         pSMB->MaxSetupCount = 0;
2572         pSMB->Reserved = 0;
2573         pSMB->Flags = 0;
2574         pSMB->Timeout = 0;
2575         pSMB->Reserved2 = 0;
2576         pSMB->ParameterOffset =  cpu_to_le16(
2577               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2578         pSMB->DataCount = 0;
2579         pSMB->DataOffset = 0;
2580         pSMB->SetupCount = 1;
2581         pSMB->Reserved3 = 0;
2582         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2583         pSMB->SearchHandle = searchHandle;      /* always kept as le */
2584         pSMB->SearchCount =
2585                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2586         /* test for Unix extensions */
2587 /*      if (tcon->ses->capabilities & CAP_UNIX) {
2588                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2589                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2590         } else {
2591                 pSMB->InformationLevel =
2592                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2593                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2594         } */
2595         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2596         pSMB->ResumeKey = psrch_inf->resume_key;
2597         pSMB->SearchFlags =
2598               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2599
2600         name_len = psrch_inf->resume_name_len;
2601         params += name_len;
2602         if(name_len < PATH_MAX) {
2603                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2604                 byte_count += name_len;
2605                 /* 14 byte parm len above enough for 2 byte null terminator */
2606                 pSMB->ResumeFileName[name_len] = 0;
2607                 pSMB->ResumeFileName[name_len+1] = 0;
2608         } else {
2609                 rc = -EINVAL;
2610                 goto FNext2_err_exit;
2611         }
2612         byte_count = params + 1 /* pad */ ;
2613         pSMB->TotalParameterCount = cpu_to_le16(params);
2614         pSMB->ParameterCount = pSMB->TotalParameterCount;
2615         pSMB->hdr.smb_buf_length += byte_count;
2616         pSMB->ByteCount = cpu_to_le16(byte_count);
2617                                                                                               
2618         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2619                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2620                                                                                               
2621         if (rc) {
2622                 if (rc == -EBADF) {
2623                         psrch_inf->endOfSearch = TRUE;
2624                         rc = 0; /* search probably was closed at end of search above */
2625                 } else
2626                         cFYI(1, ("FindNext returned = %d", rc));
2627         } else {                /* decode response */
2628                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2629                 
2630                 if(rc == 0) {
2631                         /* BB fixme add lock for file (srch_info) struct here */
2632                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2633                                 psrch_inf->unicode = TRUE;
2634                         else
2635                                 psrch_inf->unicode = FALSE;
2636                         response_data = (char *) &pSMBr->hdr.Protocol +
2637                                le16_to_cpu(pSMBr->t2.ParameterOffset);
2638                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
2639                         response_data = (char *)&pSMBr->hdr.Protocol +
2640                                 le16_to_cpu(pSMBr->t2.DataOffset);
2641                         cifs_buf_release(psrch_inf->ntwrk_buf_start);
2642                         psrch_inf->srch_entries_start = response_data;
2643                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
2644                         if(parms->EndofSearch)
2645                                 psrch_inf->endOfSearch = TRUE;
2646                         else
2647                                 psrch_inf->endOfSearch = FALSE;
2648                                                                                               
2649                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2650                         psrch_inf->index_of_last_entry +=
2651                                 psrch_inf->entries_in_buffer;
2652 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2653
2654                         /* BB fixme add unlock here */
2655                 }
2656
2657         }
2658
2659         /* BB On error, should we leave previous search buf (and count and
2660         last entry fields) intact or free the previous one? */
2661
2662         /* Note: On -EAGAIN error only caller can retry on handle based calls
2663         since file handle passed in no longer valid */
2664 FNext2_err_exit:
2665         if (rc != 0)
2666                 cifs_buf_release(pSMB);
2667                                                                                               
2668         return rc;
2669 }
2670
2671 int
2672 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2673 {
2674         int rc = 0;
2675         FINDCLOSE_REQ *pSMB = NULL;
2676         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2677         int bytes_returned;
2678
2679         cFYI(1, ("In CIFSSMBFindClose"));
2680         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2681
2682         /* no sense returning error if session restarted
2683                 as file handle has been closed */
2684         if(rc == -EAGAIN)
2685                 return 0;
2686         if (rc)
2687                 return rc;
2688
2689         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
2690         pSMB->FileID = searchHandle;
2691         pSMB->ByteCount = 0;
2692         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2693                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2694         if (rc) {
2695                 cERROR(1, ("Send error in FindClose = %d", rc));
2696         }
2697         cifs_small_buf_release(pSMB);
2698
2699         /* Since session is dead, search handle closed on server already */
2700         if (rc == -EAGAIN)
2701                 rc = 0;
2702
2703         return rc;
2704 }
2705
2706 #ifdef CONFIG_CIFS_EXPERIMENTAL
2707 int
2708 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2709                 const unsigned char *searchName,
2710                 __u64 * inode_number,
2711                 const struct nls_table *nls_codepage, int remap)
2712 {
2713         int rc = 0;
2714         TRANSACTION2_QPI_REQ *pSMB = NULL;
2715         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2716         int name_len, bytes_returned;
2717         __u16 params, byte_count;
2718
2719         cFYI(1,("In GetSrvInodeNum for %s",searchName));
2720         if(tcon == NULL)
2721                 return -ENODEV; 
2722
2723 GetInodeNumberRetry:
2724         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2725                       (void **) &pSMBr);
2726         if (rc)
2727                 return rc;
2728
2729
2730         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2731                 name_len =
2732                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2733                                 PATH_MAX,nls_codepage, remap);
2734                 name_len++;     /* trailing null */
2735                 name_len *= 2;
2736         } else {                /* BB improve the check for buffer overruns BB */
2737                 name_len = strnlen(searchName, PATH_MAX);
2738                 name_len++;     /* trailing null */
2739                 strncpy(pSMB->FileName, searchName, name_len);
2740         }
2741
2742         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2743         pSMB->TotalDataCount = 0;
2744         pSMB->MaxParameterCount = cpu_to_le16(2);
2745         /* BB find exact max data count below from sess structure BB */
2746         pSMB->MaxDataCount = cpu_to_le16(4000);
2747         pSMB->MaxSetupCount = 0;
2748         pSMB->Reserved = 0;
2749         pSMB->Flags = 0;
2750         pSMB->Timeout = 0;
2751         pSMB->Reserved2 = 0;
2752         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2753                 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2754         pSMB->DataCount = 0;
2755         pSMB->DataOffset = 0;
2756         pSMB->SetupCount = 1;
2757         pSMB->Reserved3 = 0;
2758         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2759         byte_count = params + 1 /* pad */ ;
2760         pSMB->TotalParameterCount = cpu_to_le16(params);
2761         pSMB->ParameterCount = pSMB->TotalParameterCount;
2762         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
2763         pSMB->Reserved4 = 0;
2764         pSMB->hdr.smb_buf_length += byte_count;
2765         pSMB->ByteCount = cpu_to_le16(byte_count);
2766
2767         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2768                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2769         if (rc) {
2770                 cFYI(1, ("error %d in QueryInternalInfo", rc));
2771         } else {
2772                 /* decode response */
2773                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2774                 if (rc || (pSMBr->ByteCount < 2))
2775                 /* BB also check enough total bytes returned */
2776                         /* If rc should we check for EOPNOSUPP and
2777                         disable the srvino flag? or in caller? */
2778                         rc = -EIO;      /* bad smb */
2779                 else {
2780                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2781                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2782                         struct file_internal_info * pfinfo;
2783                         /* BB Do we need a cast or hash here ? */
2784                         if(count < 8) {
2785                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
2786                                 rc = -EIO;
2787                                 goto GetInodeNumOut;
2788                         }
2789                         pfinfo = (struct file_internal_info *)
2790                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2791                         *inode_number = pfinfo->UniqueId;
2792                 }
2793         }
2794 GetInodeNumOut:
2795         cifs_buf_release(pSMB);
2796         if (rc == -EAGAIN)
2797                 goto GetInodeNumberRetry;
2798         return rc;
2799 }
2800 #endif /* CIFS_EXPERIMENTAL */
2801
2802 int
2803 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2804                 const unsigned char *searchName,
2805                 unsigned char **targetUNCs,
2806                 unsigned int *number_of_UNC_in_array,
2807                 const struct nls_table *nls_codepage, int remap)
2808 {
2809 /* TRANS2_GET_DFS_REFERRAL */
2810         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2811         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2812         struct dfs_referral_level_3 * referrals = NULL;
2813         int rc = 0;
2814         int bytes_returned;
2815         int name_len;
2816         unsigned int i;
2817         char * temp;
2818         __u16 params, byte_count;
2819         *number_of_UNC_in_array = 0;
2820         *targetUNCs = NULL;
2821
2822         cFYI(1, ("In GetDFSRefer the path %s", searchName));
2823         if (ses == NULL)
2824                 return -ENODEV;
2825 getDFSRetry:
2826         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2827                       (void **) &pSMBr);
2828         if (rc)
2829                 return rc;
2830
2831         pSMB->hdr.Tid = ses->ipc_tid;
2832         pSMB->hdr.Uid = ses->Suid;
2833         if (ses->capabilities & CAP_STATUS32) {
2834                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2835         }
2836         if (ses->capabilities & CAP_DFS) {
2837                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2838         }
2839
2840         if (ses->capabilities & CAP_UNICODE) {
2841                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2842                 name_len =
2843                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
2844                                      searchName, PATH_MAX, nls_codepage, remap);
2845                 name_len++;     /* trailing null */
2846                 name_len *= 2;
2847         } else {                /* BB improve the check for buffer overruns BB */
2848                 name_len = strnlen(searchName, PATH_MAX);
2849                 name_len++;     /* trailing null */
2850                 strncpy(pSMB->RequestFileName, searchName, name_len);
2851         }
2852
2853         params = 2 /* level */  + name_len /*includes null */ ;
2854         pSMB->TotalDataCount = 0;
2855         pSMB->DataCount = 0;
2856         pSMB->DataOffset = 0;
2857         pSMB->MaxParameterCount = 0;
2858         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2859         pSMB->MaxSetupCount = 0;
2860         pSMB->Reserved = 0;
2861         pSMB->Flags = 0;
2862         pSMB->Timeout = 0;
2863         pSMB->Reserved2 = 0;
2864         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2865         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2866         pSMB->SetupCount = 1;
2867         pSMB->Reserved3 = 0;
2868         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2869         byte_count = params + 3 /* pad */ ;
2870         pSMB->ParameterCount = cpu_to_le16(params);
2871         pSMB->TotalParameterCount = pSMB->ParameterCount;
2872         pSMB->MaxReferralLevel = cpu_to_le16(3);
2873         pSMB->hdr.smb_buf_length += byte_count;
2874         pSMB->ByteCount = cpu_to_le16(byte_count);
2875
2876         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2877                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2878         if (rc) {
2879                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2880         } else {                /* decode response */
2881 /* BB Add logic to parse referrals here */
2882                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2883
2884                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
2885                         rc = -EIO;      /* bad smb */
2886                 else {
2887                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
2888                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2889
2890                         cFYI(1,
2891                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
2892                               pSMBr->ByteCount, data_offset));
2893                         referrals = 
2894                             (struct dfs_referral_level_3 *) 
2895                                         (8 /* sizeof start of data block */ +
2896                                         data_offset +
2897                                         (char *) &pSMBr->hdr.Protocol); 
2898                         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",
2899                                 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)));
2900                         /* BB This field is actually two bytes in from start of
2901                            data block so we could do safety check that DataBlock
2902                            begins at address of pSMBr->NumberOfReferrals */
2903                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2904
2905                         /* BB Fix below so can return more than one referral */
2906                         if(*number_of_UNC_in_array > 1)
2907                                 *number_of_UNC_in_array = 1;
2908
2909                         /* get the length of the strings describing refs */
2910                         name_len = 0;
2911                         for(i=0;i<*number_of_UNC_in_array;i++) {
2912                                 /* make sure that DfsPathOffset not past end */
2913                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2914                                 if (offset > data_count) {
2915                                         /* if invalid referral, stop here and do 
2916                                         not try to copy any more */
2917                                         *number_of_UNC_in_array = i;
2918                                         break;
2919                                 } 
2920                                 temp = ((char *)referrals) + offset;
2921
2922                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2923                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
2924                                 } else {
2925                                         name_len += strnlen(temp,data_count);
2926                                 }
2927                                 referrals++;
2928                                 /* BB add check that referral pointer does not fall off end PDU */
2929                                 
2930                         }
2931                         /* BB add check for name_len bigger than bcc */
2932                         *targetUNCs = 
2933                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2934                         if(*targetUNCs == NULL) {
2935                                 rc = -ENOMEM;
2936                                 goto GetDFSRefExit;
2937                         }
2938                         /* copy the ref strings */
2939                         referrals =  
2940                             (struct dfs_referral_level_3 *) 
2941                                         (8 /* sizeof data hdr */ +
2942                                         data_offset + 
2943                                         (char *) &pSMBr->hdr.Protocol);
2944
2945                         for(i=0;i<*number_of_UNC_in_array;i++) {
2946                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
2947                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2948                                         cifs_strfromUCS_le(*targetUNCs,
2949                                                 (wchar_t *) temp, name_len, nls_codepage);
2950                                 } else {
2951                                         strncpy(*targetUNCs,temp,name_len);
2952                                 }
2953                                 /*  BB update target_uncs pointers */
2954                                 referrals++;
2955                         }
2956                         temp = *targetUNCs;
2957                         temp[name_len] = 0;
2958                 }
2959
2960         }
2961 GetDFSRefExit:
2962         if (pSMB)
2963                 cifs_buf_release(pSMB);
2964
2965         if (rc == -EAGAIN)
2966                 goto getDFSRetry;
2967
2968         return rc;
2969 }
2970
2971 int
2972 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
2973 {
2974 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
2975         TRANSACTION2_QFSI_REQ *pSMB = NULL;
2976         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2977         FILE_SYSTEM_INFO *response_data;
2978         int rc = 0;
2979         int bytes_returned = 0;
2980         __u16 params, byte_count;
2981
2982         cFYI(1, ("In QFSInfo"));
2983 QFSInfoRetry:
2984         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2985                       (void **) &pSMBr);
2986         if (rc)
2987                 return rc;
2988
2989         params = 2;     /* level */
2990         pSMB->TotalDataCount = 0;
2991         pSMB->MaxParameterCount = cpu_to_le16(2);
2992         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2993         pSMB->MaxSetupCount = 0;
2994         pSMB->Reserved = 0;
2995         pSMB->Flags = 0;
2996         pSMB->Timeout = 0;
2997         pSMB->Reserved2 = 0;
2998         byte_count = params + 1 /* pad */ ;
2999         pSMB->TotalParameterCount = cpu_to_le16(params);
3000         pSMB->ParameterCount = pSMB->TotalParameterCount;
3001         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3002         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3003         pSMB->DataCount = 0;
3004         pSMB->DataOffset = 0;
3005         pSMB->SetupCount = 1;
3006         pSMB->Reserved3 = 0;
3007         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3008         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3009         pSMB->hdr.smb_buf_length += byte_count;
3010         pSMB->ByteCount = cpu_to_le16(byte_count);
3011
3012         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3013                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3014         if (rc) {
3015                 cERROR(1, ("Send error in QFSInfo = %d", rc));
3016         } else {                /* decode response */
3017                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3018
3019                 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3020                         rc = -EIO;      /* bad smb */
3021                 else {
3022                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3023                         cFYI(1,
3024                                 ("Decoding qfsinfo response.  BCC: %d  Offset %d",
3025                                 pSMBr->ByteCount, data_offset));
3026
3027                         response_data =
3028                             (FILE_SYSTEM_INFO
3029                              *) (((char *) &pSMBr->hdr.Protocol) +
3030                                  data_offset);
3031                         FSData->f_bsize =
3032                             le32_to_cpu(response_data->BytesPerSector) *
3033                             le32_to_cpu(response_data->
3034                                         SectorsPerAllocationUnit);
3035                         FSData->f_blocks =
3036                             le64_to_cpu(response_data->TotalAllocationUnits);
3037                         FSData->f_bfree = FSData->f_bavail =
3038                             le64_to_cpu(response_data->FreeAllocationUnits);
3039                         cFYI(1,
3040                              ("Blocks: %lld  Free: %lld Block size %ld",
3041                               (unsigned long long)FSData->f_blocks,
3042                               (unsigned long long)FSData->f_bfree,
3043                               FSData->f_bsize));
3044                 }
3045         }
3046         cifs_buf_release(pSMB);
3047
3048         if (rc == -EAGAIN)
3049                 goto QFSInfoRetry;
3050
3051         return rc;
3052 }
3053
3054 int
3055 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3056 {
3057 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3058         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3059         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3060         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3061         int rc = 0;
3062         int bytes_returned = 0;
3063         __u16 params, byte_count;
3064
3065         cFYI(1, ("In QFSAttributeInfo"));
3066 QFSAttributeRetry:
3067         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3068                       (void **) &pSMBr);
3069         if (rc)
3070                 return rc;
3071
3072         params = 2;     /* level */
3073         pSMB->TotalDataCount = 0;
3074         pSMB->MaxParameterCount = cpu_to_le16(2);
3075         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3076         pSMB->MaxSetupCount = 0;
3077         pSMB->Reserved = 0;
3078         pSMB->Flags = 0;
3079         pSMB->Timeout = 0;
3080         pSMB->Reserved2 = 0;
3081         byte_count = params + 1 /* pad */ ;
3082         pSMB->TotalParameterCount = cpu_to_le16(params);
3083         pSMB->ParameterCount = pSMB->TotalParameterCount;
3084         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3085         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3086         pSMB->DataCount = 0;
3087         pSMB->DataOffset = 0;
3088         pSMB->SetupCount = 1;
3089         pSMB->Reserved3 = 0;
3090         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3091         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3092         pSMB->hdr.smb_buf_length += byte_count;
3093         pSMB->ByteCount = cpu_to_le16(byte_count);
3094
3095         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3096                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3097         if (rc) {
3098                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3099         } else {                /* decode response */
3100                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3101
3102                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3103                         rc = -EIO;      /* bad smb */
3104                 } else {
3105                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3106                         response_data =
3107                             (FILE_SYSTEM_ATTRIBUTE_INFO
3108                              *) (((char *) &pSMBr->hdr.Protocol) +
3109                                  data_offset);
3110                         memcpy(&tcon->fsAttrInfo, response_data,
3111                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3112                 }
3113         }
3114         cifs_buf_release(pSMB);
3115
3116         if (rc == -EAGAIN)
3117                 goto QFSAttributeRetry;
3118
3119         return rc;
3120 }
3121
3122 int
3123 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3124 {
3125 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3126         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3127         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3128         FILE_SYSTEM_DEVICE_INFO *response_data;
3129         int rc = 0;
3130         int bytes_returned = 0;
3131         __u16 params, byte_count;
3132
3133         cFYI(1, ("In QFSDeviceInfo"));
3134 QFSDeviceRetry:
3135         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3136                       (void **) &pSMBr);
3137         if (rc)
3138                 return rc;
3139
3140         params = 2;     /* level */
3141         pSMB->TotalDataCount = 0;
3142         pSMB->MaxParameterCount = cpu_to_le16(2);
3143         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3144         pSMB->MaxSetupCount = 0;
3145         pSMB->Reserved = 0;
3146         pSMB->Flags = 0;
3147         pSMB->Timeout = 0;
3148         pSMB->Reserved2 = 0;
3149         byte_count = params + 1 /* pad */ ;
3150         pSMB->TotalParameterCount = cpu_to_le16(params);
3151         pSMB->ParameterCount = pSMB->TotalParameterCount;
3152         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3153         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3154
3155         pSMB->DataCount = 0;
3156         pSMB->DataOffset = 0;
3157         pSMB->SetupCount = 1;
3158         pSMB->Reserved3 = 0;
3159         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3160         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3161         pSMB->hdr.smb_buf_length += byte_count;
3162         pSMB->ByteCount = cpu_to_le16(byte_count);
3163
3164         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3165                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3166         if (rc) {
3167                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3168         } else {                /* decode response */
3169                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3170
3171                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3172                         rc = -EIO;      /* bad smb */
3173                 else {
3174                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3175                         response_data =
3176                             (FILE_SYSTEM_DEVICE_INFO *)
3177                                 (((char *) &pSMBr->hdr.Protocol) +
3178                                  data_offset);
3179                         memcpy(&tcon->fsDevInfo, response_data,
3180                                sizeof (FILE_SYSTEM_DEVICE_INFO));
3181                 }
3182         }
3183         cifs_buf_release(pSMB);
3184
3185         if (rc == -EAGAIN)
3186                 goto QFSDeviceRetry;
3187
3188         return rc;
3189 }
3190
3191 int
3192 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3193 {
3194 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
3195         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3196         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3197         FILE_SYSTEM_UNIX_INFO *response_data;
3198         int rc = 0;
3199         int bytes_returned = 0;
3200         __u16 params, byte_count;
3201
3202         cFYI(1, ("In QFSUnixInfo"));
3203 QFSUnixRetry:
3204         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3205                       (void **) &pSMBr);
3206         if (rc)
3207                 return rc;
3208
3209         params = 2;     /* level */
3210         pSMB->TotalDataCount = 0;
3211         pSMB->DataCount = 0;
3212         pSMB->DataOffset = 0;
3213         pSMB->MaxParameterCount = cpu_to_le16(2);
3214         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3215         pSMB->MaxSetupCount = 0;
3216         pSMB->Reserved = 0;
3217         pSMB->Flags = 0;
3218         pSMB->Timeout = 0;
3219         pSMB->Reserved2 = 0;
3220         byte_count = params + 1 /* pad */ ;
3221         pSMB->ParameterCount = cpu_to_le16(params);
3222         pSMB->TotalParameterCount = pSMB->ParameterCount;
3223         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3224         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3225         pSMB->SetupCount = 1;
3226         pSMB->Reserved3 = 0;
3227         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3228         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3229         pSMB->hdr.smb_buf_length += byte_count;
3230         pSMB->ByteCount = cpu_to_le16(byte_count);
3231
3232         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3233                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3234         if (rc) {
3235                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3236         } else {                /* decode response */
3237                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3238
3239                 if (rc || (pSMBr->ByteCount < 13)) {
3240                         rc = -EIO;      /* bad smb */
3241                 } else {
3242                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3243                         response_data =
3244                             (FILE_SYSTEM_UNIX_INFO
3245                              *) (((char *) &pSMBr->hdr.Protocol) +
3246                                  data_offset);
3247                         memcpy(&tcon->fsUnixInfo, response_data,
3248                                sizeof (FILE_SYSTEM_UNIX_INFO));
3249                 }
3250         }
3251         cifs_buf_release(pSMB);
3252
3253         if (rc == -EAGAIN)
3254                 goto QFSUnixRetry;
3255
3256
3257         return rc;
3258 }
3259
3260
3261 int
3262 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3263                    struct kstatfs *FSData)
3264 {
3265 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
3266         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3267         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3268         FILE_SYSTEM_POSIX_INFO *response_data;
3269         int rc = 0;
3270         int bytes_returned = 0;
3271         __u16 params, byte_count;
3272
3273         cFYI(1, ("In QFSPosixInfo"));
3274 QFSPosixRetry:
3275         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3276                       (void **) &pSMBr);
3277         if (rc)
3278                 return rc;
3279
3280         params = 2;     /* level */
3281         pSMB->TotalDataCount = 0;
3282         pSMB->DataCount = 0;
3283         pSMB->DataOffset = 0;
3284         pSMB->MaxParameterCount = cpu_to_le16(2);
3285         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3286         pSMB->MaxSetupCount = 0;
3287         pSMB->Reserved = 0;
3288         pSMB->Flags = 0;
3289         pSMB->Timeout = 0;
3290         pSMB->Reserved2 = 0;
3291         byte_count = params + 1 /* pad */ ;
3292         pSMB->ParameterCount = cpu_to_le16(params);
3293         pSMB->TotalParameterCount = pSMB->ParameterCount;
3294         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3295         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3296         pSMB->SetupCount = 1;
3297         pSMB->Reserved3 = 0;
3298         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3299         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3300         pSMB->hdr.smb_buf_length += byte_count;
3301         pSMB->ByteCount = cpu_to_le16(byte_count);
3302
3303         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3304                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3305         if (rc) {
3306                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3307         } else {                /* decode response */
3308                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3309
3310                 if (rc || (pSMBr->ByteCount < 13)) {
3311                         rc = -EIO;      /* bad smb */
3312                 } else {
3313                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3314                         response_data =
3315                             (FILE_SYSTEM_POSIX_INFO
3316                              *) (((char *) &pSMBr->hdr.Protocol) +
3317                                  data_offset);
3318                         FSData->f_bsize =
3319                                         le32_to_cpu(response_data->BlockSize);
3320                         FSData->f_blocks =
3321                                         le64_to_cpu(response_data->TotalBlocks);
3322                         FSData->f_bfree =
3323                             le64_to_cpu(response_data->BlocksAvail);
3324                         if(response_data->UserBlocksAvail == -1) {
3325                                 FSData->f_bavail = FSData->f_bfree;
3326                         } else {
3327                                 FSData->f_bavail =
3328                                         le64_to_cpu(response_data->UserBlocksAvail);
3329                         }
3330                         if(response_data->TotalFileNodes != -1)
3331                                 FSData->f_files =
3332                                         le64_to_cpu(response_data->TotalFileNodes);
3333                         if(response_data->FreeFileNodes != -1)
3334                                 FSData->f_ffree =
3335                                         le64_to_cpu(response_data->FreeFileNodes);
3336                 }
3337         }
3338         cifs_buf_release(pSMB);
3339
3340         if (rc == -EAGAIN)
3341                 goto QFSPosixRetry;
3342
3343         return rc;
3344 }
3345
3346
3347 /* We can not use write of zero bytes trick to 
3348    set file size due to need for large file support.  Also note that 
3349    this SetPathInfo is preferred to SetFileInfo based method in next 
3350    routine which is only needed to work around a sharing violation bug
3351    in Samba which this routine can run into */
3352
3353 int
3354 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3355               __u64 size, int SetAllocation, 
3356               const struct nls_table *nls_codepage, int remap)
3357 {
3358         struct smb_com_transaction2_spi_req *pSMB = NULL;
3359         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3360         struct file_end_of_file_info *parm_data;
3361         int name_len;
3362         int rc = 0;
3363         int bytes_returned = 0;
3364         __u16 params, byte_count, data_count, param_offset, offset;
3365
3366         cFYI(1, ("In SetEOF"));
3367 SetEOFRetry:
3368         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3369                       (void **) &pSMBr);
3370         if (rc)
3371                 return rc;
3372
3373         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3374                 name_len =
3375                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3376                                      PATH_MAX, nls_codepage, remap);
3377                 name_len++;     /* trailing null */
3378                 name_len *= 2;
3379         } else {                /* BB improve the check for buffer overruns BB */
3380                 name_len = strnlen(fileName, PATH_MAX);
3381                 name_len++;     /* trailing null */
3382                 strncpy(pSMB->FileName, fileName, name_len);
3383         }
3384         params = 6 + name_len;
3385         data_count = sizeof (struct file_end_of_file_info);
3386         pSMB->MaxParameterCount = cpu_to_le16(2);
3387         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3388         pSMB->MaxSetupCount = 0;
3389         pSMB->Reserved = 0;
3390         pSMB->Flags = 0;
3391         pSMB->Timeout = 0;
3392         pSMB->Reserved2 = 0;
3393         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3394                                      InformationLevel) - 4;
3395         offset = param_offset + params;
3396         if(SetAllocation) {
3397                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3398                     pSMB->InformationLevel =
3399                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3400                 else
3401                     pSMB->InformationLevel =
3402                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3403         } else /* Set File Size */  {    
3404             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3405                     pSMB->InformationLevel =
3406                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3407             else
3408                     pSMB->InformationLevel =
3409                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3410         }
3411
3412         parm_data =
3413             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3414                                        offset);
3415         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3416         pSMB->DataOffset = cpu_to_le16(offset);
3417         pSMB->SetupCount = 1;
3418         pSMB->Reserved3 = 0;
3419         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3420         byte_count = 3 /* pad */  + params + data_count;
3421         pSMB->DataCount = cpu_to_le16(data_count);
3422         pSMB->TotalDataCount = pSMB->DataCount;
3423         pSMB->ParameterCount = cpu_to_le16(params);
3424         pSMB->TotalParameterCount = pSMB->ParameterCount;
3425         pSMB->Reserved4 = 0;
3426         pSMB->hdr.smb_buf_length += byte_count;
3427         parm_data->FileSize = cpu_to_le64(size);
3428         pSMB->ByteCount = cpu_to_le16(byte_count);
3429         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3430                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3431         if (rc) {
3432                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3433         }
3434
3435         cifs_buf_release(pSMB);
3436
3437         if (rc == -EAGAIN)
3438                 goto SetEOFRetry;
3439
3440         return rc;
3441 }
3442
3443 int
3444 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
3445                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
3446 {
3447         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
3448         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3449         char *data_offset;
3450         struct file_end_of_file_info *parm_data;
3451         int rc = 0;
3452         int bytes_returned = 0;
3453         __u16 params, param_offset, offset, byte_count, count;
3454
3455         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3456                         (long long)size));
3457         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3458
3459         if (rc)
3460                 return rc;
3461
3462         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3463
3464         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3465         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3466     
3467         params = 6;
3468         pSMB->MaxSetupCount = 0;
3469         pSMB->Reserved = 0;
3470         pSMB->Flags = 0;
3471         pSMB->Timeout = 0;
3472         pSMB->Reserved2 = 0;
3473         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3474         offset = param_offset + params;
3475
3476         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
3477
3478         count = sizeof(struct file_end_of_file_info);
3479         pSMB->MaxParameterCount = cpu_to_le16(2);
3480         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3481         pSMB->SetupCount = 1;
3482         pSMB->Reserved3 = 0;
3483         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3484         byte_count = 3 /* pad */  + params + count;
3485         pSMB->DataCount = cpu_to_le16(count);
3486         pSMB->ParameterCount = cpu_to_le16(params);
3487         pSMB->TotalDataCount = pSMB->DataCount;
3488         pSMB->TotalParameterCount = pSMB->ParameterCount;
3489         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3490         parm_data =
3491                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3492                         offset);
3493         pSMB->DataOffset = cpu_to_le16(offset);
3494         parm_data->FileSize = cpu_to_le64(size);
3495         pSMB->Fid = fid;
3496         if(SetAllocation) {
3497                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3498                         pSMB->InformationLevel =
3499                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3500                 else
3501                         pSMB->InformationLevel =
3502                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3503         } else /* Set File Size */  {    
3504             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3505                     pSMB->InformationLevel =
3506                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3507             else
3508                     pSMB->InformationLevel =
3509                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3510         }
3511         pSMB->Reserved4 = 0;
3512         pSMB->hdr.smb_buf_length += byte_count;
3513         pSMB->ByteCount = cpu_to_le16(byte_count);
3514         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3515                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3516         if (rc) {
3517                 cFYI(1,
3518                      ("Send error in SetFileInfo (SetFileSize) = %d",
3519                       rc));
3520         }
3521
3522         if (pSMB)
3523                 cifs_small_buf_release(pSMB);
3524
3525         /* Note: On -EAGAIN error only caller can retry on handle based calls 
3526                 since file handle passed in no longer valid */
3527
3528         return rc;
3529 }
3530
3531 /* Some legacy servers such as NT4 require that the file times be set on 
3532    an open handle, rather than by pathname - this is awkward due to
3533    potential access conflicts on the open, but it is unavoidable for these
3534    old servers since the only other choice is to go from 100 nanosecond DCE
3535    time and resort to the original setpathinfo level which takes the ancient
3536    DOS time format with 2 second granularity */
3537 int
3538 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
3539                    __u16 fid)
3540 {
3541         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
3542         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3543         char *data_offset;
3544         int rc = 0;
3545         int bytes_returned = 0;
3546         __u16 params, param_offset, offset, byte_count, count;
3547
3548         cFYI(1, ("Set Times (via SetFileInfo)"));
3549         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3550
3551         if (rc)
3552                 return rc;
3553
3554         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3555
3556         /* At this point there is no need to override the current pid
3557         with the pid of the opener, but that could change if we someday
3558         use an existing handle (rather than opening one on the fly) */
3559         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3560         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3561     
3562         params = 6;
3563         pSMB->MaxSetupCount = 0;
3564         pSMB->Reserved = 0;
3565         pSMB->Flags = 0;
3566         pSMB->Timeout = 0;
3567         pSMB->Reserved2 = 0;
3568         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3569         offset = param_offset + params;
3570
3571         data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
3572
3573         count = sizeof (FILE_BASIC_INFO);
3574         pSMB->MaxParameterCount = cpu_to_le16(2);
3575         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3576         pSMB->SetupCount = 1;
3577         pSMB->Reserved3 = 0;
3578         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3579         byte_count = 3 /* pad */  + params + count;
3580         pSMB->DataCount = cpu_to_le16(count);
3581         pSMB->ParameterCount = cpu_to_le16(params);
3582         pSMB->TotalDataCount = pSMB->DataCount;
3583         pSMB->TotalParameterCount = pSMB->ParameterCount;
3584         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3585         pSMB->DataOffset = cpu_to_le16(offset);
3586         pSMB->Fid = fid;
3587         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3588                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3589         else
3590                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3591         pSMB->Reserved4 = 0;
3592         pSMB->hdr.smb_buf_length += byte_count;
3593         pSMB->ByteCount = cpu_to_le16(byte_count);
3594         memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3595         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3596                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3597         if (rc) {
3598                 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3599         }
3600
3601         cifs_small_buf_release(pSMB);
3602
3603         /* Note: On -EAGAIN error only caller can retry on handle based calls 
3604                 since file handle passed in no longer valid */
3605
3606         return rc;
3607 }
3608
3609
3610 int
3611 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3612                 const FILE_BASIC_INFO * data, 
3613                 const struct nls_table *nls_codepage, int remap)
3614 {
3615         TRANSACTION2_SPI_REQ *pSMB = NULL;
3616         TRANSACTION2_SPI_RSP *pSMBr = NULL;
3617         int name_len;
3618         int rc = 0;
3619         int bytes_returned = 0;
3620         char *data_offset;
3621         __u16 params, param_offset, offset, byte_count, count;
3622
3623         cFYI(1, ("In SetTimes"));
3624
3625 SetTimesRetry:
3626         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3627                       (void **) &pSMBr);
3628         if (rc)
3629                 return rc;
3630
3631         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3632                 name_len =
3633                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3634                                      PATH_MAX, nls_codepage, remap);
3635                 name_len++;     /* trailing null */
3636                 name_len *= 2;
3637         } else {                /* BB improve the check for buffer overruns BB */
3638                 name_len = strnlen(fileName, PATH_MAX);
3639                 name_len++;     /* trailing null */
3640                 strncpy(pSMB->FileName, fileName, name_len);
3641         }
3642
3643         params = 6 + name_len;
3644         count = sizeof (FILE_BASIC_INFO);
3645         pSMB->MaxParameterCount = cpu_to_le16(2);
3646         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3647         pSMB->MaxSetupCount = 0;
3648         pSMB->Reserved = 0;
3649         pSMB->Flags = 0;
3650         pSMB->Timeout = 0;
3651         pSMB->Reserved2 = 0;
3652         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3653                                      InformationLevel) - 4;
3654         offset = param_offset + params;
3655         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3656         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3657         pSMB->DataOffset = cpu_to_le16(offset);
3658         pSMB->SetupCount = 1;
3659         pSMB->Reserved3 = 0;
3660         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3661         byte_count = 3 /* pad */  + params + count;
3662
3663         pSMB->DataCount = cpu_to_le16(count);
3664         pSMB->ParameterCount = cpu_to_le16(params);
3665         pSMB->TotalDataCount = pSMB->DataCount;
3666         pSMB->TotalParameterCount = pSMB->ParameterCount;
3667         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3668                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3669         else
3670                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3671         pSMB->Reserved4 = 0;
3672         pSMB->hdr.smb_buf_length += byte_count;
3673         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3674         pSMB->ByteCount = cpu_to_le16(byte_count);
3675         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3676                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3677         if (rc) {
3678                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3679         }
3680
3681         cifs_buf_release(pSMB);
3682
3683         if (rc == -EAGAIN)
3684                 goto SetTimesRetry;
3685
3686         return rc;
3687 }
3688
3689 /* Can not be used to set time stamps yet (due to old DOS time format) */
3690 /* Can be used to set attributes */
3691 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
3692           handling it anyway and NT4 was what we thought it would be needed for
3693           Do not delete it until we prove whether needed for Win9x though */
3694 int
3695 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3696                 __u16 dos_attrs, const struct nls_table *nls_codepage)
3697 {
3698         SETATTR_REQ *pSMB = NULL;
3699         SETATTR_RSP *pSMBr = NULL;
3700         int rc = 0;
3701         int bytes_returned;
3702         int name_len;
3703
3704         cFYI(1, ("In SetAttrLegacy"));
3705
3706 SetAttrLgcyRetry:
3707         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
3708                       (void **) &pSMBr);
3709         if (rc)
3710                 return rc;
3711
3712         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3713                 name_len =
3714                         ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
3715                                 PATH_MAX, nls_codepage);
3716                 name_len++;     /* trailing null */
3717                 name_len *= 2;
3718         } else {                /* BB improve the check for buffer overruns BB */
3719                 name_len = strnlen(fileName, PATH_MAX);
3720                 name_len++;     /* trailing null */
3721                 strncpy(pSMB->fileName, fileName, name_len);
3722         }
3723         pSMB->attr = cpu_to_le16(dos_attrs);
3724         pSMB->BufferFormat = 0x04;
3725         pSMB->hdr.smb_buf_length += name_len + 1;
3726         pSMB->ByteCount = cpu_to_le16(name_len + 1);
3727         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3728                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3729         if (rc) {
3730                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
3731         }
3732
3733         cifs_buf_release(pSMB);
3734
3735         if (rc == -EAGAIN)
3736                 goto SetAttrLgcyRetry;
3737
3738         return rc;
3739 }
3740 #endif /* temporarily unneeded SetAttr legacy function */
3741
3742 int
3743 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
3744                     char *fileName, __u64 mode, __u64 uid, __u64 gid, 
3745                     dev_t device, const struct nls_table *nls_codepage, 
3746                     int remap)
3747 {
3748         TRANSACTION2_SPI_REQ *pSMB = NULL;
3749         TRANSACTION2_SPI_RSP *pSMBr = NULL;
3750         int name_len;
3751         int rc = 0;
3752         int bytes_returned = 0;
3753         FILE_UNIX_BASIC_INFO *data_offset;
3754         __u16 params, param_offset, offset, count, byte_count;
3755
3756         cFYI(1, ("In SetUID/GID/Mode"));
3757 setPermsRetry:
3758         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3759                       (void **) &pSMBr);
3760         if (rc)
3761                 return rc;
3762
3763         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3764                 name_len =
3765                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
3766                                      PATH_MAX, nls_codepage, remap);
3767                 name_len++;     /* trailing null */
3768                 name_len *= 2;
3769         } else {                /* BB improve the check for buffer overruns BB */
3770                 name_len = strnlen(fileName, PATH_MAX);
3771                 name_len++;     /* trailing null */
3772                 strncpy(pSMB->FileName, fileName, name_len);
3773         }
3774
3775         params = 6 + name_len;
3776         count = sizeof (FILE_UNIX_BASIC_INFO);
3777         pSMB->MaxParameterCount = cpu_to_le16(2);
3778         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3779         pSMB->MaxSetupCount = 0;
3780         pSMB->Reserved = 0;
3781         pSMB->Flags = 0;
3782         pSMB->Timeout = 0;
3783         pSMB->Reserved2 = 0;
3784         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3785                                      InformationLevel) - 4;
3786         offset = param_offset + params;
3787         data_offset =
3788             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3789                                       offset);
3790         memset(data_offset, 0, count);
3791         pSMB->DataOffset = cpu_to_le16(offset);
3792         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3793         pSMB->SetupCount = 1;
3794         pSMB->Reserved3 = 0;
3795         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3796         byte_count = 3 /* pad */  + params + count;
3797         pSMB->ParameterCount = cpu_to_le16(params);
3798         pSMB->DataCount = cpu_to_le16(count);
3799         pSMB->TotalParameterCount = pSMB->ParameterCount;
3800         pSMB->TotalDataCount = pSMB->DataCount;
3801         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3802         pSMB->Reserved4 = 0;
3803         pSMB->hdr.smb_buf_length += byte_count;
3804         data_offset->Uid = cpu_to_le64(uid);
3805         data_offset->Gid = cpu_to_le64(gid);
3806         /* better to leave device as zero when it is  */
3807         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3808         data_offset->DevMinor = cpu_to_le64(MINOR(device));
3809         data_offset->Permissions = cpu_to_le64(mode);
3810     
3811         if(S_ISREG(mode))
3812                 data_offset->Type = cpu_to_le32(UNIX_FILE);
3813         else if(S_ISDIR(mode))
3814                 data_offset->Type = cpu_to_le32(UNIX_DIR);
3815         else if(S_ISLNK(mode))
3816                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3817         else if(S_ISCHR(mode))
3818                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3819         else if(S_ISBLK(mode))
3820                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3821         else if(S_ISFIFO(mode))
3822                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
3823         else if(S_ISSOCK(mode))
3824                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3825
3826
3827         pSMB->ByteCount = cpu_to_le16(byte_count);
3828         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3829                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3830         if (rc) {
3831                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3832         }
3833
3834         if (pSMB)
3835                 cifs_buf_release(pSMB);
3836         if (rc == -EAGAIN)
3837                 goto setPermsRetry;
3838         return rc;
3839 }
3840
3841 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
3842                         const int notify_subdirs, const __u16 netfid,
3843                         __u32 filter, const struct nls_table *nls_codepage)
3844 {
3845         int rc = 0;
3846         struct smb_com_transaction_change_notify_req * pSMB = NULL;
3847         struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
3848         int bytes_returned;
3849
3850         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3851         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3852                       (void **) &pSMBr);
3853         if (rc)
3854                 return rc;
3855
3856         pSMB->TotalParameterCount = 0 ;
3857         pSMB->TotalDataCount = 0;
3858         pSMB->MaxParameterCount = cpu_to_le32(2);
3859         /* BB find exact data count max from sess structure BB */
3860         pSMB->MaxDataCount = 0; /* same in little endian or be */
3861         pSMB->MaxSetupCount = 4;
3862         pSMB->Reserved = 0;
3863         pSMB->ParameterOffset = 0;
3864         pSMB->DataCount = 0;
3865         pSMB->DataOffset = 0;
3866         pSMB->SetupCount = 4; /* single byte does not need le conversion */
3867         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
3868         pSMB->ParameterCount = pSMB->TotalParameterCount;
3869         if(notify_subdirs)
3870                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
3871         pSMB->Reserved2 = 0;
3872         pSMB->CompletionFilter = cpu_to_le32(filter);
3873         pSMB->Fid = netfid; /* file handle always le */
3874         pSMB->ByteCount = 0;
3875
3876         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3877                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
3878         if (rc) {
3879                 cFYI(1, ("Error in Notify = %d", rc));
3880         }
3881         cifs_buf_release(pSMB);
3882         return rc;      
3883 }
3884 #ifdef CONFIG_CIFS_XATTR
3885 ssize_t
3886 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3887                  const unsigned char *searchName,
3888                  char * EAData, size_t buf_size,
3889                  const struct nls_table *nls_codepage, int remap)
3890 {
3891                 /* BB assumes one setup word */
3892         TRANSACTION2_QPI_REQ *pSMB = NULL;
3893         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3894         int rc = 0;
3895         int bytes_returned;
3896         int name_len;
3897         struct fea * temp_fea;
3898         char * temp_ptr;
3899         __u16 params, byte_count;
3900
3901         cFYI(1, ("In Query All EAs path %s", searchName));
3902 QAllEAsRetry:
3903         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3904                       (void **) &pSMBr);
3905         if (rc)
3906                 return rc;
3907
3908         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3909                 name_len =
3910                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
3911                                      PATH_MAX, nls_codepage, remap);
3912                 name_len++;     /* trailing null */
3913                 name_len *= 2;
3914         } else {        /* BB improve the check for buffer overruns BB */
3915                 name_len = strnlen(searchName, PATH_MAX);
3916                 name_len++;     /* trailing null */
3917                 strncpy(pSMB->FileName, searchName, name_len);
3918         }
3919
3920         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3921         pSMB->TotalDataCount = 0;
3922         pSMB->MaxParameterCount = cpu_to_le16(2);
3923         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3924         pSMB->MaxSetupCount = 0;
3925         pSMB->Reserved = 0;
3926         pSMB->Flags = 0;
3927         pSMB->Timeout = 0;
3928         pSMB->Reserved2 = 0;
3929         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3930         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3931         pSMB->DataCount = 0;
3932         pSMB->DataOffset = 0;
3933         pSMB->SetupCount = 1;
3934         pSMB->Reserved3 = 0;
3935         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3936         byte_count = params + 1 /* pad */ ;
3937         pSMB->TotalParameterCount = cpu_to_le16(params);
3938         pSMB->ParameterCount = pSMB->TotalParameterCount;
3939         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3940         pSMB->Reserved4 = 0;
3941         pSMB->hdr.smb_buf_length += byte_count;
3942         pSMB->ByteCount = cpu_to_le16(byte_count);
3943
3944         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3945                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3946         if (rc) {
3947                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
3948         } else {                /* decode response */
3949                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3950
3951                 /* BB also check enough total bytes returned */
3952                 /* BB we need to improve the validity checking
3953                 of these trans2 responses */
3954                 if (rc || (pSMBr->ByteCount < 4)) 
3955                         rc = -EIO;      /* bad smb */
3956            /* else if (pFindData){
3957                         memcpy((char *) pFindData,
3958                                (char *) &pSMBr->hdr.Protocol +
3959                                data_offset, kl);
3960                 }*/ else {
3961                         /* check that length of list is not more than bcc */
3962                         /* check that each entry does not go beyond length
3963                            of list */
3964                         /* check that each element of each entry does not
3965                            go beyond end of list */
3966                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3967                         struct fealist * ea_response_data;
3968                         rc = 0;
3969                         /* validate_trans2_offsets() */
3970                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
3971                         ea_response_data = (struct fealist *)
3972                                 (((char *) &pSMBr->hdr.Protocol) +
3973                                 data_offset);
3974                         name_len = le32_to_cpu(ea_response_data->list_len);
3975                         cFYI(1,("ea length %d", name_len));
3976                         if(name_len <= 8) {
3977                         /* returned EA size zeroed at top of function */
3978                                 cFYI(1,("empty EA list returned from server"));
3979                         } else {
3980                                 /* account for ea list len */
3981                                 name_len -= 4;
3982                                 temp_fea = ea_response_data->list;
3983                                 temp_ptr = (char *)temp_fea;
3984                                 while(name_len > 0) {
3985                                         __u16 value_len;
3986                                         name_len -= 4;
3987                                         temp_ptr += 4;
3988                                         rc += temp_fea->name_len;
3989                                 /* account for prefix user. and trailing null */
3990                                         rc = rc + 5 + 1; 
3991                                         if(rc<(int)buf_size) {
3992                                                 memcpy(EAData,"user.",5);
3993                                                 EAData+=5;
3994                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
3995                                                 EAData+=temp_fea->name_len;
3996                                                 /* null terminate name */
3997                                                 *EAData = 0;
3998                                                 EAData = EAData + 1;
3999                                         } else if(buf_size == 0) {
4000                                                 /* skip copy - calc size only */
4001                                         } else {
4002                                                 /* stop before overrun buffer */
4003                                                 rc = -ERANGE;
4004                                                 break;
4005                                         }
4006                                         name_len -= temp_fea->name_len;
4007                                         temp_ptr += temp_fea->name_len;
4008                                         /* account for trailing null */
4009                                         name_len--;
4010                                         temp_ptr++;
4011                                         value_len = le16_to_cpu(temp_fea->value_len);
4012                                         name_len -= value_len;
4013                                         temp_ptr += value_len;
4014                                         /* BB check that temp_ptr is still within smb BB*/
4015                                 /* no trailing null to account for in value len */
4016                                         /* go on to next EA */
4017                                         temp_fea = (struct fea *)temp_ptr;
4018                                 }
4019                         }
4020                 }
4021         }
4022         if (pSMB)
4023                 cifs_buf_release(pSMB);
4024         if (rc == -EAGAIN)
4025                 goto QAllEAsRetry;
4026
4027         return (ssize_t)rc;
4028 }
4029
4030 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4031                 const unsigned char * searchName,const unsigned char * ea_name,
4032                 unsigned char * ea_value, size_t buf_size, 
4033                 const struct nls_table *nls_codepage, int remap)
4034 {
4035         TRANSACTION2_QPI_REQ *pSMB = NULL;
4036         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4037         int rc = 0;
4038         int bytes_returned;
4039         int name_len;
4040         struct fea * temp_fea;
4041         char * temp_ptr;
4042         __u16 params, byte_count;
4043
4044         cFYI(1, ("In Query EA path %s", searchName));
4045 QEARetry:
4046         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4047                       (void **) &pSMBr);
4048         if (rc)
4049                 return rc;
4050
4051         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4052                 name_len =
4053                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4054                                      PATH_MAX, nls_codepage, remap);
4055                 name_len++;     /* trailing null */
4056                 name_len *= 2;
4057         } else {        /* BB improve the check for buffer overruns BB */
4058                 name_len = strnlen(searchName, PATH_MAX);
4059                 name_len++;     /* trailing null */
4060                 strncpy(pSMB->FileName, searchName, name_len);
4061         }
4062
4063         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4064         pSMB->TotalDataCount = 0;
4065         pSMB->MaxParameterCount = cpu_to_le16(2);
4066         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4067         pSMB->MaxSetupCount = 0;
4068         pSMB->Reserved = 0;
4069         pSMB->Flags = 0;
4070         pSMB->Timeout = 0;
4071         pSMB->Reserved2 = 0;
4072         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4073         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4074         pSMB->DataCount = 0;
4075         pSMB->DataOffset = 0;
4076         pSMB->SetupCount = 1;
4077         pSMB->Reserved3 = 0;
4078         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4079         byte_count = params + 1 /* pad */ ;
4080         pSMB->TotalParameterCount = cpu_to_le16(params);
4081         pSMB->ParameterCount = pSMB->TotalParameterCount;
4082         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4083         pSMB->Reserved4 = 0;
4084         pSMB->hdr.smb_buf_length += byte_count;
4085         pSMB->ByteCount = cpu_to_le16(byte_count);
4086
4087         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4088                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4089         if (rc) {
4090                 cFYI(1, ("Send error in Query EA = %d", rc));
4091         } else {                /* decode response */
4092                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4093
4094                 /* BB also check enough total bytes returned */
4095                 /* BB we need to improve the validity checking
4096                 of these trans2 responses */
4097                 if (rc || (pSMBr->ByteCount < 4)) 
4098                         rc = -EIO;      /* bad smb */
4099            /* else if (pFindData){
4100                         memcpy((char *) pFindData,
4101                                (char *) &pSMBr->hdr.Protocol +
4102                                data_offset, kl);
4103                 }*/ else {
4104                         /* check that length of list is not more than bcc */
4105                         /* check that each entry does not go beyond length
4106                            of list */
4107                         /* check that each element of each entry does not
4108                            go beyond end of list */
4109                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4110                         struct fealist * ea_response_data;
4111                         rc = -ENODATA;
4112                         /* validate_trans2_offsets() */
4113                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4114                         ea_response_data = (struct fealist *)
4115                                 (((char *) &pSMBr->hdr.Protocol) +
4116                                 data_offset);
4117                         name_len = le32_to_cpu(ea_response_data->list_len);
4118                         cFYI(1,("ea length %d", name_len));
4119                         if(name_len <= 8) {
4120                         /* returned EA size zeroed at top of function */
4121                                 cFYI(1,("empty EA list returned from server"));
4122                         } else {
4123                                 /* account for ea list len */
4124                                 name_len -= 4;
4125                                 temp_fea = ea_response_data->list;
4126                                 temp_ptr = (char *)temp_fea;
4127                                 /* loop through checking if we have a matching
4128                                 name and then return the associated value */
4129                                 while(name_len > 0) {
4130                                         __u16 value_len;
4131                                         name_len -= 4;
4132                                         temp_ptr += 4;
4133                                         value_len = le16_to_cpu(temp_fea->value_len);
4134                                 /* BB validate that value_len falls within SMB, 
4135                                 even though maximum for name_len is 255 */ 
4136                                         if(memcmp(temp_fea->name,ea_name,
4137                                                   temp_fea->name_len) == 0) {
4138                                                 /* found a match */
4139                                                 rc = value_len;
4140                                 /* account for prefix user. and trailing null */
4141                                                 if(rc<=(int)buf_size) {
4142                                                         memcpy(ea_value,
4143                                                                 temp_fea->name+temp_fea->name_len+1,
4144                                                                 rc);
4145                                                         /* ea values, unlike ea names,
4146                                                         are not null terminated */
4147                                                 } else if(buf_size == 0) {
4148                                                 /* skip copy - calc size only */
4149                                                 } else {
4150                                                         /* stop before overrun buffer */
4151                                                         rc = -ERANGE;
4152                                                 }
4153                                                 break;
4154                                         }
4155                                         name_len -= temp_fea->name_len;
4156                                         temp_ptr += temp_fea->name_len;
4157                                         /* account for trailing null */
4158                                         name_len--;
4159                                         temp_ptr++;
4160                                         name_len -= value_len;
4161                                         temp_ptr += value_len;
4162                                 /* no trailing null to account for in value len */
4163                                         /* go on to next EA */
4164                                         temp_fea = (struct fea *)temp_ptr;
4165                                 }
4166                         } 
4167                 }
4168         }
4169         if (pSMB)
4170                 cifs_buf_release(pSMB);
4171         if (rc == -EAGAIN)
4172                 goto QEARetry;
4173
4174         return (ssize_t)rc;
4175 }
4176
4177 int
4178 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4179                 const char * ea_name, const void * ea_value, 
4180                 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4181                 int remap)
4182 {
4183         struct smb_com_transaction2_spi_req *pSMB = NULL;
4184         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4185         struct fealist *parm_data;
4186         int name_len;
4187         int rc = 0;
4188         int bytes_returned = 0;
4189         __u16 params, param_offset, byte_count, offset, count;
4190
4191         cFYI(1, ("In SetEA"));
4192 SetEARetry:
4193         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4194                       (void **) &pSMBr);
4195         if (rc)
4196                 return rc;
4197
4198         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4199                 name_len =
4200                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4201                                      PATH_MAX, nls_codepage, remap);
4202                 name_len++;     /* trailing null */
4203                 name_len *= 2;
4204         } else {                /* BB improve the check for buffer overruns BB */
4205                 name_len = strnlen(fileName, PATH_MAX);
4206                 name_len++;     /* trailing null */
4207                 strncpy(pSMB->FileName, fileName, name_len);
4208         }
4209
4210         params = 6 + name_len;
4211
4212         /* done calculating parms using name_len of file name,
4213         now use name_len to calculate length of ea name
4214         we are going to create in the inode xattrs */
4215         if(ea_name == NULL)
4216                 name_len = 0;
4217         else
4218                 name_len = strnlen(ea_name,255);
4219
4220         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4221         pSMB->MaxParameterCount = cpu_to_le16(2);
4222         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4223         pSMB->MaxSetupCount = 0;
4224         pSMB->Reserved = 0;
4225         pSMB->Flags = 0;
4226         pSMB->Timeout = 0;
4227         pSMB->Reserved2 = 0;
4228         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4229                                      InformationLevel) - 4;
4230         offset = param_offset + params;
4231         pSMB->InformationLevel =
4232                 cpu_to_le16(SMB_SET_FILE_EA);
4233
4234         parm_data =
4235                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4236                                        offset);
4237         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4238         pSMB->DataOffset = cpu_to_le16(offset);
4239         pSMB->SetupCount = 1;
4240         pSMB->Reserved3 = 0;
4241         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4242         byte_count = 3 /* pad */  + params + count;
4243         pSMB->DataCount = cpu_to_le16(count);
4244         parm_data->list_len = cpu_to_le32(count);
4245         parm_data->list[0].EA_flags = 0;
4246         /* we checked above that name len is less than 255 */
4247         parm_data->list[0].name_len = (__u8)name_len;;
4248         /* EA names are always ASCII */
4249         if(ea_name)
4250                 strncpy(parm_data->list[0].name,ea_name,name_len);
4251         parm_data->list[0].name[name_len] = 0;
4252         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4253         /* caller ensures that ea_value_len is less than 64K but
4254         we need to ensure that it fits within the smb */
4255
4256         /*BB add length check that it would fit in negotiated SMB buffer size BB */
4257         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4258         if(ea_value_len)
4259                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4260
4261         pSMB->TotalDataCount = pSMB->DataCount;
4262         pSMB->ParameterCount = cpu_to_le16(params);
4263         pSMB->TotalParameterCount = pSMB->ParameterCount;
4264         pSMB->Reserved4 = 0;
4265         pSMB->hdr.smb_buf_length += byte_count;
4266         pSMB->ByteCount = cpu_to_le16(byte_count);
4267         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4268                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4269         if (rc) {
4270                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4271         }
4272
4273         cifs_buf_release(pSMB);
4274
4275         if (rc == -EAGAIN)
4276                 goto SetEARetry;
4277
4278         return rc;
4279 }
4280
4281 #endif