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