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