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