]> err.no Git - linux-2.6/blob - fs/cifs/cifssmb.c
[CIFS] Remove static and unused symbols
[linux-2.6] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2006
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   Contains the routines for constructing the SMB PDUs themselves
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
25  /* These are mostly routines that operate on a pathname, or on a tree id     */
26  /* (mounted volume), but there are eight handle based routines which must be */
27  /* treated slightly different for reconnection purposes since we never want  */
28  /* to reuse a stale file handle and the caller knows the file handle */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsproto.h"
38 #include "cifs_unicode.h"
39 #include "cifs_debug.h"
40 #include "cifsacl.h"
41
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44         int index;
45         char *name;
46 } protocols[] = {
47 #ifdef CONFIG_CIFS_WEAK_PW_HASH
48         {LANMAN_PROT, "\2LM1.2X002"},
49 #endif /* weak password hashing for legacy clients */
50         {CIFS_PROT, "\2NT LM 0.12"}, 
51         {POSIX_PROT, "\2POSIX 2"},
52         {BAD_PROT, "\2"}
53 };
54 #else
55 static struct {
56         int index;
57         char *name;
58 } protocols[] = {
59 #ifdef CONFIG_CIFS_WEAK_PW_HASH
60         {LANMAN_PROT, "\2LM1.2X002"},
61 #endif /* weak password hashing for legacy clients */
62         {CIFS_PROT, "\2NT LM 0.12"}, 
63         {BAD_PROT, "\2"}
64 };
65 #endif
66
67 /* define the number of elements in the cifs dialect array */
68 #ifdef CONFIG_CIFS_POSIX
69 #ifdef CONFIG_CIFS_WEAK_PW_HASH
70 #define CIFS_NUM_PROT 3
71 #else
72 #define CIFS_NUM_PROT 2
73 #endif /* CIFS_WEAK_PW_HASH */
74 #else /* not posix */
75 #ifdef CONFIG_CIFS_WEAK_PW_HASH
76 #define CIFS_NUM_PROT 2
77 #else
78 #define CIFS_NUM_PROT 1
79 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
80 #endif /* CIFS_POSIX */
81
82
83 /* Mark as invalid, all open files on tree connections since they
84    were closed when session to server was lost */
85 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
86 {
87         struct cifsFileInfo *open_file = NULL;
88         struct list_head * tmp;
89         struct list_head * tmp1;
90
91 /* list all files open on tree connection and mark them invalid */
92         write_lock(&GlobalSMBSeslock);
93         list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
94                 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
95                 if(open_file) {
96                         open_file->invalidHandle = TRUE;
97                 }
98         }
99         write_unlock(&GlobalSMBSeslock);
100         /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
101            to this tcon */
102 }
103
104 /* If the return code is zero, this function must fill in request_buf pointer */
105 static int
106 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
107          void **request_buf /* returned */)
108 {
109         int rc = 0;
110
111         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
112            check for tcp and smb session status done differently
113            for those three - in the calling routine */
114         if(tcon) {
115                 if(tcon->tidStatus == CifsExiting) {
116                         /* only tree disconnect, open, and write,
117                         (and ulogoff which does not have tcon)
118                         are allowed as we start force umount */
119                         if((smb_command != SMB_COM_WRITE_ANDX) && 
120                            (smb_command != SMB_COM_OPEN_ANDX) && 
121                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
122                                 cFYI(1,("can not send cmd %d while umounting",
123                                         smb_command));
124                                 return -ENODEV;
125                         }
126                 }
127                 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
128                                   (tcon->ses->server)){
129                         struct nls_table *nls_codepage;
130                                 /* Give Demultiplex thread up to 10 seconds to 
131                                    reconnect, should be greater than cifs socket
132                                    timeout which is 7 seconds */
133                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
134                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
135                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
136                                 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
137                                         /* on "soft" mounts we wait once */
138                                         if((tcon->retry == FALSE) || 
139                                            (tcon->ses->status == CifsExiting)) {
140                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
141                                                 return -EHOSTDOWN;
142                                         } /* else "hard" mount - keep retrying
143                                              until process is killed or server
144                                              comes back on-line */
145                                 } else /* TCP session is reestablished now */
146                                         break;
147                                  
148                         }
149                         
150                         nls_codepage = load_nls_default();
151                 /* need to prevent multiple threads trying to
152                 simultaneously reconnect the same SMB session */
153                         down(&tcon->ses->sesSem);
154                         if(tcon->ses->status == CifsNeedReconnect)
155                                 rc = cifs_setup_session(0, tcon->ses, 
156                                                         nls_codepage);
157                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
158                                 mark_open_files_invalid(tcon);
159                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
160                                         , nls_codepage);
161                                 up(&tcon->ses->sesSem);
162                                 /* BB FIXME add code to check if wsize needs
163                                    update due to negotiated smb buffer size
164                                    shrinking */
165                                 if(rc == 0)
166                                         atomic_inc(&tconInfoReconnectCount);
167
168                                 cFYI(1, ("reconnect tcon rc = %d", rc));
169                                 /* Removed call to reopen open files here - 
170                                    it is safer (and faster) to reopen files
171                                    one at a time as needed in read and write */
172
173                                 /* Check if handle based operation so we 
174                                    know whether we can continue or not without
175                                    returning to caller to reset file handle */
176                                 switch(smb_command) {
177                                         case SMB_COM_READ_ANDX:
178                                         case SMB_COM_WRITE_ANDX:
179                                         case SMB_COM_CLOSE:
180                                         case SMB_COM_FIND_CLOSE2:
181                                         case SMB_COM_LOCKING_ANDX: {
182                                                 unload_nls(nls_codepage);
183                                                 return -EAGAIN;
184                                         }
185                                 }
186                         } else {
187                                 up(&tcon->ses->sesSem);
188                         }
189                         unload_nls(nls_codepage);
190
191                 } else {
192                         return -EIO;
193                 }
194         }
195         if(rc)
196                 return rc;
197
198         *request_buf = cifs_small_buf_get();
199         if (*request_buf == NULL) {
200                 /* BB should we add a retry in here if not a writepage? */
201                 return -ENOMEM;
202         }
203
204         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
205
206         if(tcon != NULL)
207                 cifs_stats_inc(&tcon->num_smbs_sent);
208
209         return rc;
210 }
211
212 int
213 small_smb_init_no_tc(const int smb_command, const int wct, 
214                      struct cifsSesInfo *ses, void **request_buf)
215 {
216         int rc;
217         struct smb_hdr * buffer;
218
219         rc = small_smb_init(smb_command, wct, NULL, request_buf);
220         if(rc)
221                 return rc;
222
223         buffer = (struct smb_hdr *)*request_buf;
224         buffer->Mid = GetNextMid(ses->server);
225         if (ses->capabilities & CAP_UNICODE)
226                 buffer->Flags2 |= SMBFLG2_UNICODE;
227         if (ses->capabilities & CAP_STATUS32)
228                 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
229
230         /* uid, tid can stay at zero as set in header assemble */
231
232         /* BB add support for turning on the signing when 
233         this function is used after 1st of session setup requests */
234
235         return rc;
236 }
237
238 /* If the return code is zero, this function must fill in request_buf pointer */
239 static int
240 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
241          void **request_buf /* returned */ ,
242          void **response_buf /* returned */ )
243 {
244         int rc = 0;
245
246         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
247            check for tcp and smb session status done differently
248            for those three - in the calling routine */
249         if(tcon) {
250                 if(tcon->tidStatus == CifsExiting) {
251                         /* only tree disconnect, open, and write,
252                           (and ulogoff which does not have tcon)
253                           are allowed as we start force umount */
254                         if((smb_command != SMB_COM_WRITE_ANDX) &&
255                            (smb_command != SMB_COM_OPEN_ANDX) &&
256                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
257                                 cFYI(1,("can not send cmd %d while umounting",
258                                         smb_command));
259                                 return -ENODEV;
260                         }
261                 }
262
263                 if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
264                                   (tcon->ses->server)){
265                         struct nls_table *nls_codepage;
266                                 /* Give Demultiplex thread up to 10 seconds to
267                                    reconnect, should be greater than cifs socket
268                                    timeout which is 7 seconds */
269                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
270                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
271                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
272                                 if(tcon->ses->server->tcpStatus == 
273                                                 CifsNeedReconnect) {
274                                         /* on "soft" mounts we wait once */
275                                         if((tcon->retry == FALSE) || 
276                                            (tcon->ses->status == CifsExiting)) {
277                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
278                                                 return -EHOSTDOWN;
279                                         } /* else "hard" mount - keep retrying
280                                              until process is killed or server
281                                              comes on-line */
282                                 } else /* TCP session is reestablished now */
283                                         break;
284                                  
285                         }
286                         
287                         nls_codepage = load_nls_default();
288                 /* need to prevent multiple threads trying to
289                 simultaneously reconnect the same SMB session */
290                         down(&tcon->ses->sesSem);
291                         if(tcon->ses->status == CifsNeedReconnect)
292                                 rc = cifs_setup_session(0, tcon->ses, 
293                                                         nls_codepage);
294                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
295                                 mark_open_files_invalid(tcon);
296                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
297                                               tcon, nls_codepage);
298                                 up(&tcon->ses->sesSem);
299                                 /* BB FIXME add code to check if wsize needs
300                                 update due to negotiated smb buffer size
301                                 shrinking */
302                                 if(rc == 0)
303                                         atomic_inc(&tconInfoReconnectCount);
304
305                                 cFYI(1, ("reconnect tcon rc = %d", rc));
306                                 /* Removed call to reopen open files here - 
307                                    it is safer (and faster) to reopen files
308                                    one at a time as needed in read and write */
309
310                                 /* Check if handle based operation so we 
311                                    know whether we can continue or not without
312                                    returning to caller to reset file handle */
313                                 switch(smb_command) {
314                                         case SMB_COM_READ_ANDX:
315                                         case SMB_COM_WRITE_ANDX:
316                                         case SMB_COM_CLOSE:
317                                         case SMB_COM_FIND_CLOSE2:
318                                         case SMB_COM_LOCKING_ANDX: {
319                                                 unload_nls(nls_codepage);
320                                                 return -EAGAIN;
321                                         }
322                                 }
323                         } else {
324                                 up(&tcon->ses->sesSem);
325                         }
326                         unload_nls(nls_codepage);
327
328                 } else {
329                         return -EIO;
330                 }
331         }
332         if(rc)
333                 return rc;
334
335         *request_buf = cifs_buf_get();
336         if (*request_buf == NULL) {
337                 /* BB should we add a retry in here if not a writepage? */
338                 return -ENOMEM;
339         }
340     /* Although the original thought was we needed the response buf for  */
341     /* potential retries of smb operations it turns out we can determine */
342     /* from the mid flags when the request buffer can be resent without  */
343     /* having to use a second distinct buffer for the response */
344         if(response_buf)
345                 *response_buf = *request_buf; 
346
347         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
348                         wct /*wct */ );
349
350         if(tcon != NULL)
351                 cifs_stats_inc(&tcon->num_smbs_sent);
352
353         return rc;
354 }
355
356 static int validate_t2(struct smb_t2_rsp * pSMB) 
357 {
358         int rc = -EINVAL;
359         int total_size;
360         char * pBCC;
361
362         /* check for plausible wct, bcc and t2 data and parm sizes */
363         /* check for parm and data offset going beyond end of smb */
364         if(pSMB->hdr.WordCount >= 10) {
365                 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
366                    (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
367                         /* check that bcc is at least as big as parms + data */
368                         /* check that bcc is less than negotiated smb buffer */
369                         total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
370                         if(total_size < 512) {
371                                 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
372                                 /* BCC le converted in SendReceive */
373                                 pBCC = (pSMB->hdr.WordCount * 2) + 
374                                         sizeof(struct smb_hdr) +
375                                         (char *)pSMB;
376                                 if((total_size <= (*(u16 *)pBCC)) && 
377                                    (total_size < 
378                                         CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
379                                         return 0;
380                                 }
381                                 
382                         }
383                 }
384         }
385         cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
386                 sizeof(struct smb_t2_rsp) + 16);
387         return rc;
388 }
389 int
390 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
391 {
392         NEGOTIATE_REQ *pSMB;
393         NEGOTIATE_RSP *pSMBr;
394         int rc = 0;
395         int bytes_returned;
396         int i;
397         struct TCP_Server_Info * server;
398         u16 count;
399         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 static struct cifs_sid sid_everyone = 
2777                 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2778 /* group users */
2779 const static struct cifs_sid sid_user = 
2780                 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2781
2782 /* Convert CIFS ACL to POSIX form */
2783 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2784 {
2785         return 0;
2786 }
2787
2788 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2789 int
2790 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2791          /*  BB fix up return info */ char *acl_inf, const int buflen, 
2792                   const int acl_type /* ACCESS/DEFAULT not sure implication */)
2793 {
2794         int rc = 0;
2795         int buf_type = 0;
2796         QUERY_SEC_DESC_REQ * pSMB;
2797         struct kvec iov[1];
2798
2799         cFYI(1, ("GetCifsACL"));
2800
2801         rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 
2802                         8 /* parm len */, tcon, (void **) &pSMB);
2803         if (rc)
2804                 return rc;
2805
2806         pSMB->MaxParameterCount = cpu_to_le32(4);
2807         /* BB TEST with big acls that might need to be e.g. larger than 16K */
2808         pSMB->MaxSetupCount = 0;
2809         pSMB->Fid = fid; /* file handle always le */
2810         pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2811                                      CIFS_ACL_DACL);
2812         pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2813         pSMB->hdr.smb_buf_length += 11;
2814         iov[0].iov_base = (char *)pSMB;
2815         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2816
2817         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2818         cifs_stats_inc(&tcon->num_acl_get);
2819         if (rc) {
2820                 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2821         } else {                /* decode response */
2822                 struct cifs_sid * psec_desc;
2823                 __le32 * parm;
2824                 int parm_len;
2825                 int data_len;
2826                 int acl_len;
2827                 struct smb_com_ntransact_rsp * pSMBr;
2828
2829 /* validate_nttransact */
2830                 rc = validate_ntransact(iov[0].iov_base, (char **)&parm, 
2831                                         (char **)&psec_desc,
2832                                         &parm_len, &data_len);
2833                 
2834                 if(rc)
2835                         goto qsec_out;
2836                 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2837
2838                 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc));  /* BB removeme BB */
2839
2840                 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2841                         rc = -EIO;      /* bad smb */
2842                         goto qsec_out;
2843                 }
2844
2845 /* BB check that data area is minimum length and as big as acl_len */
2846
2847                 acl_len = le32_to_cpu(*(__le32 *)parm);
2848                 /* BB check if(acl_len > bufsize) */
2849
2850                 parse_sec_desc(psec_desc, acl_len);
2851         }
2852 qsec_out:
2853         if(buf_type == CIFS_SMALL_BUFFER)
2854                 cifs_small_buf_release(iov[0].iov_base);
2855         else if(buf_type == CIFS_LARGE_BUFFER)
2856                 cifs_buf_release(iov[0].iov_base);
2857 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2858         return rc;
2859 }
2860
2861 /* Legacy Query Path Information call for lookup to old servers such
2862    as Win9x/WinME */
2863 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2864                  const unsigned char *searchName,
2865                  FILE_ALL_INFO * pFinfo,
2866                  const struct nls_table *nls_codepage, int remap)
2867 {
2868         QUERY_INFORMATION_REQ * pSMB;
2869         QUERY_INFORMATION_RSP * pSMBr;
2870         int rc = 0;
2871         int bytes_returned;
2872         int name_len;
2873
2874         cFYI(1, ("In SMBQPath path %s", searchName)); 
2875 QInfRetry:
2876         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2877                       (void **) &pSMBr);
2878         if (rc)
2879                 return rc;
2880
2881         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2882                 name_len =
2883                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2884                                      PATH_MAX, nls_codepage, remap);
2885                 name_len++;     /* trailing null */
2886                 name_len *= 2;
2887         } else {               
2888                 name_len = strnlen(searchName, PATH_MAX);
2889                 name_len++;     /* trailing null */
2890                 strncpy(pSMB->FileName, searchName, name_len);
2891         }
2892         pSMB->BufferFormat = 0x04;
2893         name_len++; /* account for buffer type byte */  
2894         pSMB->hdr.smb_buf_length += (__u16) name_len;
2895         pSMB->ByteCount = cpu_to_le16(name_len);
2896
2897         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2898                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2899         if (rc) {
2900                 cFYI(1, ("Send error in QueryInfo = %d", rc));
2901         } else if (pFinfo) {            /* decode response */
2902                 struct timespec ts;
2903                 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2904                 /* BB FIXME - add time zone adjustment BB */
2905                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2906                 ts.tv_nsec = 0;
2907                 ts.tv_sec = time;
2908                 /* decode time fields */
2909                 pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
2910                 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2911                 pFinfo->LastAccessTime = 0;
2912                 pFinfo->AllocationSize =
2913                         cpu_to_le64(le32_to_cpu(pSMBr->size));
2914                 pFinfo->EndOfFile = pFinfo->AllocationSize;
2915                 pFinfo->Attributes =
2916                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
2917         } else
2918                 rc = -EIO; /* bad buffer passed in */
2919
2920         cifs_buf_release(pSMB);
2921
2922         if (rc == -EAGAIN)
2923                 goto QInfRetry;
2924
2925         return rc;
2926 }
2927
2928
2929
2930
2931 int
2932 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2933                  const unsigned char *searchName,
2934                  FILE_ALL_INFO * pFindData,
2935                  const struct nls_table *nls_codepage, int remap)
2936 {
2937 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2938         TRANSACTION2_QPI_REQ *pSMB = NULL;
2939         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2940         int rc = 0;
2941         int bytes_returned;
2942         int name_len;
2943         __u16 params, byte_count;
2944
2945 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2946 QPathInfoRetry:
2947         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2948                       (void **) &pSMBr);
2949         if (rc)
2950                 return rc;
2951
2952         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2953                 name_len =
2954                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2955                                      PATH_MAX, nls_codepage, remap);
2956                 name_len++;     /* trailing null */
2957                 name_len *= 2;
2958         } else {                /* BB improve the check for buffer overruns BB */
2959                 name_len = strnlen(searchName, PATH_MAX);
2960                 name_len++;     /* trailing null */
2961                 strncpy(pSMB->FileName, searchName, name_len);
2962         }
2963
2964         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2965         pSMB->TotalDataCount = 0;
2966         pSMB->MaxParameterCount = cpu_to_le16(2);
2967         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2968         pSMB->MaxSetupCount = 0;
2969         pSMB->Reserved = 0;
2970         pSMB->Flags = 0;
2971         pSMB->Timeout = 0;
2972         pSMB->Reserved2 = 0;
2973         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2974         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2975         pSMB->DataCount = 0;
2976         pSMB->DataOffset = 0;
2977         pSMB->SetupCount = 1;
2978         pSMB->Reserved3 = 0;
2979         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2980         byte_count = params + 1 /* pad */ ;
2981         pSMB->TotalParameterCount = cpu_to_le16(params);
2982         pSMB->ParameterCount = pSMB->TotalParameterCount;
2983         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2984         pSMB->Reserved4 = 0;
2985         pSMB->hdr.smb_buf_length += byte_count;
2986         pSMB->ByteCount = cpu_to_le16(byte_count);
2987
2988         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2989                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2990         if (rc) {
2991                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2992         } else {                /* decode response */
2993                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2994
2995                 if (rc || (pSMBr->ByteCount < 40)) 
2996                         rc = -EIO;      /* bad smb */
2997                 else if (pFindData){
2998                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2999                         memcpy((char *) pFindData,
3000                                (char *) &pSMBr->hdr.Protocol +
3001                                data_offset, sizeof (FILE_ALL_INFO));
3002                 } else
3003                     rc = -ENOMEM;
3004         }
3005         cifs_buf_release(pSMB);
3006         if (rc == -EAGAIN)
3007                 goto QPathInfoRetry;
3008
3009         return rc;
3010 }
3011
3012 int
3013 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3014                      const unsigned char *searchName,
3015                      FILE_UNIX_BASIC_INFO * pFindData,
3016                      const struct nls_table *nls_codepage, int remap)
3017 {
3018 /* SMB_QUERY_FILE_UNIX_BASIC */
3019         TRANSACTION2_QPI_REQ *pSMB = NULL;
3020         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3021         int rc = 0;
3022         int bytes_returned = 0;
3023         int name_len;
3024         __u16 params, byte_count;
3025
3026         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3027 UnixQPathInfoRetry:
3028         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3029                       (void **) &pSMBr);
3030         if (rc)
3031                 return rc;
3032
3033         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3034                 name_len =
3035                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3036                                   PATH_MAX, nls_codepage, remap);
3037                 name_len++;     /* trailing null */
3038                 name_len *= 2;
3039         } else {                /* BB improve the check for buffer overruns BB */
3040                 name_len = strnlen(searchName, PATH_MAX);
3041                 name_len++;     /* trailing null */
3042                 strncpy(pSMB->FileName, searchName, name_len);
3043         }
3044
3045         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3046         pSMB->TotalDataCount = 0;
3047         pSMB->MaxParameterCount = cpu_to_le16(2);
3048         /* BB find exact max SMB PDU from sess structure BB */
3049         pSMB->MaxDataCount = cpu_to_le16(4000); 
3050         pSMB->MaxSetupCount = 0;
3051         pSMB->Reserved = 0;
3052         pSMB->Flags = 0;
3053         pSMB->Timeout = 0;
3054         pSMB->Reserved2 = 0;
3055         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3056         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3057         pSMB->DataCount = 0;
3058         pSMB->DataOffset = 0;
3059         pSMB->SetupCount = 1;
3060         pSMB->Reserved3 = 0;
3061         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3062         byte_count = params + 1 /* pad */ ;
3063         pSMB->TotalParameterCount = cpu_to_le16(params);
3064         pSMB->ParameterCount = pSMB->TotalParameterCount;
3065         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3066         pSMB->Reserved4 = 0;
3067         pSMB->hdr.smb_buf_length += byte_count;
3068         pSMB->ByteCount = cpu_to_le16(byte_count);
3069
3070         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3071                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3072         if (rc) {
3073                 cFYI(1, ("Send error in QPathInfo = %d", rc));
3074         } else {                /* decode response */
3075                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3076
3077                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3078                         rc = -EIO;      /* bad smb */
3079                 } else {
3080                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3081                         memcpy((char *) pFindData,
3082                                (char *) &pSMBr->hdr.Protocol +
3083                                data_offset,
3084                                sizeof (FILE_UNIX_BASIC_INFO));
3085                 }
3086         }
3087         cifs_buf_release(pSMB);
3088         if (rc == -EAGAIN)
3089                 goto UnixQPathInfoRetry;
3090
3091         return rc;
3092 }
3093
3094 #if 0  /* function unused at present */
3095 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3096                const char *searchName, FILE_ALL_INFO * findData,
3097                const struct nls_table *nls_codepage)
3098 {
3099 /* level 257 SMB_ */
3100         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3101         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3102         int rc = 0;
3103         int bytes_returned;
3104         int name_len;
3105         __u16 params, byte_count;
3106
3107         cFYI(1, ("In FindUnique"));
3108 findUniqueRetry:
3109         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3110                       (void **) &pSMBr);
3111         if (rc)
3112                 return rc;
3113
3114         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3115                 name_len =
3116                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
3117                                   /* find define for this maxpathcomponent */
3118                                   , nls_codepage);
3119                 name_len++;     /* trailing null */
3120                 name_len *= 2;
3121         } else {                /* BB improve the check for buffer overruns BB */
3122                 name_len = strnlen(searchName, PATH_MAX);
3123                 name_len++;     /* trailing null */
3124                 strncpy(pSMB->FileName, searchName, name_len);
3125         }
3126
3127         params = 12 + name_len /* includes null */ ;
3128         pSMB->TotalDataCount = 0;       /* no EAs */
3129         pSMB->MaxParameterCount = cpu_to_le16(2);
3130         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3131         pSMB->MaxSetupCount = 0;
3132         pSMB->Reserved = 0;
3133         pSMB->Flags = 0;
3134         pSMB->Timeout = 0;
3135         pSMB->Reserved2 = 0;
3136         pSMB->ParameterOffset = cpu_to_le16(
3137          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3138         pSMB->DataCount = 0;
3139         pSMB->DataOffset = 0;
3140         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
3141         pSMB->Reserved3 = 0;
3142         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3143         byte_count = params + 1 /* pad */ ;
3144         pSMB->TotalParameterCount = cpu_to_le16(params);
3145         pSMB->ParameterCount = pSMB->TotalParameterCount;
3146         pSMB->SearchAttributes =
3147             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3148                         ATTR_DIRECTORY);
3149         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
3150         pSMB->SearchFlags = cpu_to_le16(1);
3151         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3152         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
3153         pSMB->hdr.smb_buf_length += byte_count;
3154         pSMB->ByteCount = cpu_to_le16(byte_count);
3155
3156         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3157                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3158
3159         if (rc) {
3160                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3161         } else {                /* decode response */
3162                 cifs_stats_inc(&tcon->num_ffirst);
3163                 /* BB fill in */
3164         }
3165
3166         cifs_buf_release(pSMB);
3167         if (rc == -EAGAIN)
3168                 goto findUniqueRetry;
3169
3170         return rc;
3171 }
3172 #endif /* end unused (temporarily) function */
3173
3174 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3175 int
3176 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3177               const char *searchName, 
3178               const struct nls_table *nls_codepage,
3179               __u16 *   pnetfid,
3180               struct cifs_search_info * psrch_inf, int remap, const char dirsep)
3181 {
3182 /* level 257 SMB_ */
3183         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3184         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3185         T2_FFIRST_RSP_PARMS * parms;
3186         int rc = 0;
3187         int bytes_returned = 0;
3188         int name_len;
3189         __u16 params, byte_count;
3190
3191         cFYI(1, ("In FindFirst for %s",searchName));
3192
3193 findFirstRetry:
3194         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3195                       (void **) &pSMBr);
3196         if (rc)
3197                 return rc;
3198
3199         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3200                 name_len =
3201                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
3202                                  PATH_MAX, nls_codepage, remap);
3203                 /* We can not add the asterik earlier in case
3204                 it got remapped to 0xF03A as if it were part of the
3205                 directory name instead of a wildcard */
3206                 name_len *= 2;
3207                 pSMB->FileName[name_len] = dirsep;
3208                 pSMB->FileName[name_len+1] = 0;
3209                 pSMB->FileName[name_len+2] = '*';
3210                 pSMB->FileName[name_len+3] = 0;
3211                 name_len += 4; /* now the trailing null */
3212                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3213                 pSMB->FileName[name_len+1] = 0;
3214                 name_len += 2;
3215         } else {        /* BB add check for overrun of SMB buf BB */
3216                 name_len = strnlen(searchName, PATH_MAX);
3217 /* BB fix here and in unicode clause above ie
3218                 if(name_len > buffersize-header)
3219                         free buffer exit; BB */
3220                 strncpy(pSMB->FileName, searchName, name_len);
3221                 pSMB->FileName[name_len] = dirsep;
3222                 pSMB->FileName[name_len+1] = '*';
3223                 pSMB->FileName[name_len+2] = 0;
3224                 name_len += 3;
3225         }
3226
3227         params = 12 + name_len /* includes null */ ;
3228         pSMB->TotalDataCount = 0;       /* no EAs */
3229         pSMB->MaxParameterCount = cpu_to_le16(10);
3230         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3231                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3232         pSMB->MaxSetupCount = 0;
3233         pSMB->Reserved = 0;
3234         pSMB->Flags = 0;
3235         pSMB->Timeout = 0;
3236         pSMB->Reserved2 = 0;
3237         byte_count = params + 1 /* pad */ ;
3238         pSMB->TotalParameterCount = cpu_to_le16(params);
3239         pSMB->ParameterCount = pSMB->TotalParameterCount;
3240         pSMB->ParameterOffset = cpu_to_le16(
3241               offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3242                 - 4);
3243         pSMB->DataCount = 0;
3244         pSMB->DataOffset = 0;
3245         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
3246         pSMB->Reserved3 = 0;
3247         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3248         pSMB->SearchAttributes =
3249             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3250                         ATTR_DIRECTORY);
3251         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3252         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
3253                 CIFS_SEARCH_RETURN_RESUME);
3254         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3255
3256         /* BB what should we set StorageType to? Does it matter? BB */
3257         pSMB->SearchStorageType = 0;
3258         pSMB->hdr.smb_buf_length += byte_count;
3259         pSMB->ByteCount = cpu_to_le16(byte_count);
3260
3261         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3262                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3263         cifs_stats_inc(&tcon->num_ffirst);
3264
3265         if (rc) {/* BB add logic to retry regular search if Unix search
3266                         rejected unexpectedly by server */
3267                 /* BB Add code to handle unsupported level rc */
3268                 cFYI(1, ("Error in FindFirst = %d", rc));
3269
3270                 cifs_buf_release(pSMB);
3271
3272                 /* BB eventually could optimize out free and realloc of buf */
3273                 /*    for this case */
3274                 if (rc == -EAGAIN)
3275                         goto findFirstRetry;
3276         } else { /* decode response */
3277                 /* BB remember to free buffer if error BB */
3278                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3279                 if(rc == 0) {
3280                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3281                                 psrch_inf->unicode = TRUE;
3282                         else
3283                                 psrch_inf->unicode = FALSE;
3284
3285                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3286                         psrch_inf->smallBuf = 0;
3287                         psrch_inf->srch_entries_start = 
3288                                 (char *) &pSMBr->hdr.Protocol + 
3289                                         le16_to_cpu(pSMBr->t2.DataOffset);
3290                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3291                                le16_to_cpu(pSMBr->t2.ParameterOffset));
3292
3293                         if(parms->EndofSearch)
3294                                 psrch_inf->endOfSearch = TRUE;
3295                         else
3296                                 psrch_inf->endOfSearch = FALSE;
3297
3298                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3299                         psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3300                                 psrch_inf->entries_in_buffer;
3301                         *pnetfid = parms->SearchHandle;
3302                 } else {
3303                         cifs_buf_release(pSMB);
3304                 }
3305         }
3306
3307         return rc;
3308 }
3309
3310 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3311             __u16 searchHandle, struct cifs_search_info * psrch_inf)
3312 {
3313         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3314         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3315         T2_FNEXT_RSP_PARMS * parms;
3316         char *response_data;
3317         int rc = 0;
3318         int bytes_returned, name_len;
3319         __u16 params, byte_count;
3320
3321         cFYI(1, ("In FindNext"));
3322
3323         if(psrch_inf->endOfSearch == TRUE)
3324                 return -ENOENT;
3325
3326         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3327                 (void **) &pSMBr);
3328         if (rc)
3329                 return rc;
3330
3331         params = 14;    /* includes 2 bytes of null string, converted to LE below */
3332         byte_count = 0;
3333         pSMB->TotalDataCount = 0;       /* no EAs */
3334         pSMB->MaxParameterCount = cpu_to_le16(8);
3335         pSMB->MaxDataCount =
3336             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3337         pSMB->MaxSetupCount = 0;
3338         pSMB->Reserved = 0;
3339         pSMB->Flags = 0;
3340         pSMB->Timeout = 0;
3341         pSMB->Reserved2 = 0;
3342         pSMB->ParameterOffset =  cpu_to_le16(
3343               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3344         pSMB->DataCount = 0;
3345         pSMB->DataOffset = 0;
3346         pSMB->SetupCount = 1;
3347         pSMB->Reserved3 = 0;
3348         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3349         pSMB->SearchHandle = searchHandle;      /* always kept as le */
3350         pSMB->SearchCount =
3351                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3352         /* test for Unix extensions */
3353 /*      if (tcon->ses->capabilities & CAP_UNIX) {
3354                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3355                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3356         } else {
3357                 pSMB->InformationLevel =
3358                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3359                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3360         } */
3361         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3362         pSMB->ResumeKey = psrch_inf->resume_key;
3363         pSMB->SearchFlags =
3364               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3365
3366         name_len = psrch_inf->resume_name_len;
3367         params += name_len;
3368         if(name_len < PATH_MAX) {
3369                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3370                 byte_count += name_len;
3371                 /* 14 byte parm len above enough for 2 byte null terminator */
3372                 pSMB->ResumeFileName[name_len] = 0;
3373                 pSMB->ResumeFileName[name_len+1] = 0;
3374         } else {
3375                 rc = -EINVAL;
3376                 goto FNext2_err_exit;
3377         }
3378         byte_count = params + 1 /* pad */ ;
3379         pSMB->TotalParameterCount = cpu_to_le16(params);
3380         pSMB->ParameterCount = pSMB->TotalParameterCount;
3381         pSMB->hdr.smb_buf_length += byte_count;
3382         pSMB->ByteCount = cpu_to_le16(byte_count);
3383                                                                                               
3384         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3385                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3386         cifs_stats_inc(&tcon->num_fnext);
3387         if (rc) {
3388                 if (rc == -EBADF) {
3389                         psrch_inf->endOfSearch = TRUE;
3390                         rc = 0; /* search probably was closed at end of search above */
3391                 } else
3392                         cFYI(1, ("FindNext returned = %d", rc));
3393         } else {                /* decode response */
3394                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3395                 
3396                 if(rc == 0) {
3397                         /* BB fixme add lock for file (srch_info) struct here */
3398                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3399                                 psrch_inf->unicode = TRUE;
3400                         else
3401                                 psrch_inf->unicode = FALSE;
3402                         response_data = (char *) &pSMBr->hdr.Protocol +
3403                                le16_to_cpu(pSMBr->t2.ParameterOffset);
3404                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
3405                         response_data = (char *)&pSMBr->hdr.Protocol +
3406                                 le16_to_cpu(pSMBr->t2.DataOffset);
3407                         if(psrch_inf->smallBuf)
3408                                 cifs_small_buf_release(
3409                                         psrch_inf->ntwrk_buf_start);
3410                         else
3411                                 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3412                         psrch_inf->srch_entries_start = response_data;
3413                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
3414                         psrch_inf->smallBuf = 0;
3415                         if(parms->EndofSearch)
3416                                 psrch_inf->endOfSearch = TRUE;
3417                         else
3418                                 psrch_inf->endOfSearch = FALSE;
3419                                                                                               
3420                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3421                         psrch_inf->index_of_last_entry +=
3422                                 psrch_inf->entries_in_buffer;
3423 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3424
3425                         /* BB fixme add unlock here */
3426                 }
3427
3428         }
3429
3430         /* BB On error, should we leave previous search buf (and count and
3431         last entry fields) intact or free the previous one? */
3432
3433         /* Note: On -EAGAIN error only caller can retry on handle based calls
3434         since file handle passed in no longer valid */
3435 FNext2_err_exit:
3436         if (rc != 0)
3437                 cifs_buf_release(pSMB);
3438                                                                                               
3439         return rc;
3440 }
3441
3442 int
3443 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3444 {
3445         int rc = 0;
3446         FINDCLOSE_REQ *pSMB = NULL;
3447         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3448         int bytes_returned;
3449
3450         cFYI(1, ("In CIFSSMBFindClose"));
3451         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3452
3453         /* no sense returning error if session restarted
3454                 as file handle has been closed */
3455         if(rc == -EAGAIN)
3456                 return 0;
3457         if (rc)
3458                 return rc;
3459
3460         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
3461         pSMB->FileID = searchHandle;
3462         pSMB->ByteCount = 0;
3463         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3464                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3465         if (rc) {
3466                 cERROR(1, ("Send error in FindClose = %d", rc));
3467         }
3468         cifs_stats_inc(&tcon->num_fclose);
3469         cifs_small_buf_release(pSMB);
3470
3471         /* Since session is dead, search handle closed on server already */
3472         if (rc == -EAGAIN)
3473                 rc = 0;
3474
3475         return rc;
3476 }
3477
3478 int
3479 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3480                 const unsigned char *searchName,
3481                 __u64 * inode_number,
3482                 const struct nls_table *nls_codepage, int remap)
3483 {
3484         int rc = 0;
3485         TRANSACTION2_QPI_REQ *pSMB = NULL;
3486         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3487         int name_len, bytes_returned;
3488         __u16 params, byte_count;
3489
3490         cFYI(1,("In GetSrvInodeNum for %s",searchName));
3491         if(tcon == NULL)
3492                 return -ENODEV; 
3493
3494 GetInodeNumberRetry:
3495         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3496                       (void **) &pSMBr);
3497         if (rc)
3498                 return rc;
3499
3500
3501         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3502                 name_len =
3503                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3504                                 PATH_MAX,nls_codepage, remap);
3505                 name_len++;     /* trailing null */
3506                 name_len *= 2;
3507         } else {                /* BB improve the check for buffer overruns BB */
3508                 name_len = strnlen(searchName, PATH_MAX);
3509                 name_len++;     /* trailing null */
3510                 strncpy(pSMB->FileName, searchName, name_len);
3511         }
3512
3513         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
3514         pSMB->TotalDataCount = 0;
3515         pSMB->MaxParameterCount = cpu_to_le16(2);
3516         /* BB find exact max data count below from sess structure BB */
3517         pSMB->MaxDataCount = cpu_to_le16(4000);
3518         pSMB->MaxSetupCount = 0;
3519         pSMB->Reserved = 0;
3520         pSMB->Flags = 0;
3521         pSMB->Timeout = 0;
3522         pSMB->Reserved2 = 0;
3523         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3524                 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3525         pSMB->DataCount = 0;
3526         pSMB->DataOffset = 0;
3527         pSMB->SetupCount = 1;
3528         pSMB->Reserved3 = 0;
3529         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3530         byte_count = params + 1 /* pad */ ;
3531         pSMB->TotalParameterCount = cpu_to_le16(params);
3532         pSMB->ParameterCount = pSMB->TotalParameterCount;
3533         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3534         pSMB->Reserved4 = 0;
3535         pSMB->hdr.smb_buf_length += byte_count;
3536         pSMB->ByteCount = cpu_to_le16(byte_count);
3537
3538         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3539                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3540         if (rc) {
3541                 cFYI(1, ("error %d in QueryInternalInfo", rc));
3542         } else {
3543                 /* decode response */
3544                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3545                 if (rc || (pSMBr->ByteCount < 2))
3546                 /* BB also check enough total bytes returned */
3547                         /* If rc should we check for EOPNOSUPP and
3548                         disable the srvino flag? or in caller? */
3549                         rc = -EIO;      /* bad smb */
3550                 else {
3551                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3552                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3553                         struct file_internal_info * pfinfo;
3554                         /* BB Do we need a cast or hash here ? */
3555                         if(count < 8) {
3556                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3557                                 rc = -EIO;
3558                                 goto GetInodeNumOut;
3559                         }
3560                         pfinfo = (struct file_internal_info *)
3561                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3562                         *inode_number = pfinfo->UniqueId;
3563                 }
3564         }
3565 GetInodeNumOut:
3566         cifs_buf_release(pSMB);
3567         if (rc == -EAGAIN)
3568                 goto GetInodeNumberRetry;
3569         return rc;
3570 }
3571
3572 int
3573 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3574                 const unsigned char *searchName,
3575                 unsigned char **targetUNCs,
3576                 unsigned int *number_of_UNC_in_array,
3577                 const struct nls_table *nls_codepage, int remap)
3578 {
3579 /* TRANS2_GET_DFS_REFERRAL */
3580         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3581         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3582         struct dfs_referral_level_3 * referrals = NULL;
3583         int rc = 0;
3584         int bytes_returned;
3585         int name_len;
3586         unsigned int i;
3587         char * temp;
3588         __u16 params, byte_count;
3589         *number_of_UNC_in_array = 0;
3590         *targetUNCs = NULL;
3591
3592         cFYI(1, ("In GetDFSRefer the path %s", searchName));
3593         if (ses == NULL)
3594                 return -ENODEV;
3595 getDFSRetry:
3596         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3597                       (void **) &pSMBr);
3598         if (rc)
3599                 return rc;
3600         
3601         /* server pointer checked in called function, 
3602         but should never be null here anyway */
3603         pSMB->hdr.Mid = GetNextMid(ses->server);
3604         pSMB->hdr.Tid = ses->ipc_tid;
3605         pSMB->hdr.Uid = ses->Suid;
3606         if (ses->capabilities & CAP_STATUS32) {
3607                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3608         }
3609         if (ses->capabilities & CAP_DFS) {
3610                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3611         }
3612
3613         if (ses->capabilities & CAP_UNICODE) {
3614                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3615                 name_len =
3616                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3617                                      searchName, PATH_MAX, nls_codepage, remap);
3618                 name_len++;     /* trailing null */
3619                 name_len *= 2;
3620         } else {                /* BB improve the check for buffer overruns BB */
3621                 name_len = strnlen(searchName, PATH_MAX);
3622                 name_len++;     /* trailing null */
3623                 strncpy(pSMB->RequestFileName, searchName, name_len);
3624         }
3625
3626         params = 2 /* level */  + name_len /*includes null */ ;
3627         pSMB->TotalDataCount = 0;
3628         pSMB->DataCount = 0;
3629         pSMB->DataOffset = 0;
3630         pSMB->MaxParameterCount = 0;
3631         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3632         pSMB->MaxSetupCount = 0;
3633         pSMB->Reserved = 0;
3634         pSMB->Flags = 0;
3635         pSMB->Timeout = 0;
3636         pSMB->Reserved2 = 0;
3637         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3638         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3639         pSMB->SetupCount = 1;
3640         pSMB->Reserved3 = 0;
3641         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3642         byte_count = params + 3 /* pad */ ;
3643         pSMB->ParameterCount = cpu_to_le16(params);
3644         pSMB->TotalParameterCount = pSMB->ParameterCount;
3645         pSMB->MaxReferralLevel = cpu_to_le16(3);
3646         pSMB->hdr.smb_buf_length += byte_count;
3647         pSMB->ByteCount = cpu_to_le16(byte_count);
3648
3649         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3650                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3651         if (rc) {
3652                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3653         } else {                /* decode response */
3654 /* BB Add logic to parse referrals here */
3655                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3656
3657                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
3658                         rc = -EIO;      /* bad smb */
3659                 else {
3660                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
3661                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3662
3663                         cFYI(1,
3664                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
3665                               pSMBr->ByteCount, data_offset));
3666                         referrals = 
3667                             (struct dfs_referral_level_3 *) 
3668                                         (8 /* sizeof start of data block */ +
3669                                         data_offset +
3670                                         (char *) &pSMBr->hdr.Protocol); 
3671                         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",
3672                                 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)));
3673                         /* BB This field is actually two bytes in from start of
3674                            data block so we could do safety check that DataBlock
3675                            begins at address of pSMBr->NumberOfReferrals */
3676                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3677
3678                         /* BB Fix below so can return more than one referral */
3679                         if(*number_of_UNC_in_array > 1)
3680                                 *number_of_UNC_in_array = 1;
3681
3682                         /* get the length of the strings describing refs */
3683                         name_len = 0;
3684                         for(i=0;i<*number_of_UNC_in_array;i++) {
3685                                 /* make sure that DfsPathOffset not past end */
3686                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3687                                 if (offset > data_count) {
3688                                         /* if invalid referral, stop here and do 
3689                                         not try to copy any more */
3690                                         *number_of_UNC_in_array = i;
3691                                         break;
3692                                 } 
3693                                 temp = ((char *)referrals) + offset;
3694
3695                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3696                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
3697                                 } else {
3698                                         name_len += strnlen(temp,data_count);
3699                                 }
3700                                 referrals++;
3701                                 /* BB add check that referral pointer does not fall off end PDU */
3702                                 
3703                         }
3704                         /* BB add check for name_len bigger than bcc */
3705                         *targetUNCs = 
3706                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3707                         if(*targetUNCs == NULL) {
3708                                 rc = -ENOMEM;
3709                                 goto GetDFSRefExit;
3710                         }
3711                         /* copy the ref strings */
3712                         referrals =  
3713                             (struct dfs_referral_level_3 *) 
3714                                         (8 /* sizeof data hdr */ +
3715                                         data_offset + 
3716                                         (char *) &pSMBr->hdr.Protocol);
3717
3718                         for(i=0;i<*number_of_UNC_in_array;i++) {
3719                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3720                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3721                                         cifs_strfromUCS_le(*targetUNCs,
3722                                                 (__le16 *) temp, name_len, nls_codepage);
3723                                 } else {
3724                                         strncpy(*targetUNCs,temp,name_len);
3725                                 }
3726                                 /*  BB update target_uncs pointers */
3727                                 referrals++;
3728                         }
3729                         temp = *targetUNCs;
3730                         temp[name_len] = 0;
3731                 }
3732
3733         }
3734 GetDFSRefExit:
3735         if (pSMB)
3736                 cifs_buf_release(pSMB);
3737
3738         if (rc == -EAGAIN)
3739                 goto getDFSRetry;
3740
3741         return rc;
3742 }
3743
3744 /* Query File System Info such as free space to old servers such as Win 9x */
3745 int
3746 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3747 {
3748 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3749         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3750         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3751         FILE_SYSTEM_ALLOC_INFO *response_data;
3752         int rc = 0;
3753         int bytes_returned = 0;
3754         __u16 params, byte_count;
3755
3756         cFYI(1, ("OldQFSInfo"));
3757 oldQFSInfoRetry:
3758         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3759                 (void **) &pSMBr);
3760         if (rc)
3761                 return rc;
3762         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3763                       (void **) &pSMBr);
3764         if (rc)
3765                 return rc;
3766
3767         params = 2;     /* level */
3768         pSMB->TotalDataCount = 0;
3769         pSMB->MaxParameterCount = cpu_to_le16(2);
3770         pSMB->MaxDataCount = cpu_to_le16(1000);
3771         pSMB->MaxSetupCount = 0;
3772         pSMB->Reserved = 0;
3773         pSMB->Flags = 0;
3774         pSMB->Timeout = 0;
3775         pSMB->Reserved2 = 0;
3776         byte_count = params + 1 /* pad */ ;
3777         pSMB->TotalParameterCount = cpu_to_le16(params);
3778         pSMB->ParameterCount = pSMB->TotalParameterCount;
3779         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3780         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3781         pSMB->DataCount = 0;
3782         pSMB->DataOffset = 0;
3783         pSMB->SetupCount = 1;
3784         pSMB->Reserved3 = 0;
3785         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3786         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3787         pSMB->hdr.smb_buf_length += byte_count;
3788         pSMB->ByteCount = cpu_to_le16(byte_count);
3789
3790         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3791                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3792         if (rc) {
3793                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3794         } else {                /* decode response */
3795                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3796
3797                 if (rc || (pSMBr->ByteCount < 18))
3798                         rc = -EIO;      /* bad smb */
3799                 else {
3800                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3801                         cFYI(1,("qfsinf resp BCC: %d  Offset %d",
3802                                  pSMBr->ByteCount, data_offset));
3803
3804                         response_data =
3805                                 (FILE_SYSTEM_ALLOC_INFO *) 
3806                                 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3807                         FSData->f_bsize =
3808                                 le16_to_cpu(response_data->BytesPerSector) *
3809                                 le32_to_cpu(response_data->
3810                                         SectorsPerAllocationUnit);
3811                         FSData->f_blocks =
3812                                 le32_to_cpu(response_data->TotalAllocationUnits);
3813                         FSData->f_bfree = FSData->f_bavail =
3814                                 le32_to_cpu(response_data->FreeAllocationUnits);
3815                         cFYI(1,
3816                              ("Blocks: %lld  Free: %lld Block size %ld",
3817                               (unsigned long long)FSData->f_blocks,
3818                               (unsigned long long)FSData->f_bfree,
3819                               FSData->f_bsize));
3820                 }
3821         }
3822         cifs_buf_release(pSMB);
3823
3824         if (rc == -EAGAIN)
3825                 goto oldQFSInfoRetry;
3826
3827         return rc;
3828 }
3829
3830 int
3831 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3832 {
3833 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3834         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3835         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3836         FILE_SYSTEM_INFO *response_data;
3837         int rc = 0;
3838         int bytes_returned = 0;
3839         __u16 params, byte_count;
3840
3841         cFYI(1, ("In QFSInfo"));
3842 QFSInfoRetry:
3843         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3844                       (void **) &pSMBr);
3845         if (rc)
3846                 return rc;
3847
3848         params = 2;     /* level */
3849         pSMB->TotalDataCount = 0;
3850         pSMB->MaxParameterCount = cpu_to_le16(2);
3851         pSMB->MaxDataCount = cpu_to_le16(1000);
3852         pSMB->MaxSetupCount = 0;
3853         pSMB->Reserved = 0;
3854         pSMB->Flags = 0;
3855         pSMB->Timeout = 0;
3856         pSMB->Reserved2 = 0;
3857         byte_count = params + 1 /* pad */ ;
3858         pSMB->TotalParameterCount = cpu_to_le16(params);
3859         pSMB->ParameterCount = pSMB->TotalParameterCount;
3860         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3861         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3862         pSMB->DataCount = 0;
3863         pSMB->DataOffset = 0;
3864         pSMB->SetupCount = 1;
3865         pSMB->Reserved3 = 0;
3866         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3867         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3868         pSMB->hdr.smb_buf_length += byte_count;
3869         pSMB->ByteCount = cpu_to_le16(byte_count);
3870
3871         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3872                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3873         if (rc) {
3874                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3875         } else {                /* decode response */
3876                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3877
3878                 if (rc || (pSMBr->ByteCount < 24))
3879                         rc = -EIO;      /* bad smb */
3880                 else {
3881                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3882
3883                         response_data =
3884                             (FILE_SYSTEM_INFO
3885                              *) (((char *) &pSMBr->hdr.Protocol) +
3886                                  data_offset);
3887                         FSData->f_bsize =
3888                             le32_to_cpu(response_data->BytesPerSector) *
3889                             le32_to_cpu(response_data->
3890                                         SectorsPerAllocationUnit);
3891                         FSData->f_blocks =
3892                             le64_to_cpu(response_data->TotalAllocationUnits);
3893                         FSData->f_bfree = FSData->f_bavail =
3894                             le64_to_cpu(response_data->FreeAllocationUnits);
3895                         cFYI(1,
3896                              ("Blocks: %lld  Free: %lld Block size %ld",
3897                               (unsigned long long)FSData->f_blocks,
3898                               (unsigned long long)FSData->f_bfree,
3899                               FSData->f_bsize));
3900                 }
3901         }
3902         cifs_buf_release(pSMB);
3903
3904         if (rc == -EAGAIN)
3905                 goto QFSInfoRetry;
3906
3907         return rc;
3908 }
3909
3910 int
3911 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3912 {
3913 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3914         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3915         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3916         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3917         int rc = 0;
3918         int bytes_returned = 0;
3919         __u16 params, byte_count;
3920
3921         cFYI(1, ("In QFSAttributeInfo"));
3922 QFSAttributeRetry:
3923         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3924                       (void **) &pSMBr);
3925         if (rc)
3926                 return rc;
3927
3928         params = 2;     /* level */
3929         pSMB->TotalDataCount = 0;
3930         pSMB->MaxParameterCount = cpu_to_le16(2);
3931         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3932         pSMB->MaxSetupCount = 0;
3933         pSMB->Reserved = 0;
3934         pSMB->Flags = 0;
3935         pSMB->Timeout = 0;
3936         pSMB->Reserved2 = 0;
3937         byte_count = params + 1 /* pad */ ;
3938         pSMB->TotalParameterCount = cpu_to_le16(params);
3939         pSMB->ParameterCount = pSMB->TotalParameterCount;
3940         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3941         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3942         pSMB->DataCount = 0;
3943         pSMB->DataOffset = 0;
3944         pSMB->SetupCount = 1;
3945         pSMB->Reserved3 = 0;
3946         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3947         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3948         pSMB->hdr.smb_buf_length += byte_count;
3949         pSMB->ByteCount = cpu_to_le16(byte_count);
3950
3951         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3952                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3953         if (rc) {
3954                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3955         } else {                /* decode response */
3956                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3957
3958                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3959                         rc = -EIO;      /* bad smb */
3960                 } else {
3961                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3962                         response_data =
3963                             (FILE_SYSTEM_ATTRIBUTE_INFO
3964                              *) (((char *) &pSMBr->hdr.Protocol) +
3965                                  data_offset);
3966                         memcpy(&tcon->fsAttrInfo, response_data,
3967                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3968                 }
3969         }
3970         cifs_buf_release(pSMB);
3971
3972         if (rc == -EAGAIN)
3973                 goto QFSAttributeRetry;
3974
3975         return rc;
3976 }
3977
3978 int
3979 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3980 {
3981 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3982         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3983         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3984         FILE_SYSTEM_DEVICE_INFO *response_data;
3985         int rc = 0;
3986         int bytes_returned = 0;
3987         __u16 params, byte_count;
3988
3989         cFYI(1, ("In QFSDeviceInfo"));
3990 QFSDeviceRetry:
3991         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3992                       (void **) &pSMBr);
3993         if (rc)
3994                 return rc;
3995
3996         params = 2;     /* level */
3997         pSMB->TotalDataCount = 0;
3998         pSMB->MaxParameterCount = cpu_to_le16(2);
3999         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4000         pSMB->MaxSetupCount = 0;
4001         pSMB->Reserved = 0;
4002         pSMB->Flags = 0;
4003         pSMB->Timeout = 0;
4004         pSMB->Reserved2 = 0;
4005         byte_count = params + 1 /* pad */ ;
4006         pSMB->TotalParameterCount = cpu_to_le16(params);
4007         pSMB->ParameterCount = pSMB->TotalParameterCount;
4008         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4009         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4010
4011         pSMB->DataCount = 0;
4012         pSMB->DataOffset = 0;
4013         pSMB->SetupCount = 1;
4014         pSMB->Reserved3 = 0;
4015         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4016         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4017         pSMB->hdr.smb_buf_length += byte_count;
4018         pSMB->ByteCount = cpu_to_le16(byte_count);
4019
4020         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4021                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4022         if (rc) {
4023                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4024         } else {                /* decode response */
4025                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4026
4027                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4028                         rc = -EIO;      /* bad smb */
4029                 else {
4030                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4031                         response_data =
4032                             (FILE_SYSTEM_DEVICE_INFO *)
4033                                 (((char *) &pSMBr->hdr.Protocol) +
4034                                  data_offset);
4035                         memcpy(&tcon->fsDevInfo, response_data,
4036                                sizeof (FILE_SYSTEM_DEVICE_INFO));
4037                 }
4038         }
4039         cifs_buf_release(pSMB);
4040
4041         if (rc == -EAGAIN)
4042                 goto QFSDeviceRetry;
4043
4044         return rc;
4045 }
4046
4047 int
4048 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4049 {
4050 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
4051         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4052         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4053         FILE_SYSTEM_UNIX_INFO *response_data;
4054         int rc = 0;
4055         int bytes_returned = 0;
4056         __u16 params, byte_count;
4057
4058         cFYI(1, ("In QFSUnixInfo"));
4059 QFSUnixRetry:
4060         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4061                       (void **) &pSMBr);
4062         if (rc)
4063                 return rc;
4064
4065         params = 2;     /* level */
4066         pSMB->TotalDataCount = 0;
4067         pSMB->DataCount = 0;
4068         pSMB->DataOffset = 0;
4069         pSMB->MaxParameterCount = cpu_to_le16(2);
4070         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4071         pSMB->MaxSetupCount = 0;
4072         pSMB->Reserved = 0;
4073         pSMB->Flags = 0;
4074         pSMB->Timeout = 0;
4075         pSMB->Reserved2 = 0;
4076         byte_count = params + 1 /* pad */ ;
4077         pSMB->ParameterCount = cpu_to_le16(params);
4078         pSMB->TotalParameterCount = pSMB->ParameterCount;
4079         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
4080         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4081         pSMB->SetupCount = 1;
4082         pSMB->Reserved3 = 0;
4083         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4084         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4085         pSMB->hdr.smb_buf_length += byte_count;
4086         pSMB->ByteCount = cpu_to_le16(byte_count);
4087
4088         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4089                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4090         if (rc) {
4091                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4092         } else {                /* decode response */
4093                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4094
4095                 if (rc || (pSMBr->ByteCount < 13)) {
4096                         rc = -EIO;      /* bad smb */
4097                 } else {
4098                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4099                         response_data =
4100                             (FILE_SYSTEM_UNIX_INFO
4101                              *) (((char *) &pSMBr->hdr.Protocol) +
4102                                  data_offset);
4103                         memcpy(&tcon->fsUnixInfo, response_data,
4104                                sizeof (FILE_SYSTEM_UNIX_INFO));
4105                 }
4106         }
4107         cifs_buf_release(pSMB);
4108
4109         if (rc == -EAGAIN)
4110                 goto QFSUnixRetry;
4111
4112
4113         return rc;
4114 }
4115
4116 int
4117 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4118 {
4119 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
4120         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4121         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4122         int rc = 0;
4123         int bytes_returned = 0;
4124         __u16 params, param_offset, offset, byte_count;
4125
4126         cFYI(1, ("In SETFSUnixInfo"));
4127 SETFSUnixRetry:
4128         /* BB switch to small buf init to save memory */
4129         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4130                       (void **) &pSMBr);
4131         if (rc)
4132                 return rc;
4133
4134         params = 4;     /* 2 bytes zero followed by info level. */
4135         pSMB->MaxSetupCount = 0;
4136         pSMB->Reserved = 0;
4137         pSMB->Flags = 0;
4138         pSMB->Timeout = 0;
4139         pSMB->Reserved2 = 0;
4140         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4141         offset = param_offset + params;
4142
4143         pSMB->MaxParameterCount = cpu_to_le16(4);
4144         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4145         pSMB->SetupCount = 1;
4146         pSMB->Reserved3 = 0;
4147         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4148         byte_count = 1 /* pad */ + params + 12;
4149
4150         pSMB->DataCount = cpu_to_le16(12);
4151         pSMB->ParameterCount = cpu_to_le16(params);
4152         pSMB->TotalDataCount = pSMB->DataCount;
4153         pSMB->TotalParameterCount = pSMB->ParameterCount;
4154         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4155         pSMB->DataOffset = cpu_to_le16(offset);
4156
4157         /* Params. */
4158         pSMB->FileNum = 0;
4159         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4160
4161         /* Data. */
4162         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4163         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4164         pSMB->ClientUnixCap = cpu_to_le64(cap);
4165
4166         pSMB->hdr.smb_buf_length += byte_count;
4167         pSMB->ByteCount = cpu_to_le16(byte_count);
4168
4169         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4170                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4171         if (rc) {
4172                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4173         } else {                /* decode response */
4174                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4175                 if (rc) {
4176                         rc = -EIO;      /* bad smb */
4177                 }
4178         }
4179         cifs_buf_release(pSMB);
4180
4181         if (rc == -EAGAIN)
4182                 goto SETFSUnixRetry;
4183
4184         return rc;
4185 }
4186
4187
4188
4189 int
4190 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4191                    struct kstatfs *FSData)
4192 {
4193 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
4194         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4195         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4196         FILE_SYSTEM_POSIX_INFO *response_data;
4197         int rc = 0;
4198         int bytes_returned = 0;
4199         __u16 params, byte_count;
4200
4201         cFYI(1, ("In QFSPosixInfo"));
4202 QFSPosixRetry:
4203         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4204                       (void **) &pSMBr);
4205         if (rc)
4206                 return rc;
4207
4208         params = 2;     /* level */
4209         pSMB->TotalDataCount = 0;
4210         pSMB->DataCount = 0;
4211         pSMB->DataOffset = 0;
4212         pSMB->MaxParameterCount = cpu_to_le16(2);
4213         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4214         pSMB->MaxSetupCount = 0;
4215         pSMB->Reserved = 0;
4216         pSMB->Flags = 0;
4217         pSMB->Timeout = 0;
4218         pSMB->Reserved2 = 0;
4219         byte_count = params + 1 /* pad */ ;
4220         pSMB->ParameterCount = cpu_to_le16(params);
4221         pSMB->TotalParameterCount = pSMB->ParameterCount;
4222         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
4223         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4224         pSMB->SetupCount = 1;
4225         pSMB->Reserved3 = 0;
4226         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4227         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4228         pSMB->hdr.smb_buf_length += byte_count;
4229         pSMB->ByteCount = cpu_to_le16(byte_count);
4230
4231         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4232                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4233         if (rc) {
4234                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4235         } else {                /* decode response */
4236                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4237
4238                 if (rc || (pSMBr->ByteCount < 13)) {
4239                         rc = -EIO;      /* bad smb */
4240                 } else {
4241                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4242                         response_data =
4243                             (FILE_SYSTEM_POSIX_INFO
4244                              *) (((char *) &pSMBr->hdr.Protocol) +
4245                                  data_offset);
4246                         FSData->f_bsize =
4247                                         le32_to_cpu(response_data->BlockSize);
4248                         FSData->f_blocks =
4249                                         le64_to_cpu(response_data->TotalBlocks);
4250                         FSData->f_bfree =
4251                             le64_to_cpu(response_data->BlocksAvail);
4252                         if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4253                                 FSData->f_bavail = FSData->f_bfree;
4254                         } else {
4255                                 FSData->f_bavail =
4256                                         le64_to_cpu(response_data->UserBlocksAvail);
4257                         }
4258                         if(response_data->TotalFileNodes != cpu_to_le64(-1))
4259                                 FSData->f_files =
4260                                         le64_to_cpu(response_data->TotalFileNodes);
4261                         if(response_data->FreeFileNodes != cpu_to_le64(-1))
4262                                 FSData->f_ffree =
4263                                         le64_to_cpu(response_data->FreeFileNodes);
4264                 }
4265         }
4266         cifs_buf_release(pSMB);
4267
4268         if (rc == -EAGAIN)
4269                 goto QFSPosixRetry;
4270
4271         return rc;
4272 }
4273
4274
4275 /* We can not use write of zero bytes trick to 
4276    set file size due to need for large file support.  Also note that 
4277    this SetPathInfo is preferred to SetFileInfo based method in next 
4278    routine which is only needed to work around a sharing violation bug
4279    in Samba which this routine can run into */
4280
4281 int
4282 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4283               __u64 size, int SetAllocation, 
4284               const struct nls_table *nls_codepage, int remap)
4285 {
4286         struct smb_com_transaction2_spi_req *pSMB = NULL;
4287         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4288         struct file_end_of_file_info *parm_data;
4289         int name_len;
4290         int rc = 0;
4291         int bytes_returned = 0;
4292         __u16 params, byte_count, data_count, param_offset, offset;
4293
4294         cFYI(1, ("In SetEOF"));
4295 SetEOFRetry:
4296         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4297                       (void **) &pSMBr);
4298         if (rc)
4299                 return rc;
4300
4301         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4302                 name_len =
4303                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4304                                      PATH_MAX, nls_codepage, remap);
4305                 name_len++;     /* trailing null */
4306                 name_len *= 2;
4307         } else {        /* BB improve the check for buffer overruns BB */
4308                 name_len = strnlen(fileName, PATH_MAX);
4309                 name_len++;     /* trailing null */
4310                 strncpy(pSMB->FileName, fileName, name_len);
4311         }
4312         params = 6 + name_len;
4313         data_count = sizeof (struct file_end_of_file_info);
4314         pSMB->MaxParameterCount = cpu_to_le16(2);
4315         pSMB->MaxDataCount = cpu_to_le16(4100);
4316         pSMB->MaxSetupCount = 0;
4317         pSMB->Reserved = 0;
4318         pSMB->Flags = 0;
4319         pSMB->Timeout = 0;
4320         pSMB->Reserved2 = 0;
4321         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4322                                      InformationLevel) - 4;
4323         offset = param_offset + params;
4324         if(SetAllocation) {
4325                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4326                     pSMB->InformationLevel =
4327                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4328                 else
4329                     pSMB->InformationLevel =
4330                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4331         } else /* Set File Size */  {    
4332             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4333                     pSMB->InformationLevel =
4334                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4335             else
4336                     pSMB->InformationLevel =
4337                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4338         }
4339
4340         parm_data =
4341             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4342                                        offset);
4343         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4344         pSMB->DataOffset = cpu_to_le16(offset);
4345         pSMB->SetupCount = 1;
4346         pSMB->Reserved3 = 0;
4347         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4348         byte_count = 3 /* pad */  + params + data_count;
4349         pSMB->DataCount = cpu_to_le16(data_count);
4350         pSMB->TotalDataCount = pSMB->DataCount;
4351         pSMB->ParameterCount = cpu_to_le16(params);
4352         pSMB->TotalParameterCount = pSMB->ParameterCount;
4353         pSMB->Reserved4 = 0;
4354         pSMB->hdr.smb_buf_length += byte_count;
4355         parm_data->FileSize = cpu_to_le64(size);
4356         pSMB->ByteCount = cpu_to_le16(byte_count);
4357         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4358                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4359         if (rc) {
4360                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4361         }
4362
4363         cifs_buf_release(pSMB);
4364
4365         if (rc == -EAGAIN)
4366                 goto SetEOFRetry;
4367
4368         return rc;
4369 }
4370
4371 int
4372 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
4373                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
4374 {
4375         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4376         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4377         char *data_offset;
4378         struct file_end_of_file_info *parm_data;
4379         int rc = 0;
4380         int bytes_returned = 0;
4381         __u16 params, param_offset, offset, byte_count, count;
4382
4383         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4384                         (long long)size));
4385         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4386
4387         if (rc)
4388                 return rc;
4389
4390         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4391
4392         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4393         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4394     
4395         params = 6;
4396         pSMB->MaxSetupCount = 0;
4397         pSMB->Reserved = 0;
4398         pSMB->Flags = 0;
4399         pSMB->Timeout = 0;
4400         pSMB->Reserved2 = 0;
4401         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4402         offset = param_offset + params;
4403
4404         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
4405
4406         count = sizeof(struct file_end_of_file_info);
4407         pSMB->MaxParameterCount = cpu_to_le16(2);
4408         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4409         pSMB->SetupCount = 1;
4410         pSMB->Reserved3 = 0;
4411         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4412         byte_count = 3 /* pad */  + params + count;
4413         pSMB->DataCount = cpu_to_le16(count);
4414         pSMB->ParameterCount = cpu_to_le16(params);
4415         pSMB->TotalDataCount = pSMB->DataCount;
4416         pSMB->TotalParameterCount = pSMB->ParameterCount;
4417         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4418         parm_data =
4419                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4420                         offset);
4421         pSMB->DataOffset = cpu_to_le16(offset);
4422         parm_data->FileSize = cpu_to_le64(size);
4423         pSMB->Fid = fid;
4424         if(SetAllocation) {
4425                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4426                         pSMB->InformationLevel =
4427                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4428                 else
4429                         pSMB->InformationLevel =
4430                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4431         } else /* Set File Size */  {    
4432             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4433                     pSMB->InformationLevel =
4434                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4435             else
4436                     pSMB->InformationLevel =
4437                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4438         }
4439         pSMB->Reserved4 = 0;
4440         pSMB->hdr.smb_buf_length += byte_count;
4441         pSMB->ByteCount = cpu_to_le16(byte_count);
4442         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4443                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4444         if (rc) {
4445                 cFYI(1,
4446                      ("Send error in SetFileInfo (SetFileSize) = %d",
4447                       rc));
4448         }
4449
4450         if (pSMB)
4451                 cifs_small_buf_release(pSMB);
4452
4453         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4454                 since file handle passed in no longer valid */
4455
4456         return rc;
4457 }
4458
4459 /* Some legacy servers such as NT4 require that the file times be set on 
4460    an open handle, rather than by pathname - this is awkward due to
4461    potential access conflicts on the open, but it is unavoidable for these
4462    old servers since the only other choice is to go from 100 nanosecond DCE
4463    time and resort to the original setpathinfo level which takes the ancient
4464    DOS time format with 2 second granularity */
4465 int
4466 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
4467                    __u16 fid)
4468 {
4469         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4470         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4471         char *data_offset;
4472         int rc = 0;
4473         int bytes_returned = 0;
4474         __u16 params, param_offset, offset, byte_count, count;
4475
4476         cFYI(1, ("Set Times (via SetFileInfo)"));
4477         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4478
4479         if (rc)
4480                 return rc;
4481
4482         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4483
4484         /* At this point there is no need to override the current pid
4485         with the pid of the opener, but that could change if we someday
4486         use an existing handle (rather than opening one on the fly) */
4487         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4488         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4489     
4490         params = 6;
4491         pSMB->MaxSetupCount = 0;
4492         pSMB->Reserved = 0;
4493         pSMB->Flags = 0;
4494         pSMB->Timeout = 0;
4495         pSMB->Reserved2 = 0;
4496         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4497         offset = param_offset + params;
4498
4499         data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
4500
4501         count = sizeof (FILE_BASIC_INFO);
4502         pSMB->MaxParameterCount = cpu_to_le16(2);
4503         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4504         pSMB->SetupCount = 1;
4505         pSMB->Reserved3 = 0;
4506         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4507         byte_count = 3 /* pad */  + params + count;
4508         pSMB->DataCount = cpu_to_le16(count);
4509         pSMB->ParameterCount = cpu_to_le16(params);
4510         pSMB->TotalDataCount = pSMB->DataCount;
4511         pSMB->TotalParameterCount = pSMB->ParameterCount;
4512         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4513         pSMB->DataOffset = cpu_to_le16(offset);
4514         pSMB->Fid = fid;
4515         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4516                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4517         else
4518                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4519         pSMB->Reserved4 = 0;
4520         pSMB->hdr.smb_buf_length += byte_count;
4521         pSMB->ByteCount = cpu_to_le16(byte_count);
4522         memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4523         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4524                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4525         if (rc) {
4526                 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4527         }
4528
4529         cifs_small_buf_release(pSMB);
4530
4531         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4532                 since file handle passed in no longer valid */
4533
4534         return rc;
4535 }
4536
4537
4538 int
4539 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4540                 const FILE_BASIC_INFO * data, 
4541                 const struct nls_table *nls_codepage, int remap)
4542 {
4543         TRANSACTION2_SPI_REQ *pSMB = NULL;
4544         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4545         int name_len;
4546         int rc = 0;
4547         int bytes_returned = 0;
4548         char *data_offset;
4549         __u16 params, param_offset, offset, byte_count, count;
4550
4551         cFYI(1, ("In SetTimes"));
4552
4553 SetTimesRetry:
4554         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4555                       (void **) &pSMBr);
4556         if (rc)
4557                 return rc;
4558
4559         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4560                 name_len =
4561                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4562                                      PATH_MAX, nls_codepage, remap);
4563                 name_len++;     /* trailing null */
4564                 name_len *= 2;
4565         } else {                /* BB improve the check for buffer overruns BB */
4566                 name_len = strnlen(fileName, PATH_MAX);
4567                 name_len++;     /* trailing null */
4568                 strncpy(pSMB->FileName, fileName, name_len);
4569         }
4570
4571         params = 6 + name_len;
4572         count = sizeof (FILE_BASIC_INFO);
4573         pSMB->MaxParameterCount = cpu_to_le16(2);
4574         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4575         pSMB->MaxSetupCount = 0;
4576         pSMB->Reserved = 0;
4577         pSMB->Flags = 0;
4578         pSMB->Timeout = 0;
4579         pSMB->Reserved2 = 0;
4580         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4581                                      InformationLevel) - 4;
4582         offset = param_offset + params;
4583         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4584         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4585         pSMB->DataOffset = cpu_to_le16(offset);
4586         pSMB->SetupCount = 1;
4587         pSMB->Reserved3 = 0;
4588         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4589         byte_count = 3 /* pad */  + params + count;
4590
4591         pSMB->DataCount = cpu_to_le16(count);
4592         pSMB->ParameterCount = cpu_to_le16(params);
4593         pSMB->TotalDataCount = pSMB->DataCount;
4594         pSMB->TotalParameterCount = pSMB->ParameterCount;
4595         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4596                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4597         else
4598                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4599         pSMB->Reserved4 = 0;
4600         pSMB->hdr.smb_buf_length += byte_count;
4601         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4602         pSMB->ByteCount = cpu_to_le16(byte_count);
4603         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4604                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4605         if (rc) {
4606                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4607         }
4608
4609         cifs_buf_release(pSMB);
4610
4611         if (rc == -EAGAIN)
4612                 goto SetTimesRetry;
4613
4614         return rc;
4615 }
4616
4617 /* Can not be used to set time stamps yet (due to old DOS time format) */
4618 /* Can be used to set attributes */
4619 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
4620           handling it anyway and NT4 was what we thought it would be needed for
4621           Do not delete it until we prove whether needed for Win9x though */
4622 int
4623 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4624                 __u16 dos_attrs, const struct nls_table *nls_codepage)
4625 {
4626         SETATTR_REQ *pSMB = NULL;
4627         SETATTR_RSP *pSMBr = NULL;
4628         int rc = 0;
4629         int bytes_returned;
4630         int name_len;
4631
4632         cFYI(1, ("In SetAttrLegacy"));
4633
4634 SetAttrLgcyRetry:
4635         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4636                       (void **) &pSMBr);
4637         if (rc)
4638                 return rc;
4639
4640         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4641                 name_len =
4642                         ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
4643                                 PATH_MAX, nls_codepage);
4644                 name_len++;     /* trailing null */
4645                 name_len *= 2;
4646         } else {                /* BB improve the check for buffer overruns BB */
4647                 name_len = strnlen(fileName, PATH_MAX);
4648                 name_len++;     /* trailing null */
4649                 strncpy(pSMB->fileName, fileName, name_len);
4650         }
4651         pSMB->attr = cpu_to_le16(dos_attrs);
4652         pSMB->BufferFormat = 0x04;
4653         pSMB->hdr.smb_buf_length += name_len + 1;
4654         pSMB->ByteCount = cpu_to_le16(name_len + 1);
4655         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4656                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4657         if (rc) {
4658                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4659         }
4660
4661         cifs_buf_release(pSMB);
4662
4663         if (rc == -EAGAIN)
4664                 goto SetAttrLgcyRetry;
4665
4666         return rc;
4667 }
4668 #endif /* temporarily unneeded SetAttr legacy function */
4669
4670 int
4671 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4672                     char *fileName, __u64 mode, __u64 uid, __u64 gid, 
4673                     dev_t device, const struct nls_table *nls_codepage, 
4674                     int remap)
4675 {
4676         TRANSACTION2_SPI_REQ *pSMB = NULL;
4677         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4678         int name_len;
4679         int rc = 0;
4680         int bytes_returned = 0;
4681         FILE_UNIX_BASIC_INFO *data_offset;
4682         __u16 params, param_offset, offset, count, byte_count;
4683
4684         cFYI(1, ("In SetUID/GID/Mode"));
4685 setPermsRetry:
4686         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4687                       (void **) &pSMBr);
4688         if (rc)
4689                 return rc;
4690
4691         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4692                 name_len =
4693                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4694                                      PATH_MAX, nls_codepage, remap);
4695                 name_len++;     /* trailing null */
4696                 name_len *= 2;
4697         } else {        /* BB improve the check for buffer overruns BB */
4698                 name_len = strnlen(fileName, PATH_MAX);
4699                 name_len++;     /* trailing null */
4700                 strncpy(pSMB->FileName, fileName, name_len);
4701         }
4702
4703         params = 6 + name_len;
4704         count = sizeof (FILE_UNIX_BASIC_INFO);
4705         pSMB->MaxParameterCount = cpu_to_le16(2);
4706         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4707         pSMB->MaxSetupCount = 0;
4708         pSMB->Reserved = 0;
4709         pSMB->Flags = 0;
4710         pSMB->Timeout = 0;
4711         pSMB->Reserved2 = 0;
4712         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4713                                      InformationLevel) - 4;
4714         offset = param_offset + params;
4715         data_offset =
4716             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4717                                       offset);
4718         memset(data_offset, 0, count);
4719         pSMB->DataOffset = cpu_to_le16(offset);
4720         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4721         pSMB->SetupCount = 1;
4722         pSMB->Reserved3 = 0;
4723         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4724         byte_count = 3 /* pad */  + params + count;
4725         pSMB->ParameterCount = cpu_to_le16(params);
4726         pSMB->DataCount = cpu_to_le16(count);
4727         pSMB->TotalParameterCount = pSMB->ParameterCount;
4728         pSMB->TotalDataCount = pSMB->DataCount;
4729         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4730         pSMB->Reserved4 = 0;
4731         pSMB->hdr.smb_buf_length += byte_count;
4732         data_offset->Uid = cpu_to_le64(uid);
4733         data_offset->Gid = cpu_to_le64(gid);
4734         /* better to leave device as zero when it is  */
4735         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4736         data_offset->DevMinor = cpu_to_le64(MINOR(device));
4737         data_offset->Permissions = cpu_to_le64(mode);
4738     
4739         if(S_ISREG(mode))
4740                 data_offset->Type = cpu_to_le32(UNIX_FILE);
4741         else if(S_ISDIR(mode))
4742                 data_offset->Type = cpu_to_le32(UNIX_DIR);
4743         else if(S_ISLNK(mode))
4744                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4745         else if(S_ISCHR(mode))
4746                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4747         else if(S_ISBLK(mode))
4748                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4749         else if(S_ISFIFO(mode))
4750                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4751         else if(S_ISSOCK(mode))
4752                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4753
4754
4755         pSMB->ByteCount = cpu_to_le16(byte_count);
4756         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4757                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4758         if (rc) {
4759                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4760         }
4761
4762         if (pSMB)
4763                 cifs_buf_release(pSMB);
4764         if (rc == -EAGAIN)
4765                 goto setPermsRetry;
4766         return rc;
4767 }
4768
4769 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
4770                   const int notify_subdirs, const __u16 netfid,
4771                   __u32 filter, struct file * pfile, int multishot, 
4772                   const struct nls_table *nls_codepage)
4773 {
4774         int rc = 0;
4775         struct smb_com_transaction_change_notify_req * pSMB = NULL;
4776         struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4777         struct dir_notify_req *dnotify_req;
4778         int bytes_returned;
4779
4780         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4781         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4782                       (void **) &pSMBr);
4783         if (rc)
4784                 return rc;
4785
4786         pSMB->TotalParameterCount = 0 ;
4787         pSMB->TotalDataCount = 0;
4788         pSMB->MaxParameterCount = cpu_to_le32(2);
4789         /* BB find exact data count max from sess structure BB */
4790         pSMB->MaxDataCount = 0; /* same in little endian or be */
4791 /* BB VERIFY verify which is correct for above BB */
4792         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4793                                              MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4794
4795         pSMB->MaxSetupCount = 4;
4796         pSMB->Reserved = 0;
4797         pSMB->ParameterOffset = 0;
4798         pSMB->DataCount = 0;
4799         pSMB->DataOffset = 0;
4800         pSMB->SetupCount = 4; /* single byte does not need le conversion */
4801         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4802         pSMB->ParameterCount = pSMB->TotalParameterCount;
4803         if(notify_subdirs)
4804                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4805         pSMB->Reserved2 = 0;
4806         pSMB->CompletionFilter = cpu_to_le32(filter);
4807         pSMB->Fid = netfid; /* file handle always le */
4808         pSMB->ByteCount = 0;
4809
4810         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4811                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4812         if (rc) {
4813                 cFYI(1, ("Error in Notify = %d", rc));
4814         } else {
4815                 /* Add file to outstanding requests */
4816                 /* BB change to kmem cache alloc */     
4817                 dnotify_req = (struct dir_notify_req *) kmalloc(
4818                                                 sizeof(struct dir_notify_req),
4819                                                  GFP_KERNEL);
4820                 if(dnotify_req) {
4821                         dnotify_req->Pid = pSMB->hdr.Pid;
4822                         dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4823                         dnotify_req->Mid = pSMB->hdr.Mid;
4824                         dnotify_req->Tid = pSMB->hdr.Tid;
4825                         dnotify_req->Uid = pSMB->hdr.Uid;
4826                         dnotify_req->netfid = netfid;
4827                         dnotify_req->pfile = pfile;
4828                         dnotify_req->filter = filter;
4829                         dnotify_req->multishot = multishot;
4830                         spin_lock(&GlobalMid_Lock);
4831                         list_add_tail(&dnotify_req->lhead, 
4832                                         &GlobalDnotifyReqList);
4833                         spin_unlock(&GlobalMid_Lock);
4834                 } else 
4835                         rc = -ENOMEM;
4836         }
4837         cifs_buf_release(pSMB);
4838         return rc;      
4839 }
4840 #ifdef CONFIG_CIFS_XATTR
4841 ssize_t
4842 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4843                  const unsigned char *searchName,
4844                  char * EAData, size_t buf_size,
4845                  const struct nls_table *nls_codepage, int remap)
4846 {
4847                 /* BB assumes one setup word */
4848         TRANSACTION2_QPI_REQ *pSMB = NULL;
4849         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4850         int rc = 0;
4851         int bytes_returned;
4852         int name_len;
4853         struct fea * temp_fea;
4854         char * temp_ptr;
4855         __u16 params, byte_count;
4856
4857         cFYI(1, ("In Query All EAs path %s", searchName));
4858 QAllEAsRetry:
4859         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4860                       (void **) &pSMBr);
4861         if (rc)
4862                 return rc;
4863
4864         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4865                 name_len =
4866                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4867                                      PATH_MAX, nls_codepage, remap);
4868                 name_len++;     /* trailing null */
4869                 name_len *= 2;
4870         } else {        /* BB improve the check for buffer overruns BB */
4871                 name_len = strnlen(searchName, PATH_MAX);
4872                 name_len++;     /* trailing null */
4873                 strncpy(pSMB->FileName, searchName, name_len);
4874         }
4875
4876         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4877         pSMB->TotalDataCount = 0;
4878         pSMB->MaxParameterCount = cpu_to_le16(2);
4879         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4880         pSMB->MaxSetupCount = 0;
4881         pSMB->Reserved = 0;
4882         pSMB->Flags = 0;
4883         pSMB->Timeout = 0;
4884         pSMB->Reserved2 = 0;
4885         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4886         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4887         pSMB->DataCount = 0;
4888         pSMB->DataOffset = 0;
4889         pSMB->SetupCount = 1;
4890         pSMB->Reserved3 = 0;
4891         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4892         byte_count = params + 1 /* pad */ ;
4893         pSMB->TotalParameterCount = cpu_to_le16(params);
4894         pSMB->ParameterCount = pSMB->TotalParameterCount;
4895         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4896         pSMB->Reserved4 = 0;
4897         pSMB->hdr.smb_buf_length += byte_count;
4898         pSMB->ByteCount = cpu_to_le16(byte_count);
4899
4900         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4901                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4902         if (rc) {
4903                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4904         } else {                /* decode response */
4905                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4906
4907                 /* BB also check enough total bytes returned */
4908                 /* BB we need to improve the validity checking
4909                 of these trans2 responses */
4910                 if (rc || (pSMBr->ByteCount < 4)) 
4911                         rc = -EIO;      /* bad smb */
4912            /* else if (pFindData){
4913                         memcpy((char *) pFindData,
4914                                (char *) &pSMBr->hdr.Protocol +
4915                                data_offset, kl);
4916                 }*/ else {
4917                         /* check that length of list is not more than bcc */
4918                         /* check that each entry does not go beyond length
4919                            of list */
4920                         /* check that each element of each entry does not
4921                            go beyond end of list */
4922                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4923                         struct fealist * ea_response_data;
4924                         rc = 0;
4925                         /* validate_trans2_offsets() */
4926                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4927                         ea_response_data = (struct fealist *)
4928                                 (((char *) &pSMBr->hdr.Protocol) +
4929                                 data_offset);
4930                         name_len = le32_to_cpu(ea_response_data->list_len);
4931                         cFYI(1,("ea length %d", name_len));
4932                         if(name_len <= 8) {
4933                         /* returned EA size zeroed at top of function */
4934                                 cFYI(1,("empty EA list returned from server"));
4935                         } else {
4936                                 /* account for ea list len */
4937                                 name_len -= 4;
4938                                 temp_fea = ea_response_data->list;
4939                                 temp_ptr = (char *)temp_fea;
4940                                 while(name_len > 0) {
4941                                         __u16 value_len;
4942                                         name_len -= 4;
4943                                         temp_ptr += 4;
4944                                         rc += temp_fea->name_len;
4945                                 /* account for prefix user. and trailing null */
4946                                         rc = rc + 5 + 1; 
4947                                         if(rc<(int)buf_size) {
4948                                                 memcpy(EAData,"user.",5);
4949                                                 EAData+=5;
4950                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
4951                                                 EAData+=temp_fea->name_len;
4952                                                 /* null terminate name */
4953                                                 *EAData = 0;
4954                                                 EAData = EAData + 1;
4955                                         } else if(buf_size == 0) {
4956                                                 /* skip copy - calc size only */
4957                                         } else {
4958                                                 /* stop before overrun buffer */
4959                                                 rc = -ERANGE;
4960                                                 break;
4961                                         }
4962                                         name_len -= temp_fea->name_len;
4963                                         temp_ptr += temp_fea->name_len;
4964                                         /* account for trailing null */
4965                                         name_len--;
4966                                         temp_ptr++;
4967                                         value_len = le16_to_cpu(temp_fea->value_len);
4968                                         name_len -= value_len;
4969                                         temp_ptr += value_len;
4970                                         /* BB check that temp_ptr is still within smb BB*/
4971                                 /* no trailing null to account for in value len */
4972                                         /* go on to next EA */
4973                                         temp_fea = (struct fea *)temp_ptr;
4974                                 }
4975                         }
4976                 }
4977         }
4978         if (pSMB)
4979                 cifs_buf_release(pSMB);
4980         if (rc == -EAGAIN)
4981                 goto QAllEAsRetry;
4982
4983         return (ssize_t)rc;
4984 }
4985
4986 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4987                 const unsigned char * searchName,const unsigned char * ea_name,
4988                 unsigned char * ea_value, size_t buf_size, 
4989                 const struct nls_table *nls_codepage, int remap)
4990 {
4991         TRANSACTION2_QPI_REQ *pSMB = NULL;
4992         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4993         int rc = 0;
4994         int bytes_returned;
4995         int name_len;
4996         struct fea * temp_fea;
4997         char * temp_ptr;
4998         __u16 params, byte_count;
4999
5000         cFYI(1, ("In Query EA path %s", searchName));
5001 QEARetry:
5002         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5003                       (void **) &pSMBr);
5004         if (rc)
5005                 return rc;
5006
5007         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5008                 name_len =
5009                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
5010                                      PATH_MAX, nls_codepage, remap);
5011                 name_len++;     /* trailing null */
5012                 name_len *= 2;
5013         } else {        /* BB improve the check for buffer overruns BB */
5014                 name_len = strnlen(searchName, PATH_MAX);
5015                 name_len++;     /* trailing null */
5016                 strncpy(pSMB->FileName, searchName, name_len);
5017         }
5018
5019         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5020         pSMB->TotalDataCount = 0;
5021         pSMB->MaxParameterCount = cpu_to_le16(2);
5022         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5023         pSMB->MaxSetupCount = 0;
5024         pSMB->Reserved = 0;
5025         pSMB->Flags = 0;
5026         pSMB->Timeout = 0;
5027         pSMB->Reserved2 = 0;
5028         pSMB->ParameterOffset = cpu_to_le16(offsetof(
5029         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5030         pSMB->DataCount = 0;
5031         pSMB->DataOffset = 0;
5032         pSMB->SetupCount = 1;
5033         pSMB->Reserved3 = 0;
5034         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5035         byte_count = params + 1 /* pad */ ;
5036         pSMB->TotalParameterCount = cpu_to_le16(params);
5037         pSMB->ParameterCount = pSMB->TotalParameterCount;
5038         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5039         pSMB->Reserved4 = 0;
5040         pSMB->hdr.smb_buf_length += byte_count;
5041         pSMB->ByteCount = cpu_to_le16(byte_count);
5042
5043         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5044                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5045         if (rc) {
5046                 cFYI(1, ("Send error in Query EA = %d", rc));
5047         } else {                /* decode response */
5048                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5049
5050                 /* BB also check enough total bytes returned */
5051                 /* BB we need to improve the validity checking
5052                 of these trans2 responses */
5053                 if (rc || (pSMBr->ByteCount < 4)) 
5054                         rc = -EIO;      /* bad smb */
5055            /* else if (pFindData){
5056                         memcpy((char *) pFindData,
5057                                (char *) &pSMBr->hdr.Protocol +
5058                                data_offset, kl);
5059                 }*/ else {
5060                         /* check that length of list is not more than bcc */
5061                         /* check that each entry does not go beyond length
5062                            of list */
5063                         /* check that each element of each entry does not
5064                            go beyond end of list */
5065                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5066                         struct fealist * ea_response_data;
5067                         rc = -ENODATA;
5068                         /* validate_trans2_offsets() */
5069                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5070                         ea_response_data = (struct fealist *)
5071                                 (((char *) &pSMBr->hdr.Protocol) +
5072                                 data_offset);
5073                         name_len = le32_to_cpu(ea_response_data->list_len);
5074                         cFYI(1,("ea length %d", name_len));
5075                         if(name_len <= 8) {
5076                         /* returned EA size zeroed at top of function */
5077                                 cFYI(1,("empty EA list returned from server"));
5078                         } else {
5079                                 /* account for ea list len */
5080                                 name_len -= 4;
5081                                 temp_fea = ea_response_data->list;
5082                                 temp_ptr = (char *)temp_fea;
5083                                 /* loop through checking if we have a matching
5084                                 name and then return the associated value */
5085                                 while(name_len > 0) {
5086                                         __u16 value_len;
5087                                         name_len -= 4;
5088                                         temp_ptr += 4;
5089                                         value_len = le16_to_cpu(temp_fea->value_len);
5090                                 /* BB validate that value_len falls within SMB, 
5091                                 even though maximum for name_len is 255 */ 
5092                                         if(memcmp(temp_fea->name,ea_name,
5093                                                   temp_fea->name_len) == 0) {
5094                                                 /* found a match */
5095                                                 rc = value_len;
5096                                 /* account for prefix user. and trailing null */
5097                                                 if(rc<=(int)buf_size) {
5098                                                         memcpy(ea_value,
5099                                                                 temp_fea->name+temp_fea->name_len+1,
5100                                                                 rc);
5101                                                         /* ea values, unlike ea names,
5102                                                         are not null terminated */
5103                                                 } else if(buf_size == 0) {
5104                                                 /* skip copy - calc size only */
5105                                                 } else {
5106                                                         /* stop before overrun buffer */
5107                                                         rc = -ERANGE;
5108                                                 }
5109                                                 break;
5110                                         }
5111                                         name_len -= temp_fea->name_len;
5112                                         temp_ptr += temp_fea->name_len;
5113                                         /* account for trailing null */
5114                                         name_len--;
5115                                         temp_ptr++;
5116                                         name_len -= value_len;
5117                                         temp_ptr += value_len;
5118                                 /* no trailing null to account for in value len */
5119                                         /* go on to next EA */
5120                                         temp_fea = (struct fea *)temp_ptr;
5121                                 }
5122                         } 
5123                 }
5124         }
5125         if (pSMB)
5126                 cifs_buf_release(pSMB);
5127         if (rc == -EAGAIN)
5128                 goto QEARetry;
5129
5130         return (ssize_t)rc;
5131 }
5132
5133 int
5134 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5135                 const char * ea_name, const void * ea_value, 
5136                 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5137                 int remap)
5138 {
5139         struct smb_com_transaction2_spi_req *pSMB = NULL;
5140         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5141         struct fealist *parm_data;
5142         int name_len;
5143         int rc = 0;
5144         int bytes_returned = 0;
5145         __u16 params, param_offset, byte_count, offset, count;
5146
5147         cFYI(1, ("In SetEA"));
5148 SetEARetry:
5149         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5150                       (void **) &pSMBr);
5151         if (rc)
5152                 return rc;
5153
5154         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5155                 name_len =
5156                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
5157                                      PATH_MAX, nls_codepage, remap);
5158                 name_len++;     /* trailing null */
5159                 name_len *= 2;
5160         } else {                /* BB improve the check for buffer overruns BB */
5161                 name_len = strnlen(fileName, PATH_MAX);
5162                 name_len++;     /* trailing null */
5163                 strncpy(pSMB->FileName, fileName, name_len);
5164         }
5165
5166         params = 6 + name_len;
5167
5168         /* done calculating parms using name_len of file name,
5169         now use name_len to calculate length of ea name
5170         we are going to create in the inode xattrs */
5171         if(ea_name == NULL)
5172                 name_len = 0;
5173         else
5174                 name_len = strnlen(ea_name,255);
5175
5176         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5177         pSMB->MaxParameterCount = cpu_to_le16(2);
5178         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5179         pSMB->MaxSetupCount = 0;
5180         pSMB->Reserved = 0;
5181         pSMB->Flags = 0;
5182         pSMB->Timeout = 0;
5183         pSMB->Reserved2 = 0;
5184         param_offset = offsetof(struct smb_com_transaction2_spi_req,
5185                                      InformationLevel) - 4;
5186         offset = param_offset + params;
5187         pSMB->InformationLevel =
5188                 cpu_to_le16(SMB_SET_FILE_EA);
5189
5190         parm_data =
5191                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5192                                        offset);
5193         pSMB->ParameterOffset = cpu_to_le16(param_offset);
5194         pSMB->DataOffset = cpu_to_le16(offset);
5195         pSMB->SetupCount = 1;
5196         pSMB->Reserved3 = 0;
5197         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5198         byte_count = 3 /* pad */  + params + count;
5199         pSMB->DataCount = cpu_to_le16(count);
5200         parm_data->list_len = cpu_to_le32(count);
5201         parm_data->list[0].EA_flags = 0;
5202         /* we checked above that name len is less than 255 */
5203         parm_data->list[0].name_len = (__u8)name_len;
5204         /* EA names are always ASCII */
5205         if(ea_name)
5206                 strncpy(parm_data->list[0].name,ea_name,name_len);
5207         parm_data->list[0].name[name_len] = 0;
5208         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5209         /* caller ensures that ea_value_len is less than 64K but
5210         we need to ensure that it fits within the smb */
5211
5212         /*BB add length check that it would fit in negotiated SMB buffer size BB */
5213         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5214         if(ea_value_len)
5215                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5216
5217         pSMB->TotalDataCount = pSMB->DataCount;
5218         pSMB->ParameterCount = cpu_to_le16(params);
5219         pSMB->TotalParameterCount = pSMB->ParameterCount;
5220         pSMB->Reserved4 = 0;
5221         pSMB->hdr.smb_buf_length += byte_count;
5222         pSMB->ByteCount = cpu_to_le16(byte_count);
5223         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5224                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5225         if (rc) {
5226                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5227         }
5228
5229         cifs_buf_release(pSMB);
5230
5231         if (rc == -EAGAIN)
5232                 goto SetEARetry;
5233
5234         return rc;
5235 }
5236
5237 #endif