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