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