Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[pandora-kernel.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 == cpu_to_le16(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         if (waitFlag) {
1464                 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1465                         (struct smb_hdr *) pSMBr, &bytes_returned);
1466         } else {
1467                 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1468                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1469         }
1470         cifs_stats_inc(&tcon->num_locks);
1471         if (rc) {
1472                 cFYI(1, ("Send error in Lock = %d", rc));
1473         }
1474         cifs_small_buf_release(pSMB);
1475
1476         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1477         since file handle passed in no longer valid */
1478         return rc;
1479 }
1480
1481 int
1482 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1483                 const __u16 smb_file_id, const int get_flag, const __u64 len,
1484                 struct file_lock *pLockData, const __u16 lock_type, 
1485                 const int waitFlag)
1486 {
1487         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1488         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1489         char *data_offset;
1490         struct cifs_posix_lock *parm_data;
1491         int rc = 0;
1492         int timeout = 0;
1493         int bytes_returned = 0;
1494         __u16 params, param_offset, offset, byte_count, count;
1495
1496         cFYI(1, ("Posix Lock"));
1497
1498         if(pLockData == NULL)
1499                 return EINVAL;
1500
1501         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1502
1503         if (rc)
1504                 return rc;
1505
1506         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1507
1508         params = 6; 
1509         pSMB->MaxSetupCount = 0;
1510         pSMB->Reserved = 0;
1511         pSMB->Flags = 0;
1512         pSMB->Reserved2 = 0;
1513         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1514         offset = param_offset + params;
1515
1516         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1517
1518         count = sizeof(struct cifs_posix_lock);
1519         pSMB->MaxParameterCount = cpu_to_le16(2);
1520         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1521         pSMB->SetupCount = 1;
1522         pSMB->Reserved3 = 0;
1523         if(get_flag)
1524                 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1525         else
1526                 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1527         byte_count = 3 /* pad */  + params + count;
1528         pSMB->DataCount = cpu_to_le16(count);
1529         pSMB->ParameterCount = cpu_to_le16(params);
1530         pSMB->TotalDataCount = pSMB->DataCount;
1531         pSMB->TotalParameterCount = pSMB->ParameterCount;
1532         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1533         parm_data = (struct cifs_posix_lock *) 
1534                         (((char *) &pSMB->hdr.Protocol) + offset);
1535
1536         parm_data->lock_type = cpu_to_le16(lock_type);
1537         if(waitFlag) {
1538                 timeout = 3;  /* blocking operation, no timeout */
1539                 parm_data->lock_flags = cpu_to_le16(1);
1540                 pSMB->Timeout = cpu_to_le32(-1);
1541         } else
1542                 pSMB->Timeout = 0;
1543
1544         parm_data->pid = cpu_to_le32(current->tgid);
1545         parm_data->start = cpu_to_le64(pLockData->fl_start);
1546         parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
1547
1548         pSMB->DataOffset = cpu_to_le16(offset);
1549         pSMB->Fid = smb_file_id;
1550         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1551         pSMB->Reserved4 = 0;
1552         pSMB->hdr.smb_buf_length += byte_count;
1553         pSMB->ByteCount = cpu_to_le16(byte_count);
1554         if (waitFlag) {
1555                 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1556                         (struct smb_hdr *) pSMBr, &bytes_returned);
1557         } else {
1558                 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1559                         (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1560         }
1561
1562         if (rc) {
1563                 cFYI(1, ("Send error in Posix Lock = %d", rc));
1564         } else if (get_flag) {
1565                 /* lock structure can be returned on get */
1566                 __u16 data_offset;
1567                 __u16 data_count;
1568                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1569
1570                 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1571                         rc = -EIO;      /* bad smb */
1572                         goto plk_err_exit;
1573                 }
1574                 if(pLockData == NULL) {
1575                         rc = -EINVAL;
1576                         goto plk_err_exit;
1577                 }
1578                 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1579                 data_count  = le16_to_cpu(pSMBr->t2.DataCount);
1580                 if(data_count < sizeof(struct cifs_posix_lock)) {
1581                         rc = -EIO;
1582                         goto plk_err_exit;
1583                 }
1584                 parm_data = (struct cifs_posix_lock *)
1585                         ((char *)&pSMBr->hdr.Protocol + data_offset);
1586                 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1587                         pLockData->fl_type = F_UNLCK;
1588         }
1589  
1590 plk_err_exit:
1591         if (pSMB)
1592                 cifs_small_buf_release(pSMB);
1593
1594         /* Note: On -EAGAIN error only caller can retry on handle based calls
1595            since file handle passed in no longer valid */
1596
1597         return rc;
1598 }
1599
1600
1601 int
1602 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1603 {
1604         int rc = 0;
1605         CLOSE_REQ *pSMB = NULL;
1606         CLOSE_RSP *pSMBr = NULL;
1607         int bytes_returned;
1608         cFYI(1, ("In CIFSSMBClose"));
1609
1610 /* do not retry on dead session on close */
1611         rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1612         if(rc == -EAGAIN)
1613                 return 0;
1614         if (rc)
1615                 return rc;
1616
1617         pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1618
1619         pSMB->FileID = (__u16) smb_file_id;
1620         pSMB->LastWriteTime = 0;
1621         pSMB->ByteCount = 0;
1622         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1623                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1624         cifs_stats_inc(&tcon->num_closes);
1625         if (rc) {
1626                 if(rc!=-EINTR) {
1627                         /* EINTR is expected when user ctl-c to kill app */
1628                         cERROR(1, ("Send error in Close = %d", rc));
1629                 }
1630         }
1631
1632         cifs_small_buf_release(pSMB);
1633
1634         /* Since session is dead, file will be closed on server already */
1635         if(rc == -EAGAIN)
1636                 rc = 0;
1637
1638         return rc;
1639 }
1640
1641 int
1642 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1643               const char *fromName, const char *toName,
1644               const struct nls_table *nls_codepage, int remap)
1645 {
1646         int rc = 0;
1647         RENAME_REQ *pSMB = NULL;
1648         RENAME_RSP *pSMBr = NULL;
1649         int bytes_returned;
1650         int name_len, name_len2;
1651         __u16 count;
1652
1653         cFYI(1, ("In CIFSSMBRename"));
1654 renameRetry:
1655         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1656                       (void **) &pSMBr);
1657         if (rc)
1658                 return rc;
1659
1660         pSMB->BufferFormat = 0x04;
1661         pSMB->SearchAttributes =
1662             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1663                         ATTR_DIRECTORY);
1664
1665         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1666                 name_len =
1667                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, 
1668                                      PATH_MAX, nls_codepage, remap);
1669                 name_len++;     /* trailing null */
1670                 name_len *= 2;
1671                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1672         /* protocol requires ASCII signature byte on Unicode string */
1673                 pSMB->OldFileName[name_len + 1] = 0x00;
1674                 name_len2 =
1675                     cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1676                                      toName, PATH_MAX, nls_codepage, remap);
1677                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1678                 name_len2 *= 2; /* convert to bytes */
1679         } else {                /* BB improve the check for buffer overruns BB */
1680                 name_len = strnlen(fromName, PATH_MAX);
1681                 name_len++;     /* trailing null */
1682                 strncpy(pSMB->OldFileName, fromName, name_len);
1683                 name_len2 = strnlen(toName, PATH_MAX);
1684                 name_len2++;    /* trailing null */
1685                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1686                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1687                 name_len2++;    /* trailing null */
1688                 name_len2++;    /* signature byte */
1689         }
1690
1691         count = 1 /* 1st signature byte */  + name_len + name_len2;
1692         pSMB->hdr.smb_buf_length += count;
1693         pSMB->ByteCount = cpu_to_le16(count);
1694
1695         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1696                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1697         cifs_stats_inc(&tcon->num_renames);
1698         if (rc) {
1699                 cFYI(1, ("Send error in rename = %d", rc));
1700         } 
1701
1702         cifs_buf_release(pSMB);
1703
1704         if (rc == -EAGAIN)
1705                 goto renameRetry;
1706
1707         return rc;
1708 }
1709
1710 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
1711                 int netfid, char * target_name, 
1712                 const struct nls_table * nls_codepage, int remap)
1713 {
1714         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1715         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1716         struct set_file_rename * rename_info;
1717         char *data_offset;
1718         char dummy_string[30];
1719         int rc = 0;
1720         int bytes_returned = 0;
1721         int len_of_str;
1722         __u16 params, param_offset, offset, count, byte_count;
1723
1724         cFYI(1, ("Rename to File by handle"));
1725         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1726                         (void **) &pSMBr);
1727         if (rc)
1728                 return rc;
1729
1730         params = 6;
1731         pSMB->MaxSetupCount = 0;
1732         pSMB->Reserved = 0;
1733         pSMB->Flags = 0;
1734         pSMB->Timeout = 0;
1735         pSMB->Reserved2 = 0;
1736         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1737         offset = param_offset + params;
1738
1739         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1740         rename_info = (struct set_file_rename *) data_offset;
1741         pSMB->MaxParameterCount = cpu_to_le16(2);
1742         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1743         pSMB->SetupCount = 1;
1744         pSMB->Reserved3 = 0;
1745         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1746         byte_count = 3 /* pad */  + params;
1747         pSMB->ParameterCount = cpu_to_le16(params);
1748         pSMB->TotalParameterCount = pSMB->ParameterCount;
1749         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1750         pSMB->DataOffset = cpu_to_le16(offset);
1751         /* construct random name ".cifs_tmp<inodenum><mid>" */
1752         rename_info->overwrite = cpu_to_le32(1);
1753         rename_info->root_fid  = 0;
1754         /* unicode only call */
1755         if(target_name == NULL) {
1756                 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1757                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1758                                         dummy_string, 24, nls_codepage, remap);
1759         } else {
1760                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1761                                         target_name, PATH_MAX, nls_codepage, remap);
1762         }
1763         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1764         count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1765         byte_count += count;
1766         pSMB->DataCount = cpu_to_le16(count);
1767         pSMB->TotalDataCount = pSMB->DataCount;
1768         pSMB->Fid = netfid;
1769         pSMB->InformationLevel =
1770                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1771         pSMB->Reserved4 = 0;
1772         pSMB->hdr.smb_buf_length += byte_count;
1773         pSMB->ByteCount = cpu_to_le16(byte_count);
1774         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1775                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1776         cifs_stats_inc(&pTcon->num_t2renames);
1777         if (rc) {
1778                 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1779         }
1780
1781         cifs_buf_release(pSMB);
1782
1783         /* Note: On -EAGAIN error only caller can retry on handle based calls
1784                 since file handle passed in no longer valid */
1785
1786         return rc;
1787 }
1788
1789 int
1790 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
1791             const __u16 target_tid, const char *toName, const int flags,
1792             const struct nls_table *nls_codepage, int remap)
1793 {
1794         int rc = 0;
1795         COPY_REQ *pSMB = NULL;
1796         COPY_RSP *pSMBr = NULL;
1797         int bytes_returned;
1798         int name_len, name_len2;
1799         __u16 count;
1800
1801         cFYI(1, ("In CIFSSMBCopy"));
1802 copyRetry:
1803         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1804                         (void **) &pSMBr);
1805         if (rc)
1806                 return rc;
1807
1808         pSMB->BufferFormat = 0x04;
1809         pSMB->Tid2 = target_tid;
1810
1811         pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1812
1813         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1814                 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, 
1815                                             fromName, PATH_MAX, nls_codepage,
1816                                             remap);
1817                 name_len++;     /* trailing null */
1818                 name_len *= 2;
1819                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1820                 /* protocol requires ASCII signature byte on Unicode string */
1821                 pSMB->OldFileName[name_len + 1] = 0x00;
1822                 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1823                                 toName, PATH_MAX, nls_codepage, remap);
1824                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1825                 name_len2 *= 2; /* convert to bytes */
1826         } else {                /* BB improve the check for buffer overruns BB */
1827                 name_len = strnlen(fromName, PATH_MAX);
1828                 name_len++;     /* trailing null */
1829                 strncpy(pSMB->OldFileName, fromName, name_len);
1830                 name_len2 = strnlen(toName, PATH_MAX);
1831                 name_len2++;    /* trailing null */
1832                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1833                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1834                 name_len2++;    /* trailing null */
1835                 name_len2++;    /* signature byte */
1836         }
1837
1838         count = 1 /* 1st signature byte */  + name_len + name_len2;
1839         pSMB->hdr.smb_buf_length += count;
1840         pSMB->ByteCount = cpu_to_le16(count);
1841
1842         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1843                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1844         if (rc) {
1845                 cFYI(1, ("Send error in copy = %d with %d files copied",
1846                         rc, le16_to_cpu(pSMBr->CopyCount)));
1847         }
1848         if (pSMB)
1849                 cifs_buf_release(pSMB);
1850
1851         if (rc == -EAGAIN)
1852                 goto copyRetry;
1853
1854         return rc;
1855 }
1856
1857 int
1858 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1859                       const char *fromName, const char *toName,
1860                       const struct nls_table *nls_codepage)
1861 {
1862         TRANSACTION2_SPI_REQ *pSMB = NULL;
1863         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1864         char *data_offset;
1865         int name_len;
1866         int name_len_target;
1867         int rc = 0;
1868         int bytes_returned = 0;
1869         __u16 params, param_offset, offset, byte_count;
1870
1871         cFYI(1, ("In Symlink Unix style"));
1872 createSymLinkRetry:
1873         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1874                       (void **) &pSMBr);
1875         if (rc)
1876                 return rc;
1877
1878         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1879                 name_len =
1880                     cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1881                                   /* find define for this maxpathcomponent */
1882                                   , nls_codepage);
1883                 name_len++;     /* trailing null */
1884                 name_len *= 2;
1885
1886         } else {                /* BB improve the check for buffer overruns BB */
1887                 name_len = strnlen(fromName, PATH_MAX);
1888                 name_len++;     /* trailing null */
1889                 strncpy(pSMB->FileName, fromName, name_len);
1890         }
1891         params = 6 + name_len;
1892         pSMB->MaxSetupCount = 0;
1893         pSMB->Reserved = 0;
1894         pSMB->Flags = 0;
1895         pSMB->Timeout = 0;
1896         pSMB->Reserved2 = 0;
1897         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1898                                      InformationLevel) - 4;
1899         offset = param_offset + params;
1900
1901         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1902         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1903                 name_len_target =
1904                     cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1905                                   /* find define for this maxpathcomponent */
1906                                   , nls_codepage);
1907                 name_len_target++;      /* trailing null */
1908                 name_len_target *= 2;
1909         } else {                /* BB improve the check for buffer overruns BB */
1910                 name_len_target = strnlen(toName, PATH_MAX);
1911                 name_len_target++;      /* trailing null */
1912                 strncpy(data_offset, toName, name_len_target);
1913         }
1914
1915         pSMB->MaxParameterCount = cpu_to_le16(2);
1916         /* BB find exact max on data count below from sess */
1917         pSMB->MaxDataCount = cpu_to_le16(1000);
1918         pSMB->SetupCount = 1;
1919         pSMB->Reserved3 = 0;
1920         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1921         byte_count = 3 /* pad */  + params + name_len_target;
1922         pSMB->DataCount = cpu_to_le16(name_len_target);
1923         pSMB->ParameterCount = cpu_to_le16(params);
1924         pSMB->TotalDataCount = pSMB->DataCount;
1925         pSMB->TotalParameterCount = pSMB->ParameterCount;
1926         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1927         pSMB->DataOffset = cpu_to_le16(offset);
1928         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1929         pSMB->Reserved4 = 0;
1930         pSMB->hdr.smb_buf_length += byte_count;
1931         pSMB->ByteCount = cpu_to_le16(byte_count);
1932         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1933                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1934         cifs_stats_inc(&tcon->num_symlinks);
1935         if (rc) {
1936                 cFYI(1,
1937                      ("Send error in SetPathInfo (create symlink) = %d",
1938                       rc));
1939         }
1940
1941         if (pSMB)
1942                 cifs_buf_release(pSMB);
1943
1944         if (rc == -EAGAIN)
1945                 goto createSymLinkRetry;
1946
1947         return rc;
1948 }
1949
1950 int
1951 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1952                        const char *fromName, const char *toName,
1953                        const struct nls_table *nls_codepage, int remap)
1954 {
1955         TRANSACTION2_SPI_REQ *pSMB = NULL;
1956         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1957         char *data_offset;
1958         int name_len;
1959         int name_len_target;
1960         int rc = 0;
1961         int bytes_returned = 0;
1962         __u16 params, param_offset, offset, byte_count;
1963
1964         cFYI(1, ("In Create Hard link Unix style"));
1965 createHardLinkRetry:
1966         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1967                       (void **) &pSMBr);
1968         if (rc)
1969                 return rc;
1970
1971         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1972                 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1973                                             PATH_MAX, nls_codepage, remap);
1974                 name_len++;     /* trailing null */
1975                 name_len *= 2;
1976
1977         } else {                /* BB improve the check for buffer overruns BB */
1978                 name_len = strnlen(toName, PATH_MAX);
1979                 name_len++;     /* trailing null */
1980                 strncpy(pSMB->FileName, toName, name_len);
1981         }
1982         params = 6 + name_len;
1983         pSMB->MaxSetupCount = 0;
1984         pSMB->Reserved = 0;
1985         pSMB->Flags = 0;
1986         pSMB->Timeout = 0;
1987         pSMB->Reserved2 = 0;
1988         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1989                                      InformationLevel) - 4;
1990         offset = param_offset + params;
1991
1992         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1993         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1994                 name_len_target =
1995                     cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1996                                      nls_codepage, remap);
1997                 name_len_target++;      /* trailing null */
1998                 name_len_target *= 2;
1999         } else {                /* BB improve the check for buffer overruns BB */
2000                 name_len_target = strnlen(fromName, PATH_MAX);
2001                 name_len_target++;      /* trailing null */
2002                 strncpy(data_offset, fromName, name_len_target);
2003         }
2004
2005         pSMB->MaxParameterCount = cpu_to_le16(2);
2006         /* BB find exact max on data count below from sess*/
2007         pSMB->MaxDataCount = cpu_to_le16(1000);
2008         pSMB->SetupCount = 1;
2009         pSMB->Reserved3 = 0;
2010         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2011         byte_count = 3 /* pad */  + params + name_len_target;
2012         pSMB->ParameterCount = cpu_to_le16(params);
2013         pSMB->TotalParameterCount = pSMB->ParameterCount;
2014         pSMB->DataCount = cpu_to_le16(name_len_target);
2015         pSMB->TotalDataCount = pSMB->DataCount;
2016         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2017         pSMB->DataOffset = cpu_to_le16(offset);
2018         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2019         pSMB->Reserved4 = 0;
2020         pSMB->hdr.smb_buf_length += byte_count;
2021         pSMB->ByteCount = cpu_to_le16(byte_count);
2022         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2023                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2024         cifs_stats_inc(&tcon->num_hardlinks);
2025         if (rc) {
2026                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2027         }
2028
2029         cifs_buf_release(pSMB);
2030         if (rc == -EAGAIN)
2031                 goto createHardLinkRetry;
2032
2033         return rc;
2034 }
2035
2036 int
2037 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2038                    const char *fromName, const char *toName,
2039                    const struct nls_table *nls_codepage, int remap)
2040 {
2041         int rc = 0;
2042         NT_RENAME_REQ *pSMB = NULL;
2043         RENAME_RSP *pSMBr = NULL;
2044         int bytes_returned;
2045         int name_len, name_len2;
2046         __u16 count;
2047
2048         cFYI(1, ("In CIFSCreateHardLink"));
2049 winCreateHardLinkRetry:
2050
2051         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2052                       (void **) &pSMBr);
2053         if (rc)
2054                 return rc;
2055
2056         pSMB->SearchAttributes =
2057             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2058                         ATTR_DIRECTORY);
2059         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2060         pSMB->ClusterCount = 0;
2061
2062         pSMB->BufferFormat = 0x04;
2063
2064         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2065                 name_len =
2066                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2067                                      PATH_MAX, nls_codepage, remap);
2068                 name_len++;     /* trailing null */
2069                 name_len *= 2;
2070                 pSMB->OldFileName[name_len] = 0;        /* pad */
2071                 pSMB->OldFileName[name_len + 1] = 0x04; 
2072                 name_len2 =
2073                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
2074                                      toName, PATH_MAX, nls_codepage, remap);
2075                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
2076                 name_len2 *= 2; /* convert to bytes */
2077         } else {                /* BB improve the check for buffer overruns BB */
2078                 name_len = strnlen(fromName, PATH_MAX);
2079                 name_len++;     /* trailing null */
2080                 strncpy(pSMB->OldFileName, fromName, name_len);
2081                 name_len2 = strnlen(toName, PATH_MAX);
2082                 name_len2++;    /* trailing null */
2083                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
2084                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2085                 name_len2++;    /* trailing null */
2086                 name_len2++;    /* signature byte */
2087         }
2088
2089         count = 1 /* string type byte */  + name_len + name_len2;
2090         pSMB->hdr.smb_buf_length += count;
2091         pSMB->ByteCount = cpu_to_le16(count);
2092
2093         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2094                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2095         cifs_stats_inc(&tcon->num_hardlinks);
2096         if (rc) {
2097                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2098         }
2099         cifs_buf_release(pSMB);
2100         if (rc == -EAGAIN)
2101                 goto winCreateHardLinkRetry;
2102
2103         return rc;
2104 }
2105
2106 int
2107 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2108                         const unsigned char *searchName,
2109                         char *symlinkinfo, const int buflen,
2110                         const struct nls_table *nls_codepage)
2111 {
2112 /* SMB_QUERY_FILE_UNIX_LINK */
2113         TRANSACTION2_QPI_REQ *pSMB = NULL;
2114         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2115         int rc = 0;
2116         int bytes_returned;
2117         int name_len;
2118         __u16 params, byte_count;
2119
2120         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2121
2122 querySymLinkRetry:
2123         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2124                       (void **) &pSMBr);
2125         if (rc)
2126                 return rc;
2127
2128         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2129                 name_len =
2130                     cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2131                                   /* find define for this maxpathcomponent */
2132                                   , nls_codepage);
2133                 name_len++;     /* trailing null */
2134                 name_len *= 2;
2135         } else {                /* BB improve the check for buffer overruns BB */
2136                 name_len = strnlen(searchName, PATH_MAX);
2137                 name_len++;     /* trailing null */
2138                 strncpy(pSMB->FileName, searchName, name_len);
2139         }
2140
2141         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2142         pSMB->TotalDataCount = 0;
2143         pSMB->MaxParameterCount = cpu_to_le16(2);
2144         /* BB find exact max data count below from sess structure BB */
2145         pSMB->MaxDataCount = cpu_to_le16(4000);
2146         pSMB->MaxSetupCount = 0;
2147         pSMB->Reserved = 0;
2148         pSMB->Flags = 0;
2149         pSMB->Timeout = 0;
2150         pSMB->Reserved2 = 0;
2151         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2152         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2153         pSMB->DataCount = 0;
2154         pSMB->DataOffset = 0;
2155         pSMB->SetupCount = 1;
2156         pSMB->Reserved3 = 0;
2157         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2158         byte_count = params + 1 /* pad */ ;
2159         pSMB->TotalParameterCount = cpu_to_le16(params);
2160         pSMB->ParameterCount = pSMB->TotalParameterCount;
2161         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2162         pSMB->Reserved4 = 0;
2163         pSMB->hdr.smb_buf_length += byte_count;
2164         pSMB->ByteCount = cpu_to_le16(byte_count);
2165
2166         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2167                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2168         if (rc) {
2169                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2170         } else {
2171                 /* decode response */
2172
2173                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2174                 if (rc || (pSMBr->ByteCount < 2))
2175                 /* BB also check enough total bytes returned */
2176                         rc = -EIO;      /* bad smb */
2177                 else {
2178                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2179                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2180
2181                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2182                                 name_len = UniStrnlen((wchar_t *) ((char *)
2183                                         &pSMBr->hdr.Protocol +data_offset),
2184                                         min_t(const int, buflen,count) / 2);
2185                         /* BB FIXME investigate remapping reserved chars here */
2186                                 cifs_strfromUCS_le(symlinkinfo,
2187                                         (__le16 *) ((char *)&pSMBr->hdr.Protocol +
2188                                                 data_offset),
2189                                         name_len, nls_codepage);
2190                         } else {
2191                                 strncpy(symlinkinfo,
2192                                         (char *) &pSMBr->hdr.Protocol + 
2193                                                 data_offset,
2194                                         min_t(const int, buflen, count));
2195                         }
2196                         symlinkinfo[buflen] = 0;
2197         /* just in case so calling code does not go off the end of buffer */
2198                 }
2199         }
2200         cifs_buf_release(pSMB);
2201         if (rc == -EAGAIN)
2202                 goto querySymLinkRetry;
2203         return rc;
2204 }
2205
2206 /* Initialize NT TRANSACT SMB into small smb request buffer.
2207    This assumes that all NT TRANSACTS that we init here have
2208    total parm and data under about 400 bytes (to fit in small cifs
2209    buffer size), which is the case so far, it easily fits. NB:
2210         Setup words themselves and ByteCount
2211         MaxSetupCount (size of returned setup area) and
2212         MaxParameterCount (returned parms size) must be set by caller */
2213 static int 
2214 smb_init_ntransact(const __u16 sub_command, const int setup_count,
2215                    const int parm_len, struct cifsTconInfo *tcon,
2216                    void ** ret_buf)
2217 {
2218         int rc;
2219         __u32 temp_offset;
2220         struct smb_com_ntransact_req * pSMB;
2221
2222         rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2223                                 (void **)&pSMB);
2224         if (rc)
2225                 return rc;
2226         *ret_buf = (void *)pSMB;
2227         pSMB->Reserved = 0;
2228         pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2229         pSMB->TotalDataCount  = 0;
2230         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2231                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2232         pSMB->ParameterCount = pSMB->TotalParameterCount;
2233         pSMB->DataCount  = pSMB->TotalDataCount;
2234         temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2235                         (setup_count * 2) - 4 /* for rfc1001 length itself */;
2236         pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2237         pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2238         pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2239         pSMB->SubCommand = cpu_to_le16(sub_command);
2240         return 0;
2241 }
2242
2243 static int
2244 validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2245                    int * pdatalen, int * pparmlen)
2246 {
2247         char * end_of_smb;
2248         __u32 data_count, data_offset, parm_count, parm_offset;
2249         struct smb_com_ntransact_rsp * pSMBr;
2250
2251         if(buf == NULL)
2252                 return -EINVAL;
2253
2254         pSMBr = (struct smb_com_ntransact_rsp *)buf;
2255
2256         /* ByteCount was converted from little endian in SendReceive */
2257         end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + 
2258                         (char *)&pSMBr->ByteCount;
2259
2260                 
2261         data_offset = le32_to_cpu(pSMBr->DataOffset);
2262         data_count = le32_to_cpu(pSMBr->DataCount);
2263         parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2264         parm_count = le32_to_cpu(pSMBr->ParameterCount);
2265
2266         *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2267         *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2268
2269         /* should we also check that parm and data areas do not overlap? */
2270         if(*ppparm > end_of_smb) {
2271                 cFYI(1,("parms start after end of smb"));
2272                 return -EINVAL;
2273         } else if(parm_count + *ppparm > end_of_smb) {
2274                 cFYI(1,("parm end after end of smb"));
2275                 return -EINVAL;
2276         } else if(*ppdata > end_of_smb) {
2277                 cFYI(1,("data starts after end of smb"));
2278                 return -EINVAL;
2279         } else if(data_count + *ppdata > end_of_smb) {
2280                 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2281                         *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr));  /* BB FIXME */
2282                 return -EINVAL;
2283         } else if(parm_count + data_count > pSMBr->ByteCount) {
2284                 cFYI(1,("parm count and data count larger than SMB"));
2285                 return -EINVAL;
2286         }
2287         return 0;
2288 }
2289
2290 int
2291 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2292                         const unsigned char *searchName,
2293                         char *symlinkinfo, const int buflen,__u16 fid,
2294                         const struct nls_table *nls_codepage)
2295 {
2296         int rc = 0;
2297         int bytes_returned;
2298         int name_len;
2299         struct smb_com_transaction_ioctl_req * pSMB;
2300         struct smb_com_transaction_ioctl_rsp * pSMBr;
2301
2302         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2303         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2304                       (void **) &pSMBr);
2305         if (rc)
2306                 return rc;
2307
2308         pSMB->TotalParameterCount = 0 ;
2309         pSMB->TotalDataCount = 0;
2310         pSMB->MaxParameterCount = cpu_to_le32(2);
2311         /* BB find exact data count max from sess structure BB */
2312         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2313                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2314         pSMB->MaxSetupCount = 4;
2315         pSMB->Reserved = 0;
2316         pSMB->ParameterOffset = 0;
2317         pSMB->DataCount = 0;
2318         pSMB->DataOffset = 0;
2319         pSMB->SetupCount = 4;
2320         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2321         pSMB->ParameterCount = pSMB->TotalParameterCount;
2322         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2323         pSMB->IsFsctl = 1; /* FSCTL */
2324         pSMB->IsRootFlag = 0;
2325         pSMB->Fid = fid; /* file handle always le */
2326         pSMB->ByteCount = 0;
2327
2328         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2329                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2330         if (rc) {
2331                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2332         } else {                /* decode response */
2333                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2334                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2335                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2336                 /* BB also check enough total bytes returned */
2337                         rc = -EIO;      /* bad smb */
2338                 else {
2339                         if(data_count && (data_count < 2048)) {
2340                                 char * end_of_smb = 2 /* sizeof byte count */ +
2341                                                 pSMBr->ByteCount +
2342                                                 (char *)&pSMBr->ByteCount;
2343
2344                                 struct reparse_data * reparse_buf = (struct reparse_data *)
2345                                         ((char *)&pSMBr->hdr.Protocol + data_offset);
2346                                 if((char*)reparse_buf >= end_of_smb) {
2347                                         rc = -EIO;
2348                                         goto qreparse_out;
2349                                 }
2350                                 if((reparse_buf->LinkNamesBuf + 
2351                                         reparse_buf->TargetNameOffset +
2352                                         reparse_buf->TargetNameLen) >
2353                                                 end_of_smb) {
2354                                         cFYI(1,("reparse buf extended beyond SMB"));
2355                                         rc = -EIO;
2356                                         goto qreparse_out;
2357                                 }
2358                                 
2359                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2360                                         name_len = UniStrnlen((wchar_t *)
2361                                                         (reparse_buf->LinkNamesBuf + 
2362                                                         reparse_buf->TargetNameOffset),
2363                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
2364                                         cifs_strfromUCS_le(symlinkinfo,
2365                                                 (__le16 *) (reparse_buf->LinkNamesBuf + 
2366                                                 reparse_buf->TargetNameOffset),
2367                                                 name_len, nls_codepage);
2368                                 } else { /* ASCII names */
2369                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
2370                                                 reparse_buf->TargetNameOffset, 
2371                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
2372                                 }
2373                         } else {
2374                                 rc = -EIO;
2375                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2376                         }
2377                         symlinkinfo[buflen] = 0; /* just in case so the caller
2378                                         does not go off the end of the buffer */
2379                         cFYI(1,("readlink result - %s",symlinkinfo));
2380                 }
2381         }
2382 qreparse_out:
2383         cifs_buf_release(pSMB);
2384
2385         /* Note: On -EAGAIN error only caller can retry on handle based calls
2386                 since file handle passed in no longer valid */
2387
2388         return rc;
2389 }
2390
2391 #ifdef CONFIG_CIFS_POSIX
2392
2393 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2394 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2395 {
2396         /* u8 cifs fields do not need le conversion */
2397         ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2398         ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
2399         ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2400         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2401
2402         return;
2403 }
2404
2405 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2406 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2407                                 const int acl_type,const int size_of_data_area)
2408 {
2409         int size =  0;
2410         int i;
2411         __u16 count;
2412         struct cifs_posix_ace * pACE;
2413         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2414         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2415
2416         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2417                 return -EOPNOTSUPP;
2418
2419         if(acl_type & ACL_TYPE_ACCESS) {
2420                 count = le16_to_cpu(cifs_acl->access_entry_count);
2421                 pACE = &cifs_acl->ace_array[0];
2422                 size = sizeof(struct cifs_posix_acl);
2423                 size += sizeof(struct cifs_posix_ace) * count;
2424                 /* check if we would go beyond end of SMB */
2425                 if(size_of_data_area < size) {
2426                         cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2427                         return -EINVAL;
2428                 }
2429         } else if(acl_type & ACL_TYPE_DEFAULT) {
2430                 count = le16_to_cpu(cifs_acl->access_entry_count);
2431                 size = sizeof(struct cifs_posix_acl);
2432                 size += sizeof(struct cifs_posix_ace) * count;
2433 /* skip past access ACEs to get to default ACEs */
2434                 pACE = &cifs_acl->ace_array[count];
2435                 count = le16_to_cpu(cifs_acl->default_entry_count);
2436                 size += sizeof(struct cifs_posix_ace) * count;
2437                 /* check if we would go beyond end of SMB */
2438                 if(size_of_data_area < size)
2439                         return -EINVAL;
2440         } else {
2441                 /* illegal type */
2442                 return -EINVAL;
2443         }
2444
2445         size = posix_acl_xattr_size(count);
2446         if((buflen == 0) || (local_acl == NULL)) {
2447                 /* used to query ACL EA size */                         
2448         } else if(size > buflen) {
2449                 return -ERANGE;
2450         } else /* buffer big enough */ {
2451                 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2452                 for(i = 0;i < count ;i++) {
2453                         cifs_convert_ace(&local_acl->a_entries[i],pACE);
2454                         pACE ++;
2455                 }
2456         }
2457         return size;
2458 }
2459
2460 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2461                         const posix_acl_xattr_entry * local_ace)
2462 {
2463         __u16 rc = 0; /* 0 = ACL converted ok */
2464
2465         cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2466         cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
2467         /* BB is there a better way to handle the large uid? */
2468         if(local_ace->e_id == cpu_to_le32(-1)) {
2469         /* Probably no need to le convert -1 on any arch but can not hurt */
2470                 cifs_ace->cifs_uid = cpu_to_le64(-1);
2471         } else 
2472                 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2473         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2474         return rc;
2475 }
2476
2477 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2478 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2479                 const int acl_type)
2480 {
2481         __u16 rc = 0;
2482         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2483         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2484         int count;
2485         int i;
2486
2487         if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2488                 return 0;
2489
2490         count = posix_acl_xattr_count((size_t)buflen);
2491         cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2492                 count, buflen, le32_to_cpu(local_acl->a_version)));
2493         if(le32_to_cpu(local_acl->a_version) != 2) {
2494                 cFYI(1,("unknown POSIX ACL version %d",
2495                      le32_to_cpu(local_acl->a_version)));
2496                 return 0;
2497         }
2498         cifs_acl->version = cpu_to_le16(1);
2499         if(acl_type == ACL_TYPE_ACCESS) 
2500                 cifs_acl->access_entry_count = cpu_to_le16(count);
2501         else if(acl_type == ACL_TYPE_DEFAULT)
2502                 cifs_acl->default_entry_count = cpu_to_le16(count);
2503         else {
2504                 cFYI(1,("unknown ACL type %d",acl_type));
2505                 return 0;
2506         }
2507         for(i=0;i<count;i++) {
2508                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2509                                         &local_acl->a_entries[i]);
2510                 if(rc != 0) {
2511                         /* ACE not converted */
2512                         break;
2513                 }
2514         }
2515         if(rc == 0) {
2516                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2517                 rc += sizeof(struct cifs_posix_acl);
2518                 /* BB add check to make sure ACL does not overflow SMB */
2519         }
2520         return rc;
2521 }
2522
2523 int
2524 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2525                         const unsigned char *searchName,
2526                         char *acl_inf, const int buflen, const int acl_type,
2527                         const struct nls_table *nls_codepage, int remap)
2528 {
2529 /* SMB_QUERY_POSIX_ACL */
2530         TRANSACTION2_QPI_REQ *pSMB = NULL;
2531         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2532         int rc = 0;
2533         int bytes_returned;
2534         int name_len;
2535         __u16 params, byte_count;
2536                                                                                                                                              
2537         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2538
2539 queryAclRetry:
2540         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2541                 (void **) &pSMBr);
2542         if (rc)
2543                 return rc;
2544                                                                                                                                              
2545         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2546                 name_len =
2547                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2548                                          PATH_MAX, nls_codepage, remap);
2549                 name_len++;     /* trailing null */
2550                 name_len *= 2;
2551                 pSMB->FileName[name_len] = 0;
2552                 pSMB->FileName[name_len+1] = 0;
2553         } else {                /* BB improve the check for buffer overruns BB */
2554                 name_len = strnlen(searchName, PATH_MAX);
2555                 name_len++;     /* trailing null */
2556                 strncpy(pSMB->FileName, searchName, name_len);
2557         }
2558
2559         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2560         pSMB->TotalDataCount = 0;
2561         pSMB->MaxParameterCount = cpu_to_le16(2);
2562         /* BB find exact max data count below from sess structure BB */
2563         pSMB->MaxDataCount = cpu_to_le16(4000);
2564         pSMB->MaxSetupCount = 0;
2565         pSMB->Reserved = 0;
2566         pSMB->Flags = 0;
2567         pSMB->Timeout = 0;
2568         pSMB->Reserved2 = 0;
2569         pSMB->ParameterOffset = cpu_to_le16(
2570                 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2571         pSMB->DataCount = 0;
2572         pSMB->DataOffset = 0;
2573         pSMB->SetupCount = 1;
2574         pSMB->Reserved3 = 0;
2575         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2576         byte_count = params + 1 /* pad */ ;
2577         pSMB->TotalParameterCount = cpu_to_le16(params);
2578         pSMB->ParameterCount = pSMB->TotalParameterCount;
2579         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2580         pSMB->Reserved4 = 0;
2581         pSMB->hdr.smb_buf_length += byte_count;
2582         pSMB->ByteCount = cpu_to_le16(byte_count);
2583
2584         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2585                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2586         cifs_stats_inc(&tcon->num_acl_get);
2587         if (rc) {
2588                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2589         } else {
2590                 /* decode response */
2591  
2592                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2593                 if (rc || (pSMBr->ByteCount < 2))
2594                 /* BB also check enough total bytes returned */
2595                         rc = -EIO;      /* bad smb */
2596                 else {
2597                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2598                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2599                         rc = cifs_copy_posix_acl(acl_inf,
2600                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2601                                 buflen,acl_type,count);
2602                 }
2603         }
2604         cifs_buf_release(pSMB);
2605         if (rc == -EAGAIN)
2606                 goto queryAclRetry;
2607         return rc;
2608 }
2609
2610 int
2611 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2612                         const unsigned char *fileName,
2613                         const char *local_acl, const int buflen, 
2614                         const int acl_type,
2615                         const struct nls_table *nls_codepage, int remap)
2616 {
2617         struct smb_com_transaction2_spi_req *pSMB = NULL;
2618         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2619         char *parm_data;
2620         int name_len;
2621         int rc = 0;
2622         int bytes_returned = 0;
2623         __u16 params, byte_count, data_count, param_offset, offset;
2624
2625         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2626 setAclRetry:
2627         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2628                       (void **) &pSMBr);
2629         if (rc)
2630                 return rc;
2631         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2632                 name_len =
2633                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
2634                                       PATH_MAX, nls_codepage, remap);
2635                 name_len++;     /* trailing null */
2636                 name_len *= 2;
2637         } else {                /* BB improve the check for buffer overruns BB */
2638                 name_len = strnlen(fileName, PATH_MAX);
2639                 name_len++;     /* trailing null */
2640                 strncpy(pSMB->FileName, fileName, name_len);
2641         }
2642         params = 6 + name_len;
2643         pSMB->MaxParameterCount = cpu_to_le16(2);
2644         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2645         pSMB->MaxSetupCount = 0;
2646         pSMB->Reserved = 0;
2647         pSMB->Flags = 0;
2648         pSMB->Timeout = 0;
2649         pSMB->Reserved2 = 0;
2650         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2651                                      InformationLevel) - 4;
2652         offset = param_offset + params;
2653         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2654         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2655
2656         /* convert to on the wire format for POSIX ACL */
2657         data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2658
2659         if(data_count == 0) {
2660                 rc = -EOPNOTSUPP;
2661                 goto setACLerrorExit;
2662         }
2663         pSMB->DataOffset = cpu_to_le16(offset);
2664         pSMB->SetupCount = 1;
2665         pSMB->Reserved3 = 0;
2666         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2667         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2668         byte_count = 3 /* pad */  + params + data_count;
2669         pSMB->DataCount = cpu_to_le16(data_count);
2670         pSMB->TotalDataCount = pSMB->DataCount;
2671         pSMB->ParameterCount = cpu_to_le16(params);
2672         pSMB->TotalParameterCount = pSMB->ParameterCount;
2673         pSMB->Reserved4 = 0;
2674         pSMB->hdr.smb_buf_length += byte_count;
2675         pSMB->ByteCount = cpu_to_le16(byte_count);
2676         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2677                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2678         if (rc) {
2679                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2680         }
2681
2682 setACLerrorExit:
2683         cifs_buf_release(pSMB);
2684         if (rc == -EAGAIN)
2685                 goto setAclRetry;
2686         return rc;
2687 }
2688
2689 /* BB fix tabs in this function FIXME BB */
2690 int
2691 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2692                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2693 {
2694         int rc = 0;
2695         struct smb_t2_qfi_req *pSMB = NULL;
2696         struct smb_t2_qfi_rsp *pSMBr = NULL;
2697         int bytes_returned;
2698         __u16 params, byte_count;
2699
2700         cFYI(1,("In GetExtAttr"));
2701         if(tcon == NULL)
2702                 return -ENODEV;
2703
2704 GetExtAttrRetry:
2705         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2706                       (void **) &pSMBr);
2707         if (rc)
2708                 return rc;
2709
2710         params = 2 /* level */ +2 /* fid */;
2711         pSMB->t2.TotalDataCount = 0;
2712         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2713         /* BB find exact max data count below from sess structure BB */
2714         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2715         pSMB->t2.MaxSetupCount = 0;
2716         pSMB->t2.Reserved = 0;
2717         pSMB->t2.Flags = 0;
2718         pSMB->t2.Timeout = 0;
2719         pSMB->t2.Reserved2 = 0;
2720         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2721                         Fid) - 4);
2722         pSMB->t2.DataCount = 0;
2723         pSMB->t2.DataOffset = 0;
2724         pSMB->t2.SetupCount = 1;
2725         pSMB->t2.Reserved3 = 0;
2726         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2727         byte_count = params + 1 /* pad */ ;
2728         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2729         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2730         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2731         pSMB->Pad = 0;
2732         pSMB->Fid = netfid;
2733         pSMB->hdr.smb_buf_length += byte_count;
2734         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2735
2736         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2737                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2738         if (rc) {
2739                 cFYI(1, ("error %d in GetExtAttr", rc));
2740         } else {
2741                 /* decode response */
2742                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2743                 if (rc || (pSMBr->ByteCount < 2))
2744                 /* BB also check enough total bytes returned */
2745                         /* If rc should we check for EOPNOSUPP and
2746                         disable the srvino flag? or in caller? */
2747                         rc = -EIO;      /* bad smb */
2748                 else {
2749                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2750                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2751                         struct file_chattr_info * pfinfo;
2752                         /* BB Do we need a cast or hash here ? */
2753                         if(count != 16) {
2754                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
2755                                 rc = -EIO;
2756                                 goto GetExtAttrOut;
2757                         }
2758                         pfinfo = (struct file_chattr_info *)
2759                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2760                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2761                         *pMask = le64_to_cpu(pfinfo->mask);
2762                 }
2763         }
2764 GetExtAttrOut:
2765         cifs_buf_release(pSMB);
2766         if (rc == -EAGAIN)
2767                 goto GetExtAttrRetry;
2768         return rc;
2769 }
2770
2771
2772 #endif /* CONFIG_POSIX */
2773
2774
2775 /* security id for everyone */
2776 const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2777 /* group users */
2778 const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2779
2780 /* Convert CIFS ACL to POSIX form */
2781 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2782 {
2783         return 0;
2784 }
2785
2786 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2787 int
2788 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2789          /*  BB fix up return info */ char *acl_inf, const int buflen, 
2790                   const int acl_type /* ACCESS/DEFAULT not sure implication */)
2791 {
2792         int rc = 0;
2793         int buf_type = 0;
2794         QUERY_SEC_DESC_REQ * pSMB;
2795         struct kvec iov[1];
2796
2797         cFYI(1, ("GetCifsACL"));
2798
2799         rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 
2800                         8 /* parm len */, tcon, (void **) &pSMB);
2801         if (rc)
2802                 return rc;
2803
2804         pSMB->MaxParameterCount = cpu_to_le32(4);
2805         /* BB TEST with big acls that might need to be e.g. larger than 16K */
2806         pSMB->MaxSetupCount = 0;
2807         pSMB->Fid = fid; /* file handle always le */
2808         pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2809                                      CIFS_ACL_DACL);
2810         pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2811         pSMB->hdr.smb_buf_length += 11;
2812         iov[0].iov_base = (char *)pSMB;
2813         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2814
2815         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2816         cifs_stats_inc(&tcon->num_acl_get);
2817         if (rc) {
2818                 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2819         } else {                /* decode response */
2820                 struct cifs_sid * psec_desc;
2821                 __le32 * parm;
2822                 int parm_len;
2823                 int data_len;
2824                 int acl_len;
2825                 struct smb_com_ntransact_rsp * pSMBr;
2826
2827 /* validate_nttransact */
2828                 rc = validate_ntransact(iov[0].iov_base, (char **)&parm, 
2829                                         (char **)&psec_desc,
2830                                         &parm_len, &data_len);
2831                 
2832                 if(rc)
2833                         goto qsec_out;
2834                 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2835
2836                 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc));  /* BB removeme BB */
2837
2838                 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2839                         rc = -EIO;      /* bad smb */
2840                         goto qsec_out;
2841                 }
2842
2843 /* BB check that data area is minimum length and as big as acl_len */
2844
2845                 acl_len = le32_to_cpu(*(__le32 *)parm);
2846                 /* BB check if(acl_len > bufsize) */
2847
2848                 parse_sec_desc(psec_desc, acl_len);
2849         }
2850 qsec_out:
2851         if(buf_type == CIFS_SMALL_BUFFER)
2852                 cifs_small_buf_release(iov[0].iov_base);
2853         else if(buf_type == CIFS_LARGE_BUFFER)
2854                 cifs_buf_release(iov[0].iov_base);
2855 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2856         return rc;
2857 }
2858
2859
2860 /* Legacy Query Path Information call for lookup to old servers such
2861    as Win9x/WinME */
2862 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2863                  const unsigned char *searchName,
2864                  FILE_ALL_INFO * pFinfo,
2865                  const struct nls_table *nls_codepage, int remap)
2866 {
2867         QUERY_INFORMATION_REQ * pSMB;
2868         QUERY_INFORMATION_RSP * pSMBr;
2869         int rc = 0;
2870         int bytes_returned;
2871         int name_len;
2872
2873         cFYI(1, ("In SMBQPath path %s", searchName)); 
2874 QInfRetry:
2875         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2876                       (void **) &pSMBr);
2877         if (rc)
2878                 return rc;
2879
2880         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2881                 name_len =
2882                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2883                                      PATH_MAX, nls_codepage, remap);
2884                 name_len++;     /* trailing null */
2885                 name_len *= 2;
2886         } else {               
2887                 name_len = strnlen(searchName, PATH_MAX);
2888                 name_len++;     /* trailing null */
2889                 strncpy(pSMB->FileName, searchName, name_len);
2890         }
2891         pSMB->BufferFormat = 0x04;
2892         name_len++; /* account for buffer type byte */  
2893         pSMB->hdr.smb_buf_length += (__u16) name_len;
2894         pSMB->ByteCount = cpu_to_le16(name_len);
2895
2896         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2897                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2898         if (rc) {
2899                 cFYI(1, ("Send error in QueryInfo = %d", rc));
2900         } else if (pFinfo) {            /* decode response */
2901                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2902                 pFinfo->AllocationSize =
2903                         cpu_to_le64(le32_to_cpu(pSMBr->size));
2904                 pFinfo->EndOfFile = pFinfo->AllocationSize;
2905                 pFinfo->Attributes =
2906                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
2907         } else
2908                 rc = -EIO; /* bad buffer passed in */
2909
2910         cifs_buf_release(pSMB);
2911
2912         if (rc == -EAGAIN)
2913                 goto QInfRetry;
2914
2915         return rc;
2916 }
2917
2918
2919
2920
2921 int
2922 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2923                  const unsigned char *searchName,
2924                  FILE_ALL_INFO * pFindData,
2925                  const struct nls_table *nls_codepage, int remap)
2926 {
2927 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2928         TRANSACTION2_QPI_REQ *pSMB = NULL;
2929         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2930         int rc = 0;
2931         int bytes_returned;
2932         int name_len;
2933         __u16 params, byte_count;
2934
2935 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2936 QPathInfoRetry:
2937         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2938                       (void **) &pSMBr);
2939         if (rc)
2940                 return rc;
2941
2942         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2943                 name_len =
2944                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2945                                      PATH_MAX, nls_codepage, remap);
2946                 name_len++;     /* trailing null */
2947                 name_len *= 2;
2948         } else {                /* BB improve the check for buffer overruns BB */
2949                 name_len = strnlen(searchName, PATH_MAX);
2950                 name_len++;     /* trailing null */
2951                 strncpy(pSMB->FileName, searchName, name_len);
2952         }
2953
2954         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2955         pSMB->TotalDataCount = 0;
2956         pSMB->MaxParameterCount = cpu_to_le16(2);
2957         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2958         pSMB->MaxSetupCount = 0;
2959         pSMB->Reserved = 0;
2960         pSMB->Flags = 0;
2961         pSMB->Timeout = 0;
2962         pSMB->Reserved2 = 0;
2963         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2964         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2965         pSMB->DataCount = 0;
2966         pSMB->DataOffset = 0;
2967         pSMB->SetupCount = 1;
2968         pSMB->Reserved3 = 0;
2969         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2970         byte_count = params + 1 /* pad */ ;
2971         pSMB->TotalParameterCount = cpu_to_le16(params);
2972         pSMB->ParameterCount = pSMB->TotalParameterCount;
2973         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2974         pSMB->Reserved4 = 0;
2975         pSMB->hdr.smb_buf_length += byte_count;
2976         pSMB->ByteCount = cpu_to_le16(byte_count);
2977
2978         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2979                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2980         if (rc) {
2981                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2982         } else {                /* decode response */
2983                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2984
2985                 if (rc || (pSMBr->ByteCount < 40)) 
2986                         rc = -EIO;      /* bad smb */
2987                 else if (pFindData){
2988                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2989                         memcpy((char *) pFindData,
2990                                (char *) &pSMBr->hdr.Protocol +
2991                                data_offset, sizeof (FILE_ALL_INFO));
2992                 } else
2993                     rc = -ENOMEM;
2994         }
2995         cifs_buf_release(pSMB);
2996         if (rc == -EAGAIN)
2997                 goto QPathInfoRetry;
2998
2999         return rc;
3000 }
3001
3002 int
3003 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3004                      const unsigned char *searchName,
3005                      FILE_UNIX_BASIC_INFO * pFindData,
3006                      const struct nls_table *nls_codepage, int remap)
3007 {
3008 /* SMB_QUERY_FILE_UNIX_BASIC */
3009         TRANSACTION2_QPI_REQ *pSMB = NULL;
3010         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3011         int rc = 0;
3012         int bytes_returned = 0;
3013         int name_len;
3014         __u16 params, byte_count;
3015
3016         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3017 UnixQPathInfoRetry:
3018         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3019                       (void **) &pSMBr);
3020         if (rc)
3021                 return rc;
3022
3023         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3024                 name_len =
3025                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3026                                   PATH_MAX, nls_codepage, remap);
3027                 name_len++;     /* trailing null */
3028                 name_len *= 2;
3029         } else {                /* BB improve the check for buffer overruns BB */
3030                 name_len = strnlen(searchName, PATH_MAX);
3031                 name_len++;     /* trailing null */
3032                 strncpy(pSMB->FileName, searchName, name_len);
3033         }
3034
3035         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3036         pSMB->TotalDataCount = 0;
3037         pSMB->MaxParameterCount = cpu_to_le16(2);
3038         /* BB find exact max SMB PDU from sess structure BB */
3039         pSMB->MaxDataCount = cpu_to_le16(4000); 
3040         pSMB->MaxSetupCount = 0;
3041         pSMB->Reserved = 0;
3042         pSMB->Flags = 0;
3043         pSMB->Timeout = 0;
3044         pSMB->Reserved2 = 0;
3045         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3046         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3047         pSMB->DataCount = 0;
3048         pSMB->DataOffset = 0;
3049         pSMB->SetupCount = 1;
3050         pSMB->Reserved3 = 0;
3051         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3052         byte_count = params + 1 /* pad */ ;
3053         pSMB->TotalParameterCount = cpu_to_le16(params);
3054         pSMB->ParameterCount = pSMB->TotalParameterCount;
3055         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3056         pSMB->Reserved4 = 0;
3057         pSMB->hdr.smb_buf_length += byte_count;
3058         pSMB->ByteCount = cpu_to_le16(byte_count);
3059
3060         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3061                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3062         if (rc) {
3063                 cFYI(1, ("Send error in QPathInfo = %d", rc));
3064         } else {                /* decode response */
3065                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3066
3067                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3068                         rc = -EIO;      /* bad smb */
3069                 } else {
3070                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3071                         memcpy((char *) pFindData,
3072                                (char *) &pSMBr->hdr.Protocol +
3073                                data_offset,
3074                                sizeof (FILE_UNIX_BASIC_INFO));
3075                 }
3076         }
3077         cifs_buf_release(pSMB);
3078         if (rc == -EAGAIN)
3079                 goto UnixQPathInfoRetry;
3080
3081         return rc;
3082 }
3083
3084 #if 0  /* function unused at present */
3085 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3086                const char *searchName, FILE_ALL_INFO * findData,
3087                const struct nls_table *nls_codepage)
3088 {
3089 /* level 257 SMB_ */
3090         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3091         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3092         int rc = 0;
3093         int bytes_returned;
3094         int name_len;
3095         __u16 params, byte_count;
3096
3097         cFYI(1, ("In FindUnique"));
3098 findUniqueRetry:
3099         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3100                       (void **) &pSMBr);
3101         if (rc)
3102                 return rc;
3103
3104         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3105                 name_len =
3106                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
3107                                   /* find define for this maxpathcomponent */
3108                                   , nls_codepage);
3109                 name_len++;     /* trailing null */
3110                 name_len *= 2;
3111         } else {                /* BB improve the check for buffer overruns BB */
3112                 name_len = strnlen(searchName, PATH_MAX);
3113                 name_len++;     /* trailing null */
3114                 strncpy(pSMB->FileName, searchName, name_len);
3115         }
3116
3117         params = 12 + name_len /* includes null */ ;
3118         pSMB->TotalDataCount = 0;       /* no EAs */
3119         pSMB->MaxParameterCount = cpu_to_le16(2);
3120         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3121         pSMB->MaxSetupCount = 0;
3122         pSMB->Reserved = 0;
3123         pSMB->Flags = 0;
3124         pSMB->Timeout = 0;
3125         pSMB->Reserved2 = 0;
3126         pSMB->ParameterOffset = cpu_to_le16(
3127          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3128         pSMB->DataCount = 0;
3129         pSMB->DataOffset = 0;
3130         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
3131         pSMB->Reserved3 = 0;
3132         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3133         byte_count = params + 1 /* pad */ ;
3134         pSMB->TotalParameterCount = cpu_to_le16(params);
3135         pSMB->ParameterCount = pSMB->TotalParameterCount;
3136         pSMB->SearchAttributes =
3137             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3138                         ATTR_DIRECTORY);
3139         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
3140         pSMB->SearchFlags = cpu_to_le16(1);
3141         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3142         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
3143         pSMB->hdr.smb_buf_length += byte_count;
3144         pSMB->ByteCount = cpu_to_le16(byte_count);
3145
3146         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3147                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3148
3149         if (rc) {
3150                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3151         } else {                /* decode response */
3152                 cifs_stats_inc(&tcon->num_ffirst);
3153                 /* BB fill in */
3154         }
3155
3156         cifs_buf_release(pSMB);
3157         if (rc == -EAGAIN)
3158                 goto findUniqueRetry;
3159
3160         return rc;
3161 }
3162 #endif /* end unused (temporarily) function */
3163
3164 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3165 int
3166 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3167               const char *searchName, 
3168               const struct nls_table *nls_codepage,
3169               __u16 *   pnetfid,
3170               struct cifs_search_info * psrch_inf, int remap, const char dirsep)
3171 {
3172 /* level 257 SMB_ */
3173         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3174         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3175         T2_FFIRST_RSP_PARMS * parms;
3176         int rc = 0;
3177         int bytes_returned = 0;
3178         int name_len;
3179         __u16 params, byte_count;
3180
3181         cFYI(1, ("In FindFirst for %s",searchName));
3182
3183 findFirstRetry:
3184         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3185                       (void **) &pSMBr);
3186         if (rc)
3187                 return rc;
3188
3189         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3190                 name_len =
3191                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
3192                                  PATH_MAX, nls_codepage, remap);
3193                 /* We can not add the asterik earlier in case
3194                 it got remapped to 0xF03A as if it were part of the
3195                 directory name instead of a wildcard */
3196                 name_len *= 2;
3197                 pSMB->FileName[name_len] = dirsep;
3198                 pSMB->FileName[name_len+1] = 0;
3199                 pSMB->FileName[name_len+2] = '*';
3200                 pSMB->FileName[name_len+3] = 0;
3201                 name_len += 4; /* now the trailing null */
3202                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3203                 pSMB->FileName[name_len+1] = 0;
3204                 name_len += 2;
3205         } else {        /* BB add check for overrun of SMB buf BB */
3206                 name_len = strnlen(searchName, PATH_MAX);
3207 /* BB fix here and in unicode clause above ie
3208                 if(name_len > buffersize-header)
3209                         free buffer exit; BB */
3210                 strncpy(pSMB->FileName, searchName, name_len);
3211                 pSMB->FileName[name_len] = dirsep;
3212                 pSMB->FileName[name_len+1] = '*';
3213                 pSMB->FileName[name_len+2] = 0;
3214                 name_len += 3;
3215         }
3216
3217         params = 12 + name_len /* includes null */ ;
3218         pSMB->TotalDataCount = 0;       /* no EAs */
3219         pSMB->MaxParameterCount = cpu_to_le16(10);
3220         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3221                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3222         pSMB->MaxSetupCount = 0;
3223         pSMB->Reserved = 0;
3224         pSMB->Flags = 0;
3225         pSMB->Timeout = 0;
3226         pSMB->Reserved2 = 0;
3227         byte_count = params + 1 /* pad */ ;
3228         pSMB->TotalParameterCount = cpu_to_le16(params);
3229         pSMB->ParameterCount = pSMB->TotalParameterCount;
3230         pSMB->ParameterOffset = cpu_to_le16(
3231               offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3232                 - 4);
3233         pSMB->DataCount = 0;
3234         pSMB->DataOffset = 0;
3235         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
3236         pSMB->Reserved3 = 0;
3237         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3238         pSMB->SearchAttributes =
3239             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3240                         ATTR_DIRECTORY);
3241         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3242         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
3243                 CIFS_SEARCH_RETURN_RESUME);
3244         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3245
3246         /* BB what should we set StorageType to? Does it matter? BB */
3247         pSMB->SearchStorageType = 0;
3248         pSMB->hdr.smb_buf_length += byte_count;
3249         pSMB->ByteCount = cpu_to_le16(byte_count);
3250
3251         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3252                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3253         cifs_stats_inc(&tcon->num_ffirst);
3254
3255         if (rc) {/* BB add logic to retry regular search if Unix search
3256                         rejected unexpectedly by server */
3257                 /* BB Add code to handle unsupported level rc */
3258                 cFYI(1, ("Error in FindFirst = %d", rc));
3259
3260                 cifs_buf_release(pSMB);
3261
3262                 /* BB eventually could optimize out free and realloc of buf */
3263                 /*    for this case */
3264                 if (rc == -EAGAIN)
3265                         goto findFirstRetry;
3266         } else { /* decode response */
3267                 /* BB remember to free buffer if error BB */
3268                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3269                 if(rc == 0) {
3270                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3271                                 psrch_inf->unicode = TRUE;
3272                         else
3273                                 psrch_inf->unicode = FALSE;
3274
3275                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3276                         psrch_inf->smallBuf = 0;
3277                         psrch_inf->srch_entries_start = 
3278                                 (char *) &pSMBr->hdr.Protocol + 
3279                                         le16_to_cpu(pSMBr->t2.DataOffset);
3280                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3281                                le16_to_cpu(pSMBr->t2.ParameterOffset));
3282
3283                         if(parms->EndofSearch)
3284                                 psrch_inf->endOfSearch = TRUE;
3285                         else
3286                                 psrch_inf->endOfSearch = FALSE;
3287
3288                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3289                         psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3290                                 psrch_inf->entries_in_buffer;
3291                         *pnetfid = parms->SearchHandle;
3292                 } else {
3293                         cifs_buf_release(pSMB);
3294                 }
3295         }
3296
3297         return rc;
3298 }
3299
3300 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3301             __u16 searchHandle, struct cifs_search_info * psrch_inf)
3302 {
3303         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3304         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3305         T2_FNEXT_RSP_PARMS * parms;
3306         char *response_data;
3307         int rc = 0;
3308         int bytes_returned, name_len;
3309         __u16 params, byte_count;
3310
3311         cFYI(1, ("In FindNext"));
3312
3313         if(psrch_inf->endOfSearch == TRUE)
3314                 return -ENOENT;
3315
3316         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3317                 (void **) &pSMBr);
3318         if (rc)
3319                 return rc;
3320
3321         params = 14;    /* includes 2 bytes of null string, converted to LE below */
3322         byte_count = 0;
3323         pSMB->TotalDataCount = 0;       /* no EAs */
3324         pSMB->MaxParameterCount = cpu_to_le16(8);
3325         pSMB->MaxDataCount =
3326             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3327         pSMB->MaxSetupCount = 0;
3328         pSMB->Reserved = 0;
3329         pSMB->Flags = 0;
3330         pSMB->Timeout = 0;
3331         pSMB->Reserved2 = 0;
3332         pSMB->ParameterOffset =  cpu_to_le16(
3333               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3334         pSMB->DataCount = 0;
3335         pSMB->DataOffset = 0;
3336         pSMB->SetupCount = 1;
3337         pSMB->Reserved3 = 0;
3338         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3339         pSMB->SearchHandle = searchHandle;      /* always kept as le */
3340         pSMB->SearchCount =
3341                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3342         /* test for Unix extensions */
3343 /*      if (tcon->ses->capabilities & CAP_UNIX) {
3344                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3345                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3346         } else {
3347                 pSMB->InformationLevel =
3348                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3349                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3350         } */
3351         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3352         pSMB->ResumeKey = psrch_inf->resume_key;
3353         pSMB->SearchFlags =
3354               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3355
3356         name_len = psrch_inf->resume_name_len;
3357         params += name_len;
3358         if(name_len < PATH_MAX) {
3359                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3360                 byte_count += name_len;
3361                 /* 14 byte parm len above enough for 2 byte null terminator */
3362                 pSMB->ResumeFileName[name_len] = 0;
3363                 pSMB->ResumeFileName[name_len+1] = 0;
3364         } else {
3365                 rc = -EINVAL;
3366                 goto FNext2_err_exit;
3367         }
3368         byte_count = params + 1 /* pad */ ;
3369         pSMB->TotalParameterCount = cpu_to_le16(params);
3370         pSMB->ParameterCount = pSMB->TotalParameterCount;
3371         pSMB->hdr.smb_buf_length += byte_count;
3372         pSMB->ByteCount = cpu_to_le16(byte_count);
3373                                                                                               
3374         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3375                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3376         cifs_stats_inc(&tcon->num_fnext);
3377         if (rc) {
3378                 if (rc == -EBADF) {
3379                         psrch_inf->endOfSearch = TRUE;
3380                         rc = 0; /* search probably was closed at end of search above */
3381                 } else
3382                         cFYI(1, ("FindNext returned = %d", rc));
3383         } else {                /* decode response */
3384                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3385                 
3386                 if(rc == 0) {
3387                         /* BB fixme add lock for file (srch_info) struct here */
3388                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3389                                 psrch_inf->unicode = TRUE;
3390                         else
3391                                 psrch_inf->unicode = FALSE;
3392                         response_data = (char *) &pSMBr->hdr.Protocol +
3393                                le16_to_cpu(pSMBr->t2.ParameterOffset);
3394                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
3395                         response_data = (char *)&pSMBr->hdr.Protocol +
3396                                 le16_to_cpu(pSMBr->t2.DataOffset);
3397                         if(psrch_inf->smallBuf)
3398                                 cifs_small_buf_release(
3399                                         psrch_inf->ntwrk_buf_start);
3400                         else
3401                                 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3402                         psrch_inf->srch_entries_start = response_data;
3403                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
3404                         psrch_inf->smallBuf = 0;
3405                         if(parms->EndofSearch)
3406                                 psrch_inf->endOfSearch = TRUE;
3407                         else
3408                                 psrch_inf->endOfSearch = FALSE;
3409                                                                                               
3410                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3411                         psrch_inf->index_of_last_entry +=
3412                                 psrch_inf->entries_in_buffer;
3413 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3414
3415                         /* BB fixme add unlock here */
3416                 }
3417
3418         }
3419
3420         /* BB On error, should we leave previous search buf (and count and
3421         last entry fields) intact or free the previous one? */
3422
3423         /* Note: On -EAGAIN error only caller can retry on handle based calls
3424         since file handle passed in no longer valid */
3425 FNext2_err_exit:
3426         if (rc != 0)
3427                 cifs_buf_release(pSMB);
3428                                                                                               
3429         return rc;
3430 }
3431
3432 int
3433 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3434 {
3435         int rc = 0;
3436         FINDCLOSE_REQ *pSMB = NULL;
3437         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3438         int bytes_returned;
3439
3440         cFYI(1, ("In CIFSSMBFindClose"));
3441         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3442
3443         /* no sense returning error if session restarted
3444                 as file handle has been closed */
3445         if(rc == -EAGAIN)
3446                 return 0;
3447         if (rc)
3448                 return rc;
3449
3450         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
3451         pSMB->FileID = searchHandle;
3452         pSMB->ByteCount = 0;
3453         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3454                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3455         if (rc) {
3456                 cERROR(1, ("Send error in FindClose = %d", rc));
3457         }
3458         cifs_stats_inc(&tcon->num_fclose);
3459         cifs_small_buf_release(pSMB);
3460
3461         /* Since session is dead, search handle closed on server already */
3462         if (rc == -EAGAIN)
3463                 rc = 0;
3464
3465         return rc;
3466 }
3467
3468 int
3469 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3470                 const unsigned char *searchName,
3471                 __u64 * inode_number,
3472                 const struct nls_table *nls_codepage, int remap)
3473 {
3474         int rc = 0;
3475         TRANSACTION2_QPI_REQ *pSMB = NULL;
3476         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3477         int name_len, bytes_returned;
3478         __u16 params, byte_count;
3479
3480         cFYI(1,("In GetSrvInodeNum for %s",searchName));
3481         if(tcon == NULL)
3482                 return -ENODEV; 
3483
3484 GetInodeNumberRetry:
3485         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3486                       (void **) &pSMBr);
3487         if (rc)
3488                 return rc;
3489
3490
3491         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3492                 name_len =
3493                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3494                                 PATH_MAX,nls_codepage, remap);
3495                 name_len++;     /* trailing null */
3496                 name_len *= 2;
3497         } else {                /* BB improve the check for buffer overruns BB */
3498                 name_len = strnlen(searchName, PATH_MAX);
3499                 name_len++;     /* trailing null */
3500                 strncpy(pSMB->FileName, searchName, name_len);
3501         }
3502
3503         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
3504         pSMB->TotalDataCount = 0;
3505         pSMB->MaxParameterCount = cpu_to_le16(2);
3506         /* BB find exact max data count below from sess structure BB */
3507         pSMB->MaxDataCount = cpu_to_le16(4000);
3508         pSMB->MaxSetupCount = 0;
3509         pSMB->Reserved = 0;
3510         pSMB->Flags = 0;
3511         pSMB->Timeout = 0;
3512         pSMB->Reserved2 = 0;
3513         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3514                 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3515         pSMB->DataCount = 0;
3516         pSMB->DataOffset = 0;
3517         pSMB->SetupCount = 1;
3518         pSMB->Reserved3 = 0;
3519         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3520         byte_count = params + 1 /* pad */ ;
3521         pSMB->TotalParameterCount = cpu_to_le16(params);
3522         pSMB->ParameterCount = pSMB->TotalParameterCount;
3523         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3524         pSMB->Reserved4 = 0;
3525         pSMB->hdr.smb_buf_length += byte_count;
3526         pSMB->ByteCount = cpu_to_le16(byte_count);
3527
3528         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3529                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3530         if (rc) {
3531                 cFYI(1, ("error %d in QueryInternalInfo", rc));
3532         } else {
3533                 /* decode response */
3534                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3535                 if (rc || (pSMBr->ByteCount < 2))
3536                 /* BB also check enough total bytes returned */
3537                         /* If rc should we check for EOPNOSUPP and
3538                         disable the srvino flag? or in caller? */
3539                         rc = -EIO;      /* bad smb */
3540                 else {
3541                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3542                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3543                         struct file_internal_info * pfinfo;
3544                         /* BB Do we need a cast or hash here ? */
3545                         if(count < 8) {
3546                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3547                                 rc = -EIO;
3548                                 goto GetInodeNumOut;
3549                         }
3550                         pfinfo = (struct file_internal_info *)
3551                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3552                         *inode_number = pfinfo->UniqueId;
3553                 }
3554         }
3555 GetInodeNumOut:
3556         cifs_buf_release(pSMB);
3557         if (rc == -EAGAIN)
3558                 goto GetInodeNumberRetry;
3559         return rc;
3560 }
3561
3562 int
3563 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3564                 const unsigned char *searchName,
3565                 unsigned char **targetUNCs,
3566                 unsigned int *number_of_UNC_in_array,
3567                 const struct nls_table *nls_codepage, int remap)
3568 {
3569 /* TRANS2_GET_DFS_REFERRAL */
3570         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3571         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3572         struct dfs_referral_level_3 * referrals = NULL;
3573         int rc = 0;
3574         int bytes_returned;
3575         int name_len;
3576         unsigned int i;
3577         char * temp;
3578         __u16 params, byte_count;
3579         *number_of_UNC_in_array = 0;
3580         *targetUNCs = NULL;
3581
3582         cFYI(1, ("In GetDFSRefer the path %s", searchName));
3583         if (ses == NULL)
3584                 return -ENODEV;
3585 getDFSRetry:
3586         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3587                       (void **) &pSMBr);
3588         if (rc)
3589                 return rc;
3590         
3591         /* server pointer checked in called function, 
3592         but should never be null here anyway */
3593         pSMB->hdr.Mid = GetNextMid(ses->server);
3594         pSMB->hdr.Tid = ses->ipc_tid;
3595         pSMB->hdr.Uid = ses->Suid;
3596         if (ses->capabilities & CAP_STATUS32) {
3597                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3598         }
3599         if (ses->capabilities & CAP_DFS) {
3600                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3601         }
3602
3603         if (ses->capabilities & CAP_UNICODE) {
3604                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3605                 name_len =
3606                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3607                                      searchName, PATH_MAX, nls_codepage, remap);
3608                 name_len++;     /* trailing null */
3609                 name_len *= 2;
3610         } else {                /* BB improve the check for buffer overruns BB */
3611                 name_len = strnlen(searchName, PATH_MAX);
3612                 name_len++;     /* trailing null */
3613                 strncpy(pSMB->RequestFileName, searchName, name_len);
3614         }
3615
3616         params = 2 /* level */  + name_len /*includes null */ ;
3617         pSMB->TotalDataCount = 0;
3618         pSMB->DataCount = 0;
3619         pSMB->DataOffset = 0;
3620         pSMB->MaxParameterCount = 0;
3621         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3622         pSMB->MaxSetupCount = 0;
3623         pSMB->Reserved = 0;
3624         pSMB->Flags = 0;
3625         pSMB->Timeout = 0;
3626         pSMB->Reserved2 = 0;
3627         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3628         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3629         pSMB->SetupCount = 1;
3630         pSMB->Reserved3 = 0;
3631         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3632         byte_count = params + 3 /* pad */ ;
3633         pSMB->ParameterCount = cpu_to_le16(params);
3634         pSMB->TotalParameterCount = pSMB->ParameterCount;
3635         pSMB->MaxReferralLevel = cpu_to_le16(3);
3636         pSMB->hdr.smb_buf_length += byte_count;
3637         pSMB->ByteCount = cpu_to_le16(byte_count);
3638
3639         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3640                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3641         if (rc) {
3642                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3643         } else {                /* decode response */
3644 /* BB Add logic to parse referrals here */
3645                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3646
3647                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
3648                         rc = -EIO;      /* bad smb */
3649                 else {
3650                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
3651                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3652
3653                         cFYI(1,
3654                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
3655                               pSMBr->ByteCount, data_offset));
3656                         referrals = 
3657                             (struct dfs_referral_level_3 *) 
3658                                         (8 /* sizeof start of data block */ +
3659                                         data_offset +
3660                                         (char *) &pSMBr->hdr.Protocol); 
3661                         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",
3662                                 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)));
3663                         /* BB This field is actually two bytes in from start of
3664                            data block so we could do safety check that DataBlock
3665                            begins at address of pSMBr->NumberOfReferrals */
3666                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3667
3668                         /* BB Fix below so can return more than one referral */
3669                         if(*number_of_UNC_in_array > 1)
3670                                 *number_of_UNC_in_array = 1;
3671
3672                         /* get the length of the strings describing refs */
3673                         name_len = 0;
3674                         for(i=0;i<*number_of_UNC_in_array;i++) {
3675                                 /* make sure that DfsPathOffset not past end */
3676                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3677                                 if (offset > data_count) {
3678                                         /* if invalid referral, stop here and do 
3679                                         not try to copy any more */
3680                                         *number_of_UNC_in_array = i;
3681                                         break;
3682                                 } 
3683                                 temp = ((char *)referrals) + offset;
3684
3685                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3686                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
3687                                 } else {
3688                                         name_len += strnlen(temp,data_count);
3689                                 }
3690                                 referrals++;
3691                                 /* BB add check that referral pointer does not fall off end PDU */
3692                                 
3693                         }
3694                         /* BB add check for name_len bigger than bcc */
3695                         *targetUNCs = 
3696                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3697                         if(*targetUNCs == NULL) {
3698                                 rc = -ENOMEM;
3699                                 goto GetDFSRefExit;
3700                         }
3701                         /* copy the ref strings */
3702                         referrals =  
3703                             (struct dfs_referral_level_3 *) 
3704                                         (8 /* sizeof data hdr */ +
3705                                         data_offset + 
3706                                         (char *) &pSMBr->hdr.Protocol);
3707
3708                         for(i=0;i<*number_of_UNC_in_array;i++) {
3709                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3710                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3711                                         cifs_strfromUCS_le(*targetUNCs,
3712                                                 (__le16 *) temp, name_len, nls_codepage);
3713                                 } else {
3714                                         strncpy(*targetUNCs,temp,name_len);
3715                                 }
3716                                 /*  BB update target_uncs pointers */
3717                                 referrals++;
3718                         }
3719                         temp = *targetUNCs;
3720                         temp[name_len] = 0;
3721                 }
3722
3723         }
3724 GetDFSRefExit:
3725         if (pSMB)
3726                 cifs_buf_release(pSMB);
3727
3728         if (rc == -EAGAIN)
3729                 goto getDFSRetry;
3730
3731         return rc;
3732 }
3733
3734 /* Query File System Info such as free space to old servers such as Win 9x */
3735 int
3736 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3737 {
3738 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3739         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3740         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3741         FILE_SYSTEM_ALLOC_INFO *response_data;
3742         int rc = 0;
3743         int bytes_returned = 0;
3744         __u16 params, byte_count;
3745
3746         cFYI(1, ("OldQFSInfo"));
3747 oldQFSInfoRetry:
3748         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3749                 (void **) &pSMBr);
3750         if (rc)
3751                 return rc;
3752         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3753                       (void **) &pSMBr);
3754         if (rc)
3755                 return rc;
3756
3757         params = 2;     /* level */
3758         pSMB->TotalDataCount = 0;
3759         pSMB->MaxParameterCount = cpu_to_le16(2);
3760         pSMB->MaxDataCount = cpu_to_le16(1000);
3761         pSMB->MaxSetupCount = 0;
3762         pSMB->Reserved = 0;
3763         pSMB->Flags = 0;
3764         pSMB->Timeout = 0;
3765         pSMB->Reserved2 = 0;
3766         byte_count = params + 1 /* pad */ ;
3767         pSMB->TotalParameterCount = cpu_to_le16(params);
3768         pSMB->ParameterCount = pSMB->TotalParameterCount;
3769         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3770         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3771         pSMB->DataCount = 0;
3772         pSMB->DataOffset = 0;
3773         pSMB->SetupCount = 1;
3774         pSMB->Reserved3 = 0;
3775         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3776         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3777         pSMB->hdr.smb_buf_length += byte_count;
3778         pSMB->ByteCount = cpu_to_le16(byte_count);
3779
3780         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3781                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3782         if (rc) {
3783                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3784         } else {                /* decode response */
3785                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3786
3787                 if (rc || (pSMBr->ByteCount < 18))
3788                         rc = -EIO;      /* bad smb */
3789                 else {
3790                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3791                         cFYI(1,("qfsinf resp BCC: %d  Offset %d",
3792                                  pSMBr->ByteCount, data_offset));
3793
3794                         response_data =
3795                                 (FILE_SYSTEM_ALLOC_INFO *) 
3796                                 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3797                         FSData->f_bsize =
3798                                 le16_to_cpu(response_data->BytesPerSector) *
3799                                 le32_to_cpu(response_data->
3800                                         SectorsPerAllocationUnit);
3801                         FSData->f_blocks =
3802                                 le32_to_cpu(response_data->TotalAllocationUnits);
3803                         FSData->f_bfree = FSData->f_bavail =
3804                                 le32_to_cpu(response_data->FreeAllocationUnits);
3805                         cFYI(1,
3806                              ("Blocks: %lld  Free: %lld Block size %ld",
3807                               (unsigned long long)FSData->f_blocks,
3808                               (unsigned long long)FSData->f_bfree,
3809                               FSData->f_bsize));
3810                 }
3811         }
3812         cifs_buf_release(pSMB);
3813
3814         if (rc == -EAGAIN)
3815                 goto oldQFSInfoRetry;
3816
3817         return rc;
3818 }
3819
3820 int
3821 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3822 {
3823 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3824         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3825         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3826         FILE_SYSTEM_INFO *response_data;
3827         int rc = 0;
3828         int bytes_returned = 0;
3829         __u16 params, byte_count;
3830
3831         cFYI(1, ("In QFSInfo"));
3832 QFSInfoRetry:
3833         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3834                       (void **) &pSMBr);
3835         if (rc)
3836                 return rc;
3837
3838         params = 2;     /* level */
3839         pSMB->TotalDataCount = 0;
3840         pSMB->MaxParameterCount = cpu_to_le16(2);
3841         pSMB->MaxDataCount = cpu_to_le16(1000);
3842         pSMB->MaxSetupCount = 0;
3843         pSMB->Reserved = 0;
3844         pSMB->Flags = 0;
3845         pSMB->Timeout = 0;
3846         pSMB->Reserved2 = 0;
3847         byte_count = params + 1 /* pad */ ;
3848         pSMB->TotalParameterCount = cpu_to_le16(params);
3849         pSMB->ParameterCount = pSMB->TotalParameterCount;
3850         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3851         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3852         pSMB->DataCount = 0;
3853         pSMB->DataOffset = 0;
3854         pSMB->SetupCount = 1;
3855         pSMB->Reserved3 = 0;
3856         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3857         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3858         pSMB->hdr.smb_buf_length += byte_count;
3859         pSMB->ByteCount = cpu_to_le16(byte_count);
3860
3861         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3862                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3863         if (rc) {
3864                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3865         } else {                /* decode response */
3866                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3867
3868                 if (rc || (pSMBr->ByteCount < 24))
3869                         rc = -EIO;      /* bad smb */
3870                 else {
3871                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3872
3873                         response_data =
3874                             (FILE_SYSTEM_INFO
3875                              *) (((char *) &pSMBr->hdr.Protocol) +
3876                                  data_offset);
3877                         FSData->f_bsize =
3878                             le32_to_cpu(response_data->BytesPerSector) *
3879                             le32_to_cpu(response_data->
3880                                         SectorsPerAllocationUnit);
3881                         FSData->f_blocks =
3882                             le64_to_cpu(response_data->TotalAllocationUnits);
3883                         FSData->f_bfree = FSData->f_bavail =
3884                             le64_to_cpu(response_data->FreeAllocationUnits);
3885                         cFYI(1,
3886                              ("Blocks: %lld  Free: %lld Block size %ld",
3887                               (unsigned long long)FSData->f_blocks,
3888                               (unsigned long long)FSData->f_bfree,
3889                               FSData->f_bsize));
3890                 }
3891         }
3892         cifs_buf_release(pSMB);
3893
3894         if (rc == -EAGAIN)
3895                 goto QFSInfoRetry;
3896
3897         return rc;
3898 }
3899
3900 int
3901 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3902 {
3903 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3904         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3905         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3906         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3907         int rc = 0;
3908         int bytes_returned = 0;
3909         __u16 params, byte_count;
3910
3911         cFYI(1, ("In QFSAttributeInfo"));
3912 QFSAttributeRetry:
3913         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3914                       (void **) &pSMBr);
3915         if (rc)
3916                 return rc;
3917
3918         params = 2;     /* level */
3919         pSMB->TotalDataCount = 0;
3920         pSMB->MaxParameterCount = cpu_to_le16(2);
3921         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3922         pSMB->MaxSetupCount = 0;
3923         pSMB->Reserved = 0;
3924         pSMB->Flags = 0;
3925         pSMB->Timeout = 0;
3926         pSMB->Reserved2 = 0;
3927         byte_count = params + 1 /* pad */ ;
3928         pSMB->TotalParameterCount = cpu_to_le16(params);
3929         pSMB->ParameterCount = pSMB->TotalParameterCount;
3930         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3931         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3932         pSMB->DataCount = 0;
3933         pSMB->DataOffset = 0;
3934         pSMB->SetupCount = 1;
3935         pSMB->Reserved3 = 0;
3936         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3937         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3938         pSMB->hdr.smb_buf_length += byte_count;
3939         pSMB->ByteCount = cpu_to_le16(byte_count);
3940
3941         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3942                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3943         if (rc) {
3944                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3945         } else {                /* decode response */
3946                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3947
3948                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3949                         rc = -EIO;      /* bad smb */
3950                 } else {
3951                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3952                         response_data =
3953                             (FILE_SYSTEM_ATTRIBUTE_INFO
3954                              *) (((char *) &pSMBr->hdr.Protocol) +
3955                                  data_offset);
3956                         memcpy(&tcon->fsAttrInfo, response_data,
3957                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3958                 }
3959         }
3960         cifs_buf_release(pSMB);
3961
3962         if (rc == -EAGAIN)
3963                 goto QFSAttributeRetry;
3964
3965         return rc;
3966 }
3967
3968 int
3969 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3970 {
3971 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3972         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3973         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3974         FILE_SYSTEM_DEVICE_INFO *response_data;
3975         int rc = 0;
3976         int bytes_returned = 0;
3977         __u16 params, byte_count;
3978
3979         cFYI(1, ("In QFSDeviceInfo"));
3980 QFSDeviceRetry:
3981         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3982                       (void **) &pSMBr);
3983         if (rc)
3984                 return rc;
3985
3986         params = 2;     /* level */
3987         pSMB->TotalDataCount = 0;
3988         pSMB->MaxParameterCount = cpu_to_le16(2);
3989         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3990         pSMB->MaxSetupCount = 0;
3991         pSMB->Reserved = 0;
3992         pSMB->Flags = 0;
3993         pSMB->Timeout = 0;
3994         pSMB->Reserved2 = 0;
3995         byte_count = params + 1 /* pad */ ;
3996         pSMB->TotalParameterCount = cpu_to_le16(params);
3997         pSMB->ParameterCount = pSMB->TotalParameterCount;
3998         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3999         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4000
4001         pSMB->DataCount = 0;
4002         pSMB->DataOffset = 0;
4003         pSMB->SetupCount = 1;
4004         pSMB->Reserved3 = 0;
4005         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4006         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4007         pSMB->hdr.smb_buf_length += byte_count;
4008         pSMB->ByteCount = cpu_to_le16(byte_count);
4009
4010         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4011                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4012         if (rc) {
4013                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4014         } else {                /* decode response */
4015                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4016
4017                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4018                         rc = -EIO;      /* bad smb */
4019                 else {
4020                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4021                         response_data =
4022                             (FILE_SYSTEM_DEVICE_INFO *)
4023                                 (((char *) &pSMBr->hdr.Protocol) +
4024                                  data_offset);
4025                         memcpy(&tcon->fsDevInfo, response_data,
4026                                sizeof (FILE_SYSTEM_DEVICE_INFO));
4027                 }
4028         }
4029         cifs_buf_release(pSMB);
4030
4031         if (rc == -EAGAIN)
4032                 goto QFSDeviceRetry;
4033
4034         return rc;
4035 }
4036
4037 int
4038 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4039 {
4040 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
4041         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4042         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4043         FILE_SYSTEM_UNIX_INFO *response_data;
4044         int rc = 0;
4045         int bytes_returned = 0;
4046         __u16 params, byte_count;
4047
4048         cFYI(1, ("In QFSUnixInfo"));
4049 QFSUnixRetry:
4050         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4051                       (void **) &pSMBr);
4052         if (rc)
4053                 return rc;
4054
4055         params = 2;     /* level */
4056         pSMB->TotalDataCount = 0;
4057         pSMB->DataCount = 0;
4058         pSMB->DataOffset = 0;
4059         pSMB->MaxParameterCount = cpu_to_le16(2);
4060         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4061         pSMB->MaxSetupCount = 0;
4062         pSMB->Reserved = 0;
4063         pSMB->Flags = 0;
4064         pSMB->Timeout = 0;
4065         pSMB->Reserved2 = 0;
4066         byte_count = params + 1 /* pad */ ;
4067         pSMB->ParameterCount = cpu_to_le16(params);
4068         pSMB->TotalParameterCount = pSMB->ParameterCount;
4069         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
4070         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4071         pSMB->SetupCount = 1;
4072         pSMB->Reserved3 = 0;
4073         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4074         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4075         pSMB->hdr.smb_buf_length += byte_count;
4076         pSMB->ByteCount = cpu_to_le16(byte_count);
4077
4078         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4079                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4080         if (rc) {
4081                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4082         } else {                /* decode response */
4083                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4084
4085                 if (rc || (pSMBr->ByteCount < 13)) {
4086                         rc = -EIO;      /* bad smb */
4087                 } else {
4088                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4089                         response_data =
4090                             (FILE_SYSTEM_UNIX_INFO
4091                              *) (((char *) &pSMBr->hdr.Protocol) +
4092                                  data_offset);
4093                         memcpy(&tcon->fsUnixInfo, response_data,
4094                                sizeof (FILE_SYSTEM_UNIX_INFO));
4095                 }
4096         }
4097         cifs_buf_release(pSMB);
4098
4099         if (rc == -EAGAIN)
4100                 goto QFSUnixRetry;
4101
4102
4103         return rc;
4104 }
4105
4106 int
4107 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4108 {
4109 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
4110         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4111         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4112         int rc = 0;
4113         int bytes_returned = 0;
4114         __u16 params, param_offset, offset, byte_count;
4115
4116         cFYI(1, ("In SETFSUnixInfo"));
4117 SETFSUnixRetry:
4118         /* BB switch to small buf init to save memory */
4119         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4120                       (void **) &pSMBr);
4121         if (rc)
4122                 return rc;
4123
4124         params = 4;     /* 2 bytes zero followed by info level. */
4125         pSMB->MaxSetupCount = 0;
4126         pSMB->Reserved = 0;
4127         pSMB->Flags = 0;
4128         pSMB->Timeout = 0;
4129         pSMB->Reserved2 = 0;
4130         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4131         offset = param_offset + params;
4132
4133         pSMB->MaxParameterCount = cpu_to_le16(4);
4134         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4135         pSMB->SetupCount = 1;
4136         pSMB->Reserved3 = 0;
4137         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4138         byte_count = 1 /* pad */ + params + 12;
4139
4140         pSMB->DataCount = cpu_to_le16(12);
4141         pSMB->ParameterCount = cpu_to_le16(params);
4142         pSMB->TotalDataCount = pSMB->DataCount;
4143         pSMB->TotalParameterCount = pSMB->ParameterCount;
4144         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4145         pSMB->DataOffset = cpu_to_le16(offset);
4146
4147         /* Params. */
4148         pSMB->FileNum = 0;
4149         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4150
4151         /* Data. */
4152         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4153         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4154         pSMB->ClientUnixCap = cpu_to_le64(cap);
4155
4156         pSMB->hdr.smb_buf_length += byte_count;
4157         pSMB->ByteCount = cpu_to_le16(byte_count);
4158
4159         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4160                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4161         if (rc) {
4162                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4163         } else {                /* decode response */
4164                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4165                 if (rc) {
4166                         rc = -EIO;      /* bad smb */
4167                 }
4168         }
4169         cifs_buf_release(pSMB);
4170
4171         if (rc == -EAGAIN)
4172                 goto SETFSUnixRetry;
4173
4174         return rc;
4175 }
4176
4177
4178
4179 int
4180 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4181                    struct kstatfs *FSData)
4182 {
4183 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
4184         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4185         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4186         FILE_SYSTEM_POSIX_INFO *response_data;
4187         int rc = 0;
4188         int bytes_returned = 0;
4189         __u16 params, byte_count;
4190
4191         cFYI(1, ("In QFSPosixInfo"));
4192 QFSPosixRetry:
4193         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4194                       (void **) &pSMBr);
4195         if (rc)
4196                 return rc;
4197
4198         params = 2;     /* level */
4199         pSMB->TotalDataCount = 0;
4200         pSMB->DataCount = 0;
4201         pSMB->DataOffset = 0;
4202         pSMB->MaxParameterCount = cpu_to_le16(2);
4203         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4204         pSMB->MaxSetupCount = 0;
4205         pSMB->Reserved = 0;
4206         pSMB->Flags = 0;
4207         pSMB->Timeout = 0;
4208         pSMB->Reserved2 = 0;
4209         byte_count = params + 1 /* pad */ ;
4210         pSMB->ParameterCount = cpu_to_le16(params);
4211         pSMB->TotalParameterCount = pSMB->ParameterCount;
4212         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
4213         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4214         pSMB->SetupCount = 1;
4215         pSMB->Reserved3 = 0;
4216         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4217         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4218         pSMB->hdr.smb_buf_length += byte_count;
4219         pSMB->ByteCount = cpu_to_le16(byte_count);
4220
4221         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4222                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4223         if (rc) {
4224                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4225         } else {                /* decode response */
4226                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4227
4228                 if (rc || (pSMBr->ByteCount < 13)) {
4229                         rc = -EIO;      /* bad smb */
4230                 } else {
4231                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4232                         response_data =
4233                             (FILE_SYSTEM_POSIX_INFO
4234                              *) (((char *) &pSMBr->hdr.Protocol) +
4235                                  data_offset);
4236                         FSData->f_bsize =
4237                                         le32_to_cpu(response_data->BlockSize);
4238                         FSData->f_blocks =
4239                                         le64_to_cpu(response_data->TotalBlocks);
4240                         FSData->f_bfree =
4241                             le64_to_cpu(response_data->BlocksAvail);
4242                         if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4243                                 FSData->f_bavail = FSData->f_bfree;
4244                         } else {
4245                                 FSData->f_bavail =
4246                                         le64_to_cpu(response_data->UserBlocksAvail);
4247                         }
4248                         if(response_data->TotalFileNodes != cpu_to_le64(-1))
4249                                 FSData->f_files =
4250                                         le64_to_cpu(response_data->TotalFileNodes);
4251                         if(response_data->FreeFileNodes != cpu_to_le64(-1))
4252                                 FSData->f_ffree =
4253                                         le64_to_cpu(response_data->FreeFileNodes);
4254                 }
4255         }
4256         cifs_buf_release(pSMB);
4257
4258         if (rc == -EAGAIN)
4259                 goto QFSPosixRetry;
4260
4261         return rc;
4262 }
4263
4264
4265 /* We can not use write of zero bytes trick to 
4266    set file size due to need for large file support.  Also note that 
4267    this SetPathInfo is preferred to SetFileInfo based method in next 
4268    routine which is only needed to work around a sharing violation bug
4269    in Samba which this routine can run into */
4270
4271 int
4272 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4273               __u64 size, int SetAllocation, 
4274               const struct nls_table *nls_codepage, int remap)
4275 {
4276         struct smb_com_transaction2_spi_req *pSMB = NULL;
4277         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4278         struct file_end_of_file_info *parm_data;
4279         int name_len;
4280         int rc = 0;
4281         int bytes_returned = 0;
4282         __u16 params, byte_count, data_count, param_offset, offset;
4283
4284         cFYI(1, ("In SetEOF"));
4285 SetEOFRetry:
4286         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4287                       (void **) &pSMBr);
4288         if (rc)
4289                 return rc;
4290
4291         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4292                 name_len =
4293                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4294                                      PATH_MAX, nls_codepage, remap);
4295                 name_len++;     /* trailing null */
4296                 name_len *= 2;
4297         } else {        /* BB improve the check for buffer overruns BB */
4298                 name_len = strnlen(fileName, PATH_MAX);
4299                 name_len++;     /* trailing null */
4300                 strncpy(pSMB->FileName, fileName, name_len);
4301         }
4302         params = 6 + name_len;
4303         data_count = sizeof (struct file_end_of_file_info);
4304         pSMB->MaxParameterCount = cpu_to_le16(2);
4305         pSMB->MaxDataCount = cpu_to_le16(4100);
4306         pSMB->MaxSetupCount = 0;
4307         pSMB->Reserved = 0;
4308         pSMB->Flags = 0;
4309         pSMB->Timeout = 0;
4310         pSMB->Reserved2 = 0;
4311         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4312                                      InformationLevel) - 4;
4313         offset = param_offset + params;
4314         if(SetAllocation) {
4315                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4316                     pSMB->InformationLevel =
4317                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4318                 else
4319                     pSMB->InformationLevel =
4320                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4321         } else /* Set File Size */  {    
4322             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4323                     pSMB->InformationLevel =
4324                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4325             else
4326                     pSMB->InformationLevel =
4327                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4328         }
4329
4330         parm_data =
4331             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4332                                        offset);
4333         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4334         pSMB->DataOffset = cpu_to_le16(offset);
4335         pSMB->SetupCount = 1;
4336         pSMB->Reserved3 = 0;
4337         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4338         byte_count = 3 /* pad */  + params + data_count;
4339         pSMB->DataCount = cpu_to_le16(data_count);
4340         pSMB->TotalDataCount = pSMB->DataCount;
4341         pSMB->ParameterCount = cpu_to_le16(params);
4342         pSMB->TotalParameterCount = pSMB->ParameterCount;
4343         pSMB->Reserved4 = 0;
4344         pSMB->hdr.smb_buf_length += byte_count;
4345         parm_data->FileSize = cpu_to_le64(size);
4346         pSMB->ByteCount = cpu_to_le16(byte_count);
4347         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4348                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4349         if (rc) {
4350                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4351         }
4352
4353         cifs_buf_release(pSMB);
4354
4355         if (rc == -EAGAIN)
4356                 goto SetEOFRetry;
4357
4358         return rc;
4359 }
4360
4361 int
4362 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
4363                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
4364 {
4365         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4366         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4367         char *data_offset;
4368         struct file_end_of_file_info *parm_data;
4369         int rc = 0;
4370         int bytes_returned = 0;
4371         __u16 params, param_offset, offset, byte_count, count;
4372
4373         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4374                         (long long)size));
4375         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4376
4377         if (rc)
4378                 return rc;
4379
4380         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4381
4382         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4383         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4384     
4385         params = 6;
4386         pSMB->MaxSetupCount = 0;
4387         pSMB->Reserved = 0;
4388         pSMB->Flags = 0;
4389         pSMB->Timeout = 0;
4390         pSMB->Reserved2 = 0;
4391         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4392         offset = param_offset + params;
4393
4394         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
4395
4396         count = sizeof(struct file_end_of_file_info);
4397         pSMB->MaxParameterCount = cpu_to_le16(2);
4398         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4399         pSMB->SetupCount = 1;
4400         pSMB->Reserved3 = 0;
4401         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4402         byte_count = 3 /* pad */  + params + count;
4403         pSMB->DataCount = cpu_to_le16(count);
4404         pSMB->ParameterCount = cpu_to_le16(params);
4405         pSMB->TotalDataCount = pSMB->DataCount;
4406         pSMB->TotalParameterCount = pSMB->ParameterCount;
4407         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4408         parm_data =
4409                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4410                         offset);
4411         pSMB->DataOffset = cpu_to_le16(offset);
4412         parm_data->FileSize = cpu_to_le64(size);
4413         pSMB->Fid = fid;
4414         if(SetAllocation) {
4415                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4416                         pSMB->InformationLevel =
4417                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4418                 else
4419                         pSMB->InformationLevel =
4420                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4421         } else /* Set File Size */  {    
4422             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4423                     pSMB->InformationLevel =
4424                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4425             else
4426                     pSMB->InformationLevel =
4427                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4428         }
4429         pSMB->Reserved4 = 0;
4430         pSMB->hdr.smb_buf_length += byte_count;
4431         pSMB->ByteCount = cpu_to_le16(byte_count);
4432         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4433                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4434         if (rc) {
4435                 cFYI(1,
4436                      ("Send error in SetFileInfo (SetFileSize) = %d",
4437                       rc));
4438         }
4439
4440         if (pSMB)
4441                 cifs_small_buf_release(pSMB);
4442
4443         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4444                 since file handle passed in no longer valid */
4445
4446         return rc;
4447 }
4448
4449 /* Some legacy servers such as NT4 require that the file times be set on 
4450    an open handle, rather than by pathname - this is awkward due to
4451    potential access conflicts on the open, but it is unavoidable for these
4452    old servers since the only other choice is to go from 100 nanosecond DCE
4453    time and resort to the original setpathinfo level which takes the ancient
4454    DOS time format with 2 second granularity */
4455 int
4456 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
4457                    __u16 fid)
4458 {
4459         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4460         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4461         char *data_offset;
4462         int rc = 0;
4463         int bytes_returned = 0;
4464         __u16 params, param_offset, offset, byte_count, count;
4465
4466         cFYI(1, ("Set Times (via SetFileInfo)"));
4467         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4468
4469         if (rc)
4470                 return rc;
4471
4472         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4473
4474         /* At this point there is no need to override the current pid
4475         with the pid of the opener, but that could change if we someday
4476         use an existing handle (rather than opening one on the fly) */
4477         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4478         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4479     
4480         params = 6;
4481         pSMB->MaxSetupCount = 0;
4482         pSMB->Reserved = 0;
4483         pSMB->Flags = 0;
4484         pSMB->Timeout = 0;
4485         pSMB->Reserved2 = 0;
4486         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4487         offset = param_offset + params;
4488
4489         data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
4490
4491         count = sizeof (FILE_BASIC_INFO);
4492         pSMB->MaxParameterCount = cpu_to_le16(2);
4493         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4494         pSMB->SetupCount = 1;
4495         pSMB->Reserved3 = 0;
4496         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4497         byte_count = 3 /* pad */  + params + count;
4498         pSMB->DataCount = cpu_to_le16(count);
4499         pSMB->ParameterCount = cpu_to_le16(params);
4500         pSMB->TotalDataCount = pSMB->DataCount;
4501         pSMB->TotalParameterCount = pSMB->ParameterCount;
4502         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4503         pSMB->DataOffset = cpu_to_le16(offset);
4504         pSMB->Fid = fid;
4505         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4506                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4507         else
4508                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4509         pSMB->Reserved4 = 0;
4510         pSMB->hdr.smb_buf_length += byte_count;
4511         pSMB->ByteCount = cpu_to_le16(byte_count);
4512         memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4513         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4514                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4515         if (rc) {
4516                 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4517         }
4518
4519         cifs_small_buf_release(pSMB);
4520
4521         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4522                 since file handle passed in no longer valid */
4523
4524         return rc;
4525 }
4526
4527
4528 int
4529 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4530                 const FILE_BASIC_INFO * data, 
4531                 const struct nls_table *nls_codepage, int remap)
4532 {
4533         TRANSACTION2_SPI_REQ *pSMB = NULL;
4534         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4535         int name_len;
4536         int rc = 0;
4537         int bytes_returned = 0;
4538         char *data_offset;
4539         __u16 params, param_offset, offset, byte_count, count;
4540
4541         cFYI(1, ("In SetTimes"));
4542
4543 SetTimesRetry:
4544         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4545                       (void **) &pSMBr);
4546         if (rc)
4547                 return rc;
4548
4549         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4550                 name_len =
4551                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4552                                      PATH_MAX, nls_codepage, remap);
4553                 name_len++;     /* trailing null */
4554                 name_len *= 2;
4555         } else {                /* BB improve the check for buffer overruns BB */
4556                 name_len = strnlen(fileName, PATH_MAX);
4557                 name_len++;     /* trailing null */
4558                 strncpy(pSMB->FileName, fileName, name_len);
4559         }
4560
4561         params = 6 + name_len;
4562         count = sizeof (FILE_BASIC_INFO);
4563         pSMB->MaxParameterCount = cpu_to_le16(2);
4564         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4565         pSMB->MaxSetupCount = 0;
4566         pSMB->Reserved = 0;
4567         pSMB->Flags = 0;
4568         pSMB->Timeout = 0;
4569         pSMB->Reserved2 = 0;
4570         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4571                                      InformationLevel) - 4;
4572         offset = param_offset + params;
4573         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4574         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4575         pSMB->DataOffset = cpu_to_le16(offset);
4576         pSMB->SetupCount = 1;
4577         pSMB->Reserved3 = 0;
4578         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4579         byte_count = 3 /* pad */  + params + count;
4580
4581         pSMB->DataCount = cpu_to_le16(count);
4582         pSMB->ParameterCount = cpu_to_le16(params);
4583         pSMB->TotalDataCount = pSMB->DataCount;
4584         pSMB->TotalParameterCount = pSMB->ParameterCount;
4585         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4586                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4587         else
4588                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4589         pSMB->Reserved4 = 0;
4590         pSMB->hdr.smb_buf_length += byte_count;
4591         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4592         pSMB->ByteCount = cpu_to_le16(byte_count);
4593         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4594                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4595         if (rc) {
4596                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4597         }
4598
4599         cifs_buf_release(pSMB);
4600
4601         if (rc == -EAGAIN)
4602                 goto SetTimesRetry;
4603
4604         return rc;
4605 }
4606
4607 /* Can not be used to set time stamps yet (due to old DOS time format) */
4608 /* Can be used to set attributes */
4609 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
4610           handling it anyway and NT4 was what we thought it would be needed for
4611           Do not delete it until we prove whether needed for Win9x though */
4612 int
4613 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4614                 __u16 dos_attrs, const struct nls_table *nls_codepage)
4615 {
4616         SETATTR_REQ *pSMB = NULL;
4617         SETATTR_RSP *pSMBr = NULL;
4618         int rc = 0;
4619         int bytes_returned;
4620         int name_len;
4621
4622         cFYI(1, ("In SetAttrLegacy"));
4623
4624 SetAttrLgcyRetry:
4625         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4626                       (void **) &pSMBr);
4627         if (rc)
4628                 return rc;
4629
4630         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4631                 name_len =
4632                         ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
4633                                 PATH_MAX, nls_codepage);
4634                 name_len++;     /* trailing null */
4635                 name_len *= 2;
4636         } else {                /* BB improve the check for buffer overruns BB */
4637                 name_len = strnlen(fileName, PATH_MAX);
4638                 name_len++;     /* trailing null */
4639                 strncpy(pSMB->fileName, fileName, name_len);
4640         }
4641         pSMB->attr = cpu_to_le16(dos_attrs);
4642         pSMB->BufferFormat = 0x04;
4643         pSMB->hdr.smb_buf_length += name_len + 1;
4644         pSMB->ByteCount = cpu_to_le16(name_len + 1);
4645         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4646                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4647         if (rc) {
4648                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4649         }
4650
4651         cifs_buf_release(pSMB);
4652
4653         if (rc == -EAGAIN)
4654                 goto SetAttrLgcyRetry;
4655
4656         return rc;
4657 }
4658 #endif /* temporarily unneeded SetAttr legacy function */
4659
4660 int
4661 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4662                     char *fileName, __u64 mode, __u64 uid, __u64 gid, 
4663                     dev_t device, const struct nls_table *nls_codepage, 
4664                     int remap)
4665 {
4666         TRANSACTION2_SPI_REQ *pSMB = NULL;
4667         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4668         int name_len;
4669         int rc = 0;
4670         int bytes_returned = 0;
4671         FILE_UNIX_BASIC_INFO *data_offset;
4672         __u16 params, param_offset, offset, count, byte_count;
4673
4674         cFYI(1, ("In SetUID/GID/Mode"));
4675 setPermsRetry:
4676         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4677                       (void **) &pSMBr);
4678         if (rc)
4679                 return rc;
4680
4681         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4682                 name_len =
4683                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4684                                      PATH_MAX, nls_codepage, remap);
4685                 name_len++;     /* trailing null */
4686                 name_len *= 2;
4687         } else {        /* BB improve the check for buffer overruns BB */
4688                 name_len = strnlen(fileName, PATH_MAX);
4689                 name_len++;     /* trailing null */
4690                 strncpy(pSMB->FileName, fileName, name_len);
4691         }
4692
4693         params = 6 + name_len;
4694         count = sizeof (FILE_UNIX_BASIC_INFO);
4695         pSMB->MaxParameterCount = cpu_to_le16(2);
4696         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4697         pSMB->MaxSetupCount = 0;
4698         pSMB->Reserved = 0;
4699         pSMB->Flags = 0;
4700         pSMB->Timeout = 0;
4701         pSMB->Reserved2 = 0;
4702         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4703                                      InformationLevel) - 4;
4704         offset = param_offset + params;
4705         data_offset =
4706             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4707                                       offset);
4708         memset(data_offset, 0, count);
4709         pSMB->DataOffset = cpu_to_le16(offset);
4710         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4711         pSMB->SetupCount = 1;
4712         pSMB->Reserved3 = 0;
4713         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4714         byte_count = 3 /* pad */  + params + count;
4715         pSMB->ParameterCount = cpu_to_le16(params);
4716         pSMB->DataCount = cpu_to_le16(count);
4717         pSMB->TotalParameterCount = pSMB->ParameterCount;
4718         pSMB->TotalDataCount = pSMB->DataCount;
4719         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4720         pSMB->Reserved4 = 0;
4721         pSMB->hdr.smb_buf_length += byte_count;
4722         data_offset->Uid = cpu_to_le64(uid);
4723         data_offset->Gid = cpu_to_le64(gid);
4724         /* better to leave device as zero when it is  */
4725         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4726         data_offset->DevMinor = cpu_to_le64(MINOR(device));
4727         data_offset->Permissions = cpu_to_le64(mode);
4728     
4729         if(S_ISREG(mode))
4730                 data_offset->Type = cpu_to_le32(UNIX_FILE);
4731         else if(S_ISDIR(mode))
4732                 data_offset->Type = cpu_to_le32(UNIX_DIR);
4733         else if(S_ISLNK(mode))
4734                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4735         else if(S_ISCHR(mode))
4736                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4737         else if(S_ISBLK(mode))
4738                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4739         else if(S_ISFIFO(mode))
4740                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4741         else if(S_ISSOCK(mode))
4742                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4743
4744
4745         pSMB->ByteCount = cpu_to_le16(byte_count);
4746         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4747                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4748         if (rc) {
4749                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4750         }
4751
4752         if (pSMB)
4753                 cifs_buf_release(pSMB);
4754         if (rc == -EAGAIN)
4755                 goto setPermsRetry;
4756         return rc;
4757 }
4758
4759 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
4760                   const int notify_subdirs, const __u16 netfid,
4761                   __u32 filter, struct file * pfile, int multishot, 
4762                   const struct nls_table *nls_codepage)
4763 {
4764         int rc = 0;
4765         struct smb_com_transaction_change_notify_req * pSMB = NULL;
4766         struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4767         struct dir_notify_req *dnotify_req;
4768         int bytes_returned;
4769
4770         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4771         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4772                       (void **) &pSMBr);
4773         if (rc)
4774                 return rc;
4775
4776         pSMB->TotalParameterCount = 0 ;
4777         pSMB->TotalDataCount = 0;
4778         pSMB->MaxParameterCount = cpu_to_le32(2);
4779         /* BB find exact data count max from sess structure BB */
4780         pSMB->MaxDataCount = 0; /* same in little endian or be */
4781 /* BB VERIFY verify which is correct for above BB */
4782         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4783                                              MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4784
4785         pSMB->MaxSetupCount = 4;
4786         pSMB->Reserved = 0;
4787         pSMB->ParameterOffset = 0;
4788         pSMB->DataCount = 0;
4789         pSMB->DataOffset = 0;
4790         pSMB->SetupCount = 4; /* single byte does not need le conversion */
4791         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4792         pSMB->ParameterCount = pSMB->TotalParameterCount;
4793         if(notify_subdirs)
4794                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4795         pSMB->Reserved2 = 0;
4796         pSMB->CompletionFilter = cpu_to_le32(filter);
4797         pSMB->Fid = netfid; /* file handle always le */
4798         pSMB->ByteCount = 0;
4799
4800         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4801                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4802         if (rc) {
4803                 cFYI(1, ("Error in Notify = %d", rc));
4804         } else {
4805                 /* Add file to outstanding requests */
4806                 /* BB change to kmem cache alloc */     
4807                 dnotify_req = (struct dir_notify_req *) kmalloc(
4808                                                 sizeof(struct dir_notify_req),
4809                                                  GFP_KERNEL);
4810                 if(dnotify_req) {
4811                         dnotify_req->Pid = pSMB->hdr.Pid;
4812                         dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4813                         dnotify_req->Mid = pSMB->hdr.Mid;
4814                         dnotify_req->Tid = pSMB->hdr.Tid;
4815                         dnotify_req->Uid = pSMB->hdr.Uid;
4816                         dnotify_req->netfid = netfid;
4817                         dnotify_req->pfile = pfile;
4818                         dnotify_req->filter = filter;
4819                         dnotify_req->multishot = multishot;
4820                         spin_lock(&GlobalMid_Lock);
4821                         list_add_tail(&dnotify_req->lhead, 
4822                                         &GlobalDnotifyReqList);
4823                         spin_unlock(&GlobalMid_Lock);
4824                 } else 
4825                         rc = -ENOMEM;
4826         }
4827         cifs_buf_release(pSMB);
4828         return rc;      
4829 }
4830 #ifdef CONFIG_CIFS_XATTR
4831 ssize_t
4832 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4833                  const unsigned char *searchName,
4834                  char * EAData, size_t buf_size,
4835                  const struct nls_table *nls_codepage, int remap)
4836 {
4837                 /* BB assumes one setup word */
4838         TRANSACTION2_QPI_REQ *pSMB = NULL;
4839         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4840         int rc = 0;
4841         int bytes_returned;
4842         int name_len;
4843         struct fea * temp_fea;
4844         char * temp_ptr;
4845         __u16 params, byte_count;
4846
4847         cFYI(1, ("In Query All EAs path %s", searchName));
4848 QAllEAsRetry:
4849         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4850                       (void **) &pSMBr);
4851         if (rc)
4852                 return rc;
4853
4854         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4855                 name_len =
4856                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4857                                      PATH_MAX, nls_codepage, remap);
4858                 name_len++;     /* trailing null */
4859                 name_len *= 2;
4860         } else {        /* BB improve the check for buffer overruns BB */
4861                 name_len = strnlen(searchName, PATH_MAX);
4862                 name_len++;     /* trailing null */
4863                 strncpy(pSMB->FileName, searchName, name_len);
4864         }
4865
4866         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4867         pSMB->TotalDataCount = 0;
4868         pSMB->MaxParameterCount = cpu_to_le16(2);
4869         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4870         pSMB->MaxSetupCount = 0;
4871         pSMB->Reserved = 0;
4872         pSMB->Flags = 0;
4873         pSMB->Timeout = 0;
4874         pSMB->Reserved2 = 0;
4875         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4876         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4877         pSMB->DataCount = 0;
4878         pSMB->DataOffset = 0;
4879         pSMB->SetupCount = 1;
4880         pSMB->Reserved3 = 0;
4881         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4882         byte_count = params + 1 /* pad */ ;
4883         pSMB->TotalParameterCount = cpu_to_le16(params);
4884         pSMB->ParameterCount = pSMB->TotalParameterCount;
4885         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4886         pSMB->Reserved4 = 0;
4887         pSMB->hdr.smb_buf_length += byte_count;
4888         pSMB->ByteCount = cpu_to_le16(byte_count);
4889
4890         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4891                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4892         if (rc) {
4893                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4894         } else {                /* decode response */
4895                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4896
4897                 /* BB also check enough total bytes returned */
4898                 /* BB we need to improve the validity checking
4899                 of these trans2 responses */
4900                 if (rc || (pSMBr->ByteCount < 4)) 
4901                         rc = -EIO;      /* bad smb */
4902            /* else if (pFindData){
4903                         memcpy((char *) pFindData,
4904                                (char *) &pSMBr->hdr.Protocol +
4905                                data_offset, kl);
4906                 }*/ else {
4907                         /* check that length of list is not more than bcc */
4908                         /* check that each entry does not go beyond length
4909                            of list */
4910                         /* check that each element of each entry does not
4911                            go beyond end of list */
4912                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4913                         struct fealist * ea_response_data;
4914                         rc = 0;
4915                         /* validate_trans2_offsets() */
4916                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4917                         ea_response_data = (struct fealist *)
4918                                 (((char *) &pSMBr->hdr.Protocol) +
4919                                 data_offset);
4920                         name_len = le32_to_cpu(ea_response_data->list_len);
4921                         cFYI(1,("ea length %d", name_len));
4922                         if(name_len <= 8) {
4923                         /* returned EA size zeroed at top of function */
4924                                 cFYI(1,("empty EA list returned from server"));
4925                         } else {
4926                                 /* account for ea list len */
4927                                 name_len -= 4;
4928                                 temp_fea = ea_response_data->list;
4929                                 temp_ptr = (char *)temp_fea;
4930                                 while(name_len > 0) {
4931                                         __u16 value_len;
4932                                         name_len -= 4;
4933                                         temp_ptr += 4;
4934                                         rc += temp_fea->name_len;
4935                                 /* account for prefix user. and trailing null */
4936                                         rc = rc + 5 + 1; 
4937                                         if(rc<(int)buf_size) {
4938                                                 memcpy(EAData,"user.",5);
4939                                                 EAData+=5;
4940                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
4941                                                 EAData+=temp_fea->name_len;
4942                                                 /* null terminate name */
4943                                                 *EAData = 0;
4944                                                 EAData = EAData + 1;
4945                                         } else if(buf_size == 0) {
4946                                                 /* skip copy - calc size only */
4947                                         } else {
4948                                                 /* stop before overrun buffer */
4949                                                 rc = -ERANGE;
4950                                                 break;
4951                                         }
4952                                         name_len -= temp_fea->name_len;
4953                                         temp_ptr += temp_fea->name_len;
4954                                         /* account for trailing null */
4955                                         name_len--;
4956                                         temp_ptr++;
4957                                         value_len = le16_to_cpu(temp_fea->value_len);
4958                                         name_len -= value_len;
4959                                         temp_ptr += value_len;
4960                                         /* BB check that temp_ptr is still within smb BB*/
4961                                 /* no trailing null to account for in value len */
4962                                         /* go on to next EA */
4963                                         temp_fea = (struct fea *)temp_ptr;
4964                                 }
4965                         }
4966                 }
4967         }
4968         if (pSMB)
4969                 cifs_buf_release(pSMB);
4970         if (rc == -EAGAIN)
4971                 goto QAllEAsRetry;
4972
4973         return (ssize_t)rc;
4974 }
4975
4976 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4977                 const unsigned char * searchName,const unsigned char * ea_name,
4978                 unsigned char * ea_value, size_t buf_size, 
4979                 const struct nls_table *nls_codepage, int remap)
4980 {
4981         TRANSACTION2_QPI_REQ *pSMB = NULL;
4982         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4983         int rc = 0;
4984         int bytes_returned;
4985         int name_len;
4986         struct fea * temp_fea;
4987         char * temp_ptr;
4988         __u16 params, byte_count;
4989
4990         cFYI(1, ("In Query EA path %s", searchName));
4991 QEARetry:
4992         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4993                       (void **) &pSMBr);
4994         if (rc)
4995                 return rc;
4996
4997         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4998                 name_len =
4999                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
5000                                      PATH_MAX, nls_codepage, remap);
5001                 name_len++;     /* trailing null */
5002                 name_len *= 2;
5003         } else {        /* BB improve the check for buffer overruns BB */
5004                 name_len = strnlen(searchName, PATH_MAX);
5005                 name_len++;     /* trailing null */
5006                 strncpy(pSMB->FileName, searchName, name_len);
5007         }
5008
5009         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5010         pSMB->TotalDataCount = 0;
5011         pSMB->MaxParameterCount = cpu_to_le16(2);
5012         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5013         pSMB->MaxSetupCount = 0;
5014         pSMB->Reserved = 0;
5015         pSMB->Flags = 0;
5016         pSMB->Timeout = 0;
5017         pSMB->Reserved2 = 0;
5018         pSMB->ParameterOffset = cpu_to_le16(offsetof(
5019         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5020         pSMB->DataCount = 0;
5021         pSMB->DataOffset = 0;
5022         pSMB->SetupCount = 1;
5023         pSMB->Reserved3 = 0;
5024         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5025         byte_count = params + 1 /* pad */ ;
5026         pSMB->TotalParameterCount = cpu_to_le16(params);
5027         pSMB->ParameterCount = pSMB->TotalParameterCount;
5028         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5029         pSMB->Reserved4 = 0;
5030         pSMB->hdr.smb_buf_length += byte_count;
5031         pSMB->ByteCount = cpu_to_le16(byte_count);
5032
5033         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5034                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5035         if (rc) {
5036                 cFYI(1, ("Send error in Query EA = %d", rc));
5037         } else {                /* decode response */
5038                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5039
5040                 /* BB also check enough total bytes returned */
5041                 /* BB we need to improve the validity checking
5042                 of these trans2 responses */
5043                 if (rc || (pSMBr->ByteCount < 4)) 
5044                         rc = -EIO;      /* bad smb */
5045            /* else if (pFindData){
5046                         memcpy((char *) pFindData,
5047                                (char *) &pSMBr->hdr.Protocol +
5048                                data_offset, kl);
5049                 }*/ else {
5050                         /* check that length of list is not more than bcc */
5051                         /* check that each entry does not go beyond length
5052                            of list */
5053                         /* check that each element of each entry does not
5054                            go beyond end of list */
5055                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5056                         struct fealist * ea_response_data;
5057                         rc = -ENODATA;
5058                         /* validate_trans2_offsets() */
5059                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5060                         ea_response_data = (struct fealist *)
5061                                 (((char *) &pSMBr->hdr.Protocol) +
5062                                 data_offset);
5063                         name_len = le32_to_cpu(ea_response_data->list_len);
5064                         cFYI(1,("ea length %d", name_len));
5065                         if(name_len <= 8) {
5066                         /* returned EA size zeroed at top of function */
5067                                 cFYI(1,("empty EA list returned from server"));
5068                         } else {
5069                                 /* account for ea list len */
5070                                 name_len -= 4;
5071                                 temp_fea = ea_response_data->list;
5072                                 temp_ptr = (char *)temp_fea;
5073                                 /* loop through checking if we have a matching
5074                                 name and then return the associated value */
5075                                 while(name_len > 0) {
5076                                         __u16 value_len;
5077                                         name_len -= 4;
5078                                         temp_ptr += 4;
5079                                         value_len = le16_to_cpu(temp_fea->value_len);
5080                                 /* BB validate that value_len falls within SMB, 
5081                                 even though maximum for name_len is 255 */ 
5082                                         if(memcmp(temp_fea->name,ea_name,
5083                                                   temp_fea->name_len) == 0) {
5084                                                 /* found a match */
5085                                                 rc = value_len;
5086                                 /* account for prefix user. and trailing null */
5087                                                 if(rc<=(int)buf_size) {
5088                                                         memcpy(ea_value,
5089                                                                 temp_fea->name+temp_fea->name_len+1,
5090                                                                 rc);
5091                                                         /* ea values, unlike ea names,
5092                                                         are not null terminated */
5093                                                 } else if(buf_size == 0) {
5094                                                 /* skip copy - calc size only */
5095                                                 } else {
5096                                                         /* stop before overrun buffer */
5097                                                         rc = -ERANGE;
5098                                                 }
5099                                                 break;
5100                                         }
5101                                         name_len -= temp_fea->name_len;
5102                                         temp_ptr += temp_fea->name_len;
5103                                         /* account for trailing null */
5104                                         name_len--;
5105                                         temp_ptr++;
5106                                         name_len -= value_len;
5107                                         temp_ptr += value_len;
5108                                 /* no trailing null to account for in value len */
5109                                         /* go on to next EA */
5110                                         temp_fea = (struct fea *)temp_ptr;
5111                                 }
5112                         } 
5113                 }
5114         }
5115         if (pSMB)
5116                 cifs_buf_release(pSMB);
5117         if (rc == -EAGAIN)
5118                 goto QEARetry;
5119
5120         return (ssize_t)rc;
5121 }
5122
5123 int
5124 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5125                 const char * ea_name, const void * ea_value, 
5126                 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5127                 int remap)
5128 {
5129         struct smb_com_transaction2_spi_req *pSMB = NULL;
5130         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5131         struct fealist *parm_data;
5132         int name_len;
5133         int rc = 0;
5134         int bytes_returned = 0;
5135         __u16 params, param_offset, byte_count, offset, count;
5136
5137         cFYI(1, ("In SetEA"));
5138 SetEARetry:
5139         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5140                       (void **) &pSMBr);
5141         if (rc)
5142                 return rc;
5143
5144         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5145                 name_len =
5146                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
5147                                      PATH_MAX, nls_codepage, remap);
5148                 name_len++;     /* trailing null */
5149                 name_len *= 2;
5150         } else {                /* BB improve the check for buffer overruns BB */
5151                 name_len = strnlen(fileName, PATH_MAX);
5152                 name_len++;     /* trailing null */
5153                 strncpy(pSMB->FileName, fileName, name_len);
5154         }
5155
5156         params = 6 + name_len;
5157
5158         /* done calculating parms using name_len of file name,
5159         now use name_len to calculate length of ea name
5160         we are going to create in the inode xattrs */
5161         if(ea_name == NULL)
5162                 name_len = 0;
5163         else
5164                 name_len = strnlen(ea_name,255);
5165
5166         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5167         pSMB->MaxParameterCount = cpu_to_le16(2);
5168         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5169         pSMB->MaxSetupCount = 0;
5170         pSMB->Reserved = 0;
5171         pSMB->Flags = 0;
5172         pSMB->Timeout = 0;
5173         pSMB->Reserved2 = 0;
5174         param_offset = offsetof(struct smb_com_transaction2_spi_req,
5175                                      InformationLevel) - 4;
5176         offset = param_offset + params;
5177         pSMB->InformationLevel =
5178                 cpu_to_le16(SMB_SET_FILE_EA);
5179
5180         parm_data =
5181                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5182                                        offset);
5183         pSMB->ParameterOffset = cpu_to_le16(param_offset);
5184         pSMB->DataOffset = cpu_to_le16(offset);
5185         pSMB->SetupCount = 1;
5186         pSMB->Reserved3 = 0;
5187         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5188         byte_count = 3 /* pad */  + params + count;
5189         pSMB->DataCount = cpu_to_le16(count);
5190         parm_data->list_len = cpu_to_le32(count);
5191         parm_data->list[0].EA_flags = 0;
5192         /* we checked above that name len is less than 255 */
5193         parm_data->list[0].name_len = (__u8)name_len;
5194         /* EA names are always ASCII */
5195         if(ea_name)
5196                 strncpy(parm_data->list[0].name,ea_name,name_len);
5197         parm_data->list[0].name[name_len] = 0;
5198         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5199         /* caller ensures that ea_value_len is less than 64K but
5200         we need to ensure that it fits within the smb */
5201
5202         /*BB add length check that it would fit in negotiated SMB buffer size BB */
5203         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5204         if(ea_value_len)
5205                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5206
5207         pSMB->TotalDataCount = pSMB->DataCount;
5208         pSMB->ParameterCount = cpu_to_le16(params);
5209         pSMB->TotalParameterCount = pSMB->ParameterCount;
5210         pSMB->Reserved4 = 0;
5211         pSMB->hdr.smb_buf_length += byte_count;
5212         pSMB->ByteCount = cpu_to_le16(byte_count);
5213         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5214                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5215         if (rc) {
5216                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5217         }
5218
5219         cifs_buf_release(pSMB);
5220
5221         if (rc == -EAGAIN)
5222                 goto SetEARetry;
5223
5224         return rc;
5225 }
5226
5227 #endif