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