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