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