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