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