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