6f50f2bc8870e418fb9df8b4bb70ba8027bfc3e9
[sfrench/cifs-2.6.git] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2006
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   Contains the routines for constructing the SMB PDUs themselves
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
25  /* These are mostly routines that operate on a pathname, or on a tree id     */
26  /* (mounted volume), but there are eight handle based routines which must be */
27  /* treated slightly different for reconnection purposes since we never want  */
28  /* to reuse a stale file handle and the caller knows the file handle */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsproto.h"
38 #include "cifs_unicode.h"
39 #include "cifs_debug.h"
40 #include "cifsacl.h"
41
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44         int index;
45         char *name;
46 } protocols[] = {
47 #ifdef CONFIG_CIFS_WEAK_PW_HASH
48         {LANMAN_PROT, "\2LM1.2X002"},
49         {LANMAN2_PROT, "\2LANMAN2.1"},
50 #endif /* weak password hashing for legacy clients */
51         {CIFS_PROT, "\2NT LM 0.12"}, 
52         {POSIX_PROT, "\2POSIX 2"},
53         {BAD_PROT, "\2"}
54 };
55 #else
56 static struct {
57         int index;
58         char *name;
59 } protocols[] = {
60 #ifdef CONFIG_CIFS_WEAK_PW_HASH
61         {LANMAN_PROT, "\2LM1.2X002"},
62         {LANMAN2_PROT, "\2LANMAN2.1"},
63 #endif /* weak password hashing for legacy clients */
64         {CIFS_PROT, "\2NT LM 0.12"}, 
65         {BAD_PROT, "\2"}
66 };
67 #endif
68
69 /* define the number of elements in the cifs dialect array */
70 #ifdef CONFIG_CIFS_POSIX
71 #ifdef CONFIG_CIFS_WEAK_PW_HASH
72 #define CIFS_NUM_PROT 4
73 #else
74 #define CIFS_NUM_PROT 2
75 #endif /* CIFS_WEAK_PW_HASH */
76 #else /* not posix */
77 #ifdef CONFIG_CIFS_WEAK_PW_HASH
78 #define CIFS_NUM_PROT 3
79 #else
80 #define CIFS_NUM_PROT 1
81 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
82 #endif /* CIFS_POSIX */
83
84
85 /* Mark as invalid, all open files on tree connections since they
86    were closed when session to server was lost */
87 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
88 {
89         struct cifsFileInfo *open_file = NULL;
90         struct list_head * tmp;
91         struct list_head * tmp1;
92
93 /* list all files open on tree connection and mark them invalid */
94         write_lock(&GlobalSMBSeslock);
95         list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
96                 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
97                 if(open_file) {
98                         open_file->invalidHandle = TRUE;
99                 }
100         }
101         write_unlock(&GlobalSMBSeslock);
102         /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
103            to this tcon */
104 }
105
106 /* If the return code is zero, this function must fill in request_buf pointer */
107 static int
108 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
109          void **request_buf /* returned */)
110 {
111         int rc = 0;
112
113         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
114            check for tcp and smb session status done differently
115            for those three - in the calling routine */
116         if(tcon) {
117                 if(tcon->tidStatus == CifsExiting) {
118                         /* only tree disconnect, open, and write,
119                         (and ulogoff which does not have tcon)
120                         are allowed as we start force umount */
121                         if((smb_command != SMB_COM_WRITE_ANDX) && 
122                            (smb_command != SMB_COM_OPEN_ANDX) && 
123                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
124                                 cFYI(1,("can not send cmd %d while umounting",
125                                         smb_command));
126                                 return -ENODEV;
127                         }
128                 }
129                 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
130                                   (tcon->ses->server)){
131                         struct nls_table *nls_codepage;
132                                 /* Give Demultiplex thread up to 10 seconds to 
133                                    reconnect, should be greater than cifs socket
134                                    timeout which is 7 seconds */
135                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
136                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
137                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
138                                 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
139                                         /* on "soft" mounts we wait once */
140                                         if((tcon->retry == FALSE) || 
141                                            (tcon->ses->status == CifsExiting)) {
142                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
143                                                 return -EHOSTDOWN;
144                                         } /* else "hard" mount - keep retrying
145                                              until process is killed or server
146                                              comes back on-line */
147                                 } else /* TCP session is reestablished now */
148                                         break;
149                                  
150                         }
151                         
152                         nls_codepage = load_nls_default();
153                 /* need to prevent multiple threads trying to
154                 simultaneously reconnect the same SMB session */
155                         down(&tcon->ses->sesSem);
156                         if(tcon->ses->status == CifsNeedReconnect)
157                                 rc = cifs_setup_session(0, tcon->ses, 
158                                                         nls_codepage);
159                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
160                                 mark_open_files_invalid(tcon);
161                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
162                                         , nls_codepage);
163                                 up(&tcon->ses->sesSem);
164                                 /* BB FIXME add code to check if wsize needs
165                                    update due to negotiated smb buffer size
166                                    shrinking */
167                                 if(rc == 0)
168                                         atomic_inc(&tconInfoReconnectCount);
169
170                                 cFYI(1, ("reconnect tcon rc = %d", rc));
171                                 /* Removed call to reopen open files here - 
172                                    it is safer (and faster) to reopen files
173                                    one at a time as needed in read and write */
174
175                                 /* Check if handle based operation so we 
176                                    know whether we can continue or not without
177                                    returning to caller to reset file handle */
178                                 switch(smb_command) {
179                                         case SMB_COM_READ_ANDX:
180                                         case SMB_COM_WRITE_ANDX:
181                                         case SMB_COM_CLOSE:
182                                         case SMB_COM_FIND_CLOSE2:
183                                         case SMB_COM_LOCKING_ANDX: {
184                                                 unload_nls(nls_codepage);
185                                                 return -EAGAIN;
186                                         }
187                                 }
188                         } else {
189                                 up(&tcon->ses->sesSem);
190                         }
191                         unload_nls(nls_codepage);
192
193                 } else {
194                         return -EIO;
195                 }
196         }
197         if(rc)
198                 return rc;
199
200         *request_buf = cifs_small_buf_get();
201         if (*request_buf == NULL) {
202                 /* BB should we add a retry in here if not a writepage? */
203                 return -ENOMEM;
204         }
205
206         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
207
208         if(tcon != NULL)
209                 cifs_stats_inc(&tcon->num_smbs_sent);
210
211         return rc;
212 }
213
214 int
215 small_smb_init_no_tc(const int smb_command, const int wct, 
216                      struct cifsSesInfo *ses, void **request_buf)
217 {
218         int rc;
219         struct smb_hdr * buffer;
220
221         rc = small_smb_init(smb_command, wct, NULL, request_buf);
222         if(rc)
223                 return rc;
224
225         buffer = (struct smb_hdr *)*request_buf;
226         buffer->Mid = GetNextMid(ses->server);
227         if (ses->capabilities & CAP_UNICODE)
228                 buffer->Flags2 |= SMBFLG2_UNICODE;
229         if (ses->capabilities & CAP_STATUS32)
230                 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
231
232         /* uid, tid can stay at zero as set in header assemble */
233
234         /* BB add support for turning on the signing when 
235         this function is used after 1st of session setup requests */
236
237         return rc;
238 }
239
240 /* If the return code is zero, this function must fill in request_buf pointer */
241 static int
242 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
243          void **request_buf /* returned */ ,
244          void **response_buf /* returned */ )
245 {
246         int rc = 0;
247
248         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
249            check for tcp and smb session status done differently
250            for those three - in the calling routine */
251         if(tcon) {
252                 if(tcon->tidStatus == CifsExiting) {
253                         /* only tree disconnect, open, and write,
254                           (and ulogoff which does not have tcon)
255                           are allowed as we start force umount */
256                         if((smb_command != SMB_COM_WRITE_ANDX) &&
257                            (smb_command != SMB_COM_OPEN_ANDX) &&
258                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
259                                 cFYI(1,("can not send cmd %d while umounting",
260                                         smb_command));
261                                 return -ENODEV;
262                         }
263                 }
264
265                 if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
266                                   (tcon->ses->server)){
267                         struct nls_table *nls_codepage;
268                                 /* Give Demultiplex thread up to 10 seconds to
269                                    reconnect, should be greater than cifs socket
270                                    timeout which is 7 seconds */
271                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
272                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
273                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
274                                 if(tcon->ses->server->tcpStatus == 
275                                                 CifsNeedReconnect) {
276                                         /* on "soft" mounts we wait once */
277                                         if((tcon->retry == FALSE) || 
278                                            (tcon->ses->status == CifsExiting)) {
279                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
280                                                 return -EHOSTDOWN;
281                                         } /* else "hard" mount - keep retrying
282                                              until process is killed or server
283                                              comes on-line */
284                                 } else /* TCP session is reestablished now */
285                                         break;
286                                  
287                         }
288                         
289                         nls_codepage = load_nls_default();
290                 /* need to prevent multiple threads trying to
291                 simultaneously reconnect the same SMB session */
292                         down(&tcon->ses->sesSem);
293                         if(tcon->ses->status == CifsNeedReconnect)
294                                 rc = cifs_setup_session(0, tcon->ses, 
295                                                         nls_codepage);
296                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
297                                 mark_open_files_invalid(tcon);
298                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
299                                               tcon, nls_codepage);
300                                 up(&tcon->ses->sesSem);
301                                 /* BB FIXME add code to check if wsize needs
302                                 update due to negotiated smb buffer size
303                                 shrinking */
304                                 if(rc == 0)
305                                         atomic_inc(&tconInfoReconnectCount);
306
307                                 cFYI(1, ("reconnect tcon rc = %d", rc));
308                                 /* Removed call to reopen open files here - 
309                                    it is safer (and faster) to reopen files
310                                    one at a time as needed in read and write */
311
312                                 /* Check if handle based operation so we 
313                                    know whether we can continue or not without
314                                    returning to caller to reset file handle */
315                                 switch(smb_command) {
316                                         case SMB_COM_READ_ANDX:
317                                         case SMB_COM_WRITE_ANDX:
318                                         case SMB_COM_CLOSE:
319                                         case SMB_COM_FIND_CLOSE2:
320                                         case SMB_COM_LOCKING_ANDX: {
321                                                 unload_nls(nls_codepage);
322                                                 return -EAGAIN;
323                                         }
324                                 }
325                         } else {
326                                 up(&tcon->ses->sesSem);
327                         }
328                         unload_nls(nls_codepage);
329
330                 } else {
331                         return -EIO;
332                 }
333         }
334         if(rc)
335                 return rc;
336
337         *request_buf = cifs_buf_get();
338         if (*request_buf == NULL) {
339                 /* BB should we add a retry in here if not a writepage? */
340                 return -ENOMEM;
341         }
342     /* Although the original thought was we needed the response buf for  */
343     /* potential retries of smb operations it turns out we can determine */
344     /* from the mid flags when the request buffer can be resent without  */
345     /* having to use a second distinct buffer for the response */
346         if(response_buf)
347                 *response_buf = *request_buf; 
348
349         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
350                         wct /*wct */ );
351
352         if(tcon != NULL)
353                 cifs_stats_inc(&tcon->num_smbs_sent);
354
355         return rc;
356 }
357
358 static int validate_t2(struct smb_t2_rsp * pSMB) 
359 {
360         int rc = -EINVAL;
361         int total_size;
362         char * pBCC;
363
364         /* check for plausible wct, bcc and t2 data and parm sizes */
365         /* check for parm and data offset going beyond end of smb */
366         if(pSMB->hdr.WordCount >= 10) {
367                 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
368                    (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
369                         /* check that bcc is at least as big as parms + data */
370                         /* check that bcc is less than negotiated smb buffer */
371                         total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
372                         if(total_size < 512) {
373                                 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
374                                 /* BCC le converted in SendReceive */
375                                 pBCC = (pSMB->hdr.WordCount * 2) + 
376                                         sizeof(struct smb_hdr) +
377                                         (char *)pSMB;
378                                 if((total_size <= (*(u16 *)pBCC)) && 
379                                    (total_size < 
380                                         CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
381                                         return 0;
382                                 }
383                                 
384                         }
385                 }
386         }
387         cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
388                 sizeof(struct smb_t2_rsp) + 16);
389         return rc;
390 }
391 int
392 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
393 {
394         NEGOTIATE_REQ *pSMB;
395         NEGOTIATE_RSP *pSMBr;
396         int rc = 0;
397         int bytes_returned;
398         int i;
399         struct TCP_Server_Info * server;
400         u16 count;
401         unsigned int secFlags;
402
403         if(ses->server)
404                 server = ses->server;
405         else {
406                 rc = -EIO;
407                 return rc;
408         }
409         rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
410                       (void **) &pSMB, (void **) &pSMBr);
411         if (rc)
412                 return rc;
413
414         /* if any of auth flags (ie not sign or seal) are overriden use them */
415         if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
416                 secFlags = ses->overrideSecFlg;
417         else /* if override flags set only sign/seal OR them with global auth */
418                 secFlags = extended_security | ses->overrideSecFlg;
419
420         cFYI(1,("secFlags 0x%x",secFlags));
421
422         pSMB->hdr.Mid = GetNextMid(server);
423         pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
424         if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
425                 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
426         
427         count = 0;
428         for(i=0;i<CIFS_NUM_PROT;i++) {
429                 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
430                 count += strlen(protocols[i].name) + 1;
431                 /* null at end of source and target buffers anyway */
432         }
433         pSMB->hdr.smb_buf_length += count;
434         pSMB->ByteCount = cpu_to_le16(count);
435
436         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
437                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
438         if (rc != 0) 
439                 goto neg_err_exit;
440
441         cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
442         /* Check wct = 1 error case */
443         if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
444                 /* core returns wct = 1, but we do not ask for core - otherwise
445                 small wct just comes when dialect index is -1 indicating we 
446                 could not negotiate a common dialect */
447                 rc = -EOPNOTSUPP;
448                 goto neg_err_exit;
449 #ifdef CONFIG_CIFS_WEAK_PW_HASH 
450         } else if((pSMBr->hdr.WordCount == 13)
451                         && ((pSMBr->DialectIndex == LANMAN_PROT)
452                                 || (pSMBr->DialectIndex == LANMAN2_PROT))) {
453                 __s16 tmp;
454                 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
455
456                 if((secFlags & CIFSSEC_MAY_LANMAN) || 
457                         (secFlags & CIFSSEC_MAY_PLNTXT))
458                         server->secType = LANMAN;
459                 else {
460                         cERROR(1, ("mount failed weak security disabled"
461                                    " in /proc/fs/cifs/SecurityFlags"));
462                         rc = -EOPNOTSUPP;
463                         goto neg_err_exit;
464                 }       
465                 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
466                 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
467                 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
468                                 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
469                 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
470                 /* even though we do not use raw we might as well set this
471                 accurately, in case we ever find a need for it */
472                 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
473                         server->maxRw = 0xFF00;
474                         server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
475                 } else {
476                         server->maxRw = 0;/* we do not need to use raw anyway */
477                         server->capabilities = CAP_MPX_MODE;
478                 }
479                 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
480                 if (tmp == -1) {
481                         /* OS/2 often does not set timezone therefore
482                          * we must use server time to calc time zone.
483                          * Could deviate slightly from the right zone.
484                          * Smallest defined timezone difference is 15 minutes
485                          * (i.e. Nepal).  Rounding up/down is done to match
486                          * this requirement.
487                          */
488                         int val, seconds, remain, result;
489                         struct timespec ts, utc;
490                         utc = CURRENT_TIME;
491                         ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
492                                                 le16_to_cpu(rsp->SrvTime.Time));
493                         cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
494                                 (int)ts.tv_sec, (int)utc.tv_sec, 
495                                 (int)(utc.tv_sec - ts.tv_sec)));
496                         val = (int)(utc.tv_sec - ts.tv_sec);
497                         seconds = val < 0 ? -val : val;
498                         result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
499                         remain = seconds % MIN_TZ_ADJ;
500                         if(remain >= (MIN_TZ_ADJ / 2))
501                                 result += MIN_TZ_ADJ;
502                         if(val < 0)
503                                 result = - result;
504                         server->timeAdj = result;
505                 } else {
506                         server->timeAdj = (int)tmp;
507                         server->timeAdj *= 60; /* also in seconds */
508                 }
509                 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
510
511
512                 /* BB get server time for time conversions and add
513                 code to use it and timezone since this is not UTC */    
514
515                 if (rsp->EncryptionKeyLength == 
516                                 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
517                         memcpy(server->cryptKey, rsp->EncryptionKey,
518                                 CIFS_CRYPTO_KEY_SIZE);
519                 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
520                         rc = -EIO; /* need cryptkey unless plain text */
521                         goto neg_err_exit;
522                 }
523
524                 cFYI(1,("LANMAN negotiated"));
525                 /* we will not end up setting signing flags - as no signing
526                 was in LANMAN and server did not return the flags on */
527                 goto signing_check;
528 #else /* weak security disabled */
529         } else if(pSMBr->hdr.WordCount == 13) {
530                 cERROR(1,("mount failed, cifs module not built "
531                           "with CIFS_WEAK_PW_HASH support"));
532                         rc = -EOPNOTSUPP;
533 #endif /* WEAK_PW_HASH */
534                 goto neg_err_exit;
535         } else if(pSMBr->hdr.WordCount != 17) {
536                 /* unknown wct */
537                 rc = -EOPNOTSUPP;
538                 goto neg_err_exit;
539         }
540         /* else wct == 17 NTLM */
541         server->secMode = pSMBr->SecurityMode;
542         if((server->secMode & SECMODE_USER) == 0)
543                 cFYI(1,("share mode security"));
544
545         if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
546 #ifdef CONFIG_CIFS_WEAK_PW_HASH
547                 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
548 #endif /* CIFS_WEAK_PW_HASH */
549                         cERROR(1,("Server requests plain text password"
550                                   " but client support disabled"));
551
552         if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
553                 server->secType = NTLMv2;
554         else if(secFlags & CIFSSEC_MAY_NTLM)
555                 server->secType = NTLM;
556         else if(secFlags & CIFSSEC_MAY_NTLMV2)
557                 server->secType = NTLMv2;
558         /* else krb5 ... any others ... */
559
560         /* one byte, so no need to convert this or EncryptionKeyLen from
561            little endian */
562         server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
563         /* probably no need to store and check maxvcs */
564         server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
565                         (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
566         server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
567         cFYI(0, ("Max buf = %d", ses->server->maxBuf));
568         GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
569         server->capabilities = le32_to_cpu(pSMBr->Capabilities);
570         server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
571         server->timeAdj *= 60;
572         if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
573                 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
574                        CIFS_CRYPTO_KEY_SIZE);
575         } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
576                         && (pSMBr->EncryptionKeyLength == 0)) {
577                 /* decode security blob */
578         } else if (server->secMode & SECMODE_PW_ENCRYPT) {
579                 rc = -EIO; /* no crypt key only if plain text pwd */
580                 goto neg_err_exit;
581         }
582
583         /* BB might be helpful to save off the domain of server here */
584
585         if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
586                 (server->capabilities & CAP_EXTENDED_SECURITY)) {
587                 count = pSMBr->ByteCount;
588                 if (count < 16)
589                         rc = -EIO;
590                 else if (count == 16) {
591                         server->secType = RawNTLMSSP;
592                         if (server->socketUseCount.counter > 1) {
593                                 if (memcmp(server->server_GUID,
594                                            pSMBr->u.extended_response.
595                                            GUID, 16) != 0) {
596                                         cFYI(1, ("server UID changed"));
597                                         memcpy(server->server_GUID,
598                                                 pSMBr->u.extended_response.GUID,
599                                                 16);
600                                 }
601                         } else
602                                 memcpy(server->server_GUID,
603                                        pSMBr->u.extended_response.GUID, 16);
604                 } else {
605                         rc = decode_negTokenInit(pSMBr->u.extended_response.
606                                                  SecurityBlob,
607                                                  count - 16,
608                                                  &server->secType);
609                         if(rc == 1) {
610                         /* BB Need to fill struct for sessetup here */
611                                 rc = -EOPNOTSUPP;
612                         } else {
613                                 rc = -EINVAL;
614                         }
615                 }
616         } else
617                 server->capabilities &= ~CAP_EXTENDED_SECURITY;
618
619 #ifdef CONFIG_CIFS_WEAK_PW_HASH
620 signing_check:
621 #endif
622         if(sign_CIFS_PDUs == FALSE) {        
623                 if(server->secMode & SECMODE_SIGN_REQUIRED)
624                         cERROR(1,("Server requires "
625                                  "/proc/fs/cifs/PacketSigningEnabled to be on"));
626                 server->secMode &= 
627                         ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
628         } else if(sign_CIFS_PDUs == 1) {
629                 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
630                         server->secMode &= 
631                                 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
632         } else if(sign_CIFS_PDUs == 2) {
633                 if((server->secMode & 
634                         (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
635                         cERROR(1,("signing required but server lacks support"));
636                 }
637         }
638 neg_err_exit:   
639         cifs_buf_release(pSMB);
640
641         cFYI(1,("negprot rc %d",rc));
642         return rc;
643 }
644
645 int
646 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
647 {
648         struct smb_hdr *smb_buffer;
649         struct smb_hdr *smb_buffer_response; /* BB removeme BB */
650         int rc = 0;
651         int length;
652
653         cFYI(1, ("In tree disconnect"));
654         /*
655          *  If last user of the connection and
656          *  connection alive - disconnect it
657          *  If this is the last connection on the server session disconnect it
658          *  (and inside session disconnect we should check if tcp socket needs 
659          *  to be freed and kernel thread woken up).
660          */
661         if (tcon)
662                 down(&tcon->tconSem);
663         else
664                 return -EIO;
665
666         atomic_dec(&tcon->useCount);
667         if (atomic_read(&tcon->useCount) > 0) {
668                 up(&tcon->tconSem);
669                 return -EBUSY;
670         }
671
672         /* No need to return error on this operation if tid invalidated and 
673         closed on server already e.g. due to tcp session crashing */
674         if(tcon->tidStatus == CifsNeedReconnect) {
675                 up(&tcon->tconSem);
676                 return 0;  
677         }
678
679         if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {    
680                 up(&tcon->tconSem);
681                 return -EIO;
682         }
683         rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 
684                             (void **)&smb_buffer);
685         if (rc) {
686                 up(&tcon->tconSem);
687                 return rc;
688         } else {
689                 smb_buffer_response = smb_buffer; /* BB removeme BB */
690         }
691         rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
692                          &length, 0);
693         if (rc)
694                 cFYI(1, ("Tree disconnect failed %d", rc));
695
696         if (smb_buffer)
697                 cifs_small_buf_release(smb_buffer);
698         up(&tcon->tconSem);
699
700         /* No need to return error on this operation if tid invalidated and 
701         closed on server already e.g. due to tcp session crashing */
702         if (rc == -EAGAIN)
703                 rc = 0;
704
705         return rc;
706 }
707
708 int
709 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
710 {
711         struct smb_hdr *smb_buffer_response;
712         LOGOFF_ANDX_REQ *pSMB;
713         int rc = 0;
714         int length;
715
716         cFYI(1, ("In SMBLogoff for session disconnect"));
717         if (ses)
718                 down(&ses->sesSem);
719         else
720                 return -EIO;
721
722         atomic_dec(&ses->inUse);
723         if (atomic_read(&ses->inUse) > 0) {
724                 up(&ses->sesSem);
725                 return -EBUSY;
726         }
727         rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
728         if (rc) {
729                 up(&ses->sesSem);
730                 return rc;
731         }
732
733         smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
734         
735         if(ses->server) {
736                 pSMB->hdr.Mid = GetNextMid(ses->server);
737
738                 if(ses->server->secMode & 
739                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
740                         pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
741         }
742
743         pSMB->hdr.Uid = ses->Suid;
744
745         pSMB->AndXCommand = 0xFF;
746         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
747                          smb_buffer_response, &length, 0);
748         if (ses->server) {
749                 atomic_dec(&ses->server->socketUseCount);
750                 if (atomic_read(&ses->server->socketUseCount) == 0) {
751                         spin_lock(&GlobalMid_Lock);
752                         ses->server->tcpStatus = CifsExiting;
753                         spin_unlock(&GlobalMid_Lock);
754                         rc = -ESHUTDOWN;
755                 }
756         }
757         up(&ses->sesSem);
758         cifs_small_buf_release(pSMB);
759
760         /* if session dead then we do not need to do ulogoff,
761                 since server closed smb session, no sense reporting 
762                 error */
763         if (rc == -EAGAIN)
764                 rc = 0;
765         return rc;
766 }
767
768 int
769 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
770                const struct nls_table *nls_codepage, int remap)
771 {
772         DELETE_FILE_REQ *pSMB = NULL;
773         DELETE_FILE_RSP *pSMBr = NULL;
774         int rc = 0;
775         int bytes_returned;
776         int name_len;
777
778 DelFileRetry:
779         rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
780                       (void **) &pSMBr);
781         if (rc)
782                 return rc;
783
784         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
785                 name_len =
786                     cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, 
787                                      PATH_MAX, nls_codepage, remap);
788                 name_len++;     /* trailing null */
789                 name_len *= 2;
790         } else {                /* BB improve check for buffer overruns BB */
791                 name_len = strnlen(fileName, PATH_MAX);
792                 name_len++;     /* trailing null */
793                 strncpy(pSMB->fileName, fileName, name_len);
794         }
795         pSMB->SearchAttributes =
796             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
797         pSMB->BufferFormat = 0x04;
798         pSMB->hdr.smb_buf_length += name_len + 1;
799         pSMB->ByteCount = cpu_to_le16(name_len + 1);
800         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
801                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
802         cifs_stats_inc(&tcon->num_deletes);
803         if (rc) {
804                 cFYI(1, ("Error in RMFile = %d", rc));
805         } 
806
807         cifs_buf_release(pSMB);
808         if (rc == -EAGAIN)
809                 goto DelFileRetry;
810
811         return rc;
812 }
813
814 int
815 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, 
816              const struct nls_table *nls_codepage, int remap)
817 {
818         DELETE_DIRECTORY_REQ *pSMB = NULL;
819         DELETE_DIRECTORY_RSP *pSMBr = NULL;
820         int rc = 0;
821         int bytes_returned;
822         int name_len;
823
824         cFYI(1, ("In CIFSSMBRmDir"));
825 RmDirRetry:
826         rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
827                       (void **) &pSMBr);
828         if (rc)
829                 return rc;
830
831         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
832                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
833                                          PATH_MAX, nls_codepage, remap);
834                 name_len++;     /* trailing null */
835                 name_len *= 2;
836         } else {                /* BB improve check for buffer overruns BB */
837                 name_len = strnlen(dirName, PATH_MAX);
838                 name_len++;     /* trailing null */
839                 strncpy(pSMB->DirName, dirName, name_len);
840         }
841
842         pSMB->BufferFormat = 0x04;
843         pSMB->hdr.smb_buf_length += name_len + 1;
844         pSMB->ByteCount = cpu_to_le16(name_len + 1);
845         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
846                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
847         cifs_stats_inc(&tcon->num_rmdirs);
848         if (rc) {
849                 cFYI(1, ("Error in RMDir = %d", rc));
850         }
851
852         cifs_buf_release(pSMB);
853         if (rc == -EAGAIN)
854                 goto RmDirRetry;
855         return rc;
856 }
857
858 int
859 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
860              const char *name, const struct nls_table *nls_codepage, int remap)
861 {
862         int rc = 0;
863         CREATE_DIRECTORY_REQ *pSMB = NULL;
864         CREATE_DIRECTORY_RSP *pSMBr = NULL;
865         int bytes_returned;
866         int name_len;
867
868         cFYI(1, ("In CIFSSMBMkDir"));
869 MkDirRetry:
870         rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
871                       (void **) &pSMBr);
872         if (rc)
873                 return rc;
874
875         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
876                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, 
877                                             PATH_MAX, nls_codepage, remap);
878                 name_len++;     /* trailing null */
879                 name_len *= 2;
880         } else {                /* BB improve check for buffer overruns BB */
881                 name_len = strnlen(name, PATH_MAX);
882                 name_len++;     /* trailing null */
883                 strncpy(pSMB->DirName, name, name_len);
884         }
885
886         pSMB->BufferFormat = 0x04;
887         pSMB->hdr.smb_buf_length += name_len + 1;
888         pSMB->ByteCount = cpu_to_le16(name_len + 1);
889         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
890                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
891         cifs_stats_inc(&tcon->num_mkdirs);
892         if (rc) {
893                 cFYI(1, ("Error in Mkdir = %d", rc));
894         }
895
896         cifs_buf_release(pSMB);
897         if (rc == -EAGAIN)
898                 goto MkDirRetry;
899         return rc;
900 }
901
902 static __u16 convert_disposition(int disposition)
903 {
904         __u16 ofun = 0;
905
906         switch (disposition) {
907                 case FILE_SUPERSEDE:
908                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
909                         break;
910                 case FILE_OPEN:
911                         ofun = SMBOPEN_OAPPEND;
912                         break;
913                 case FILE_CREATE:
914                         ofun = SMBOPEN_OCREATE;
915                         break;
916                 case FILE_OPEN_IF:
917                         ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
918                         break;
919                 case FILE_OVERWRITE:
920                         ofun = SMBOPEN_OTRUNC;
921                         break;
922                 case FILE_OVERWRITE_IF:
923                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
924                         break;
925                 default:
926                         cFYI(1,("unknown disposition %d",disposition));
927                         ofun =  SMBOPEN_OAPPEND; /* regular open */
928         }
929         return ofun;
930 }
931
932 int
933 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
934             const char *fileName, const int openDisposition,
935             const int access_flags, const int create_options, __u16 * netfid,
936             int *pOplock, FILE_ALL_INFO * pfile_info,
937             const struct nls_table *nls_codepage, int remap)
938 {
939         int rc = -EACCES;
940         OPENX_REQ *pSMB = NULL;
941         OPENX_RSP *pSMBr = NULL;
942         int bytes_returned;
943         int name_len;
944         __u16 count;
945
946 OldOpenRetry:
947         rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
948                       (void **) &pSMBr);
949         if (rc)
950                 return rc;
951
952         pSMB->AndXCommand = 0xFF;       /* none */
953
954         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
955                 count = 1;      /* account for one byte pad to word boundary */
956                 name_len =
957                    cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
958                                     fileName, PATH_MAX, nls_codepage, remap);
959                 name_len++;     /* trailing null */
960                 name_len *= 2;
961         } else {                /* BB improve check for buffer overruns BB */
962                 count = 0;      /* no pad */
963                 name_len = strnlen(fileName, PATH_MAX);
964                 name_len++;     /* trailing null */
965                 strncpy(pSMB->fileName, fileName, name_len);
966         }
967         if (*pOplock & REQ_OPLOCK)
968                 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
969         else if (*pOplock & REQ_BATCHOPLOCK) {
970                 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
971         }
972         pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
973         /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
974         /* 0 = read
975            1 = write
976            2 = rw
977            3 = execute
978         */
979         pSMB->Mode = cpu_to_le16(2);
980         pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
981         /* set file as system file if special file such
982            as fifo and server expecting SFU style and
983            no Unix extensions */
984
985         if(create_options & CREATE_OPTION_SPECIAL)
986                 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
987         else
988                 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
989
990         /* if ((omode & S_IWUGO) == 0)
991                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
992         /*  Above line causes problems due to vfs splitting create into two
993             pieces - need to set mode after file created not while it is
994             being created */
995
996         /* BB FIXME BB */
997 /*      pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
998         /* BB FIXME END BB */
999
1000         pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1001         pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1002         count += name_len;
1003         pSMB->hdr.smb_buf_length += count;
1004
1005         pSMB->ByteCount = cpu_to_le16(count);
1006         /* long_op set to 1 to allow for oplock break timeouts */
1007         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1008                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1009         cifs_stats_inc(&tcon->num_opens);
1010         if (rc) {
1011                 cFYI(1, ("Error in Open = %d", rc));
1012         } else {
1013         /* BB verify if wct == 15 */
1014
1015 /*              *pOplock = pSMBr->OplockLevel; */  /* BB take from action field BB */
1016
1017                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
1018                 /* Let caller know file was created so we can set the mode. */
1019                 /* Do we care about the CreateAction in any other cases? */
1020         /* BB FIXME BB */
1021 /*              if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1022                         *pOplock |= CIFS_CREATE_ACTION; */
1023         /* BB FIXME END */
1024
1025                 if(pfile_info) {
1026                         pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1027                         pfile_info->LastAccessTime = 0; /* BB fixme */
1028                         pfile_info->LastWriteTime = 0; /* BB fixme */
1029                         pfile_info->ChangeTime = 0;  /* BB fixme */
1030                         pfile_info->Attributes =
1031                                 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 
1032                         /* the file_info buf is endian converted by caller */
1033                         pfile_info->AllocationSize =
1034                                 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1035                         pfile_info->EndOfFile = pfile_info->AllocationSize;
1036                         pfile_info->NumberOfLinks = cpu_to_le32(1);
1037                 }
1038         }
1039
1040         cifs_buf_release(pSMB);
1041         if (rc == -EAGAIN)
1042                 goto OldOpenRetry;
1043         return rc;
1044 }
1045
1046 int
1047 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1048             const char *fileName, const int openDisposition,
1049             const int access_flags, const int create_options, __u16 * netfid,
1050             int *pOplock, FILE_ALL_INFO * pfile_info, 
1051             const struct nls_table *nls_codepage, int remap)
1052 {
1053         int rc = -EACCES;
1054         OPEN_REQ *pSMB = NULL;
1055         OPEN_RSP *pSMBr = NULL;
1056         int bytes_returned;
1057         int name_len;
1058         __u16 count;
1059
1060 openRetry:
1061         rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1062                       (void **) &pSMBr);
1063         if (rc)
1064                 return rc;
1065
1066         pSMB->AndXCommand = 0xFF;       /* none */
1067
1068         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1069                 count = 1;      /* account for one byte pad to word boundary */
1070                 name_len =
1071                     cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1072                                      fileName, PATH_MAX, nls_codepage, remap);
1073                 name_len++;     /* trailing null */
1074                 name_len *= 2;
1075                 pSMB->NameLength = cpu_to_le16(name_len);
1076         } else {                /* BB improve check for buffer overruns BB */
1077                 count = 0;      /* no pad */
1078                 name_len = strnlen(fileName, PATH_MAX);
1079                 name_len++;     /* trailing null */
1080                 pSMB->NameLength = cpu_to_le16(name_len);
1081                 strncpy(pSMB->fileName, fileName, name_len);
1082         }
1083         if (*pOplock & REQ_OPLOCK)
1084                 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1085         else if (*pOplock & REQ_BATCHOPLOCK) {
1086                 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1087         }
1088         pSMB->DesiredAccess = cpu_to_le32(access_flags);
1089         pSMB->AllocationSize = 0;
1090         /* set file as system file if special file such
1091            as fifo and server expecting SFU style and
1092            no Unix extensions */
1093         if(create_options & CREATE_OPTION_SPECIAL)
1094                 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1095         else
1096                 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1097         /* XP does not handle ATTR_POSIX_SEMANTICS */
1098         /* but it helps speed up case sensitive checks for other
1099         servers such as Samba */
1100         if (tcon->ses->capabilities & CAP_UNIX)
1101                 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1102
1103         /* if ((omode & S_IWUGO) == 0)
1104                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1105         /*  Above line causes problems due to vfs splitting create into two
1106                 pieces - need to set mode after file created not while it is
1107                 being created */
1108         pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1109         pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1110         pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1111         /* BB Expirement with various impersonation levels and verify */
1112         pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1113         pSMB->SecurityFlags =
1114             SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1115
1116         count += name_len;
1117         pSMB->hdr.smb_buf_length += count;
1118
1119         pSMB->ByteCount = cpu_to_le16(count);
1120         /* long_op set to 1 to allow for oplock break timeouts */
1121         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1122                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1123         cifs_stats_inc(&tcon->num_opens);
1124         if (rc) {
1125                 cFYI(1, ("Error in Open = %d", rc));
1126         } else {
1127                 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1128                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
1129                 /* Let caller know file was created so we can set the mode. */
1130                 /* Do we care about the CreateAction in any other cases? */
1131                 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1132                         *pOplock |= CIFS_CREATE_ACTION; 
1133                 if(pfile_info) {
1134                     memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1135                         36 /* CreationTime to Attributes */);
1136                     /* the file_info buf is endian converted by caller */
1137                     pfile_info->AllocationSize = pSMBr->AllocationSize;
1138                     pfile_info->EndOfFile = pSMBr->EndOfFile;
1139                     pfile_info->NumberOfLinks = cpu_to_le32(1);
1140                 }
1141         }
1142
1143         cifs_buf_release(pSMB);
1144         if (rc == -EAGAIN)
1145                 goto openRetry;
1146         return rc;
1147 }
1148
1149 int
1150 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
1151             const int netfid, const unsigned int count,
1152             const __u64 lseek, unsigned int *nbytes, char **buf,
1153             int * pbuf_type)
1154 {
1155         int rc = -EACCES;
1156         READ_REQ *pSMB = NULL;
1157         READ_RSP *pSMBr = NULL;
1158         char *pReadData = NULL;
1159         int wct;
1160         int resp_buf_type = 0;
1161         struct kvec iov[1];
1162
1163         cFYI(1,("Reading %d bytes on fid %d",count,netfid));
1164         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1165                 wct = 12;
1166         else
1167                 wct = 10; /* old style read */
1168
1169         *nbytes = 0;
1170         rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1171         if (rc)
1172                 return rc;
1173
1174         /* tcon and ses pointer are checked in smb_init */
1175         if (tcon->ses->server == NULL)
1176                 return -ECONNABORTED;
1177
1178         pSMB->AndXCommand = 0xFF;       /* none */
1179         pSMB->Fid = netfid;
1180         pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1181         if(wct == 12)
1182                 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1183         else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1184                 return -EIO;
1185
1186         pSMB->Remaining = 0;
1187         pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1188         pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1189         if(wct == 12)
1190                 pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
1191         else {
1192                 /* old style read */
1193                 struct smb_com_readx_req * pSMBW =
1194                         (struct smb_com_readx_req *)pSMB;
1195                 pSMBW->ByteCount = 0;
1196         }
1197
1198         iov[0].iov_base = (char *)pSMB;
1199         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1200         rc = SendReceive2(xid, tcon->ses, iov, 
1201                           1 /* num iovecs */,
1202                           &resp_buf_type, 0); 
1203         cifs_stats_inc(&tcon->num_reads);
1204         pSMBr = (READ_RSP *)iov[0].iov_base;
1205         if (rc) {
1206                 cERROR(1, ("Send error in read = %d", rc));
1207         } else {
1208                 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1209                 data_length = data_length << 16;
1210                 data_length += le16_to_cpu(pSMBr->DataLength);
1211                 *nbytes = data_length;
1212
1213                 /*check that DataLength would not go beyond end of SMB */
1214                 if ((data_length > CIFSMaxBufSize)
1215                                 || (data_length > count)) {
1216                         cFYI(1,("bad length %d for count %d",data_length,count));
1217                         rc = -EIO;
1218                         *nbytes = 0;
1219                 } else {
1220                         pReadData = (char *) (&pSMBr->hdr.Protocol) +
1221                             le16_to_cpu(pSMBr->DataOffset);
1222 /*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
1223                                 cERROR(1,("Faulting on read rc = %d",rc));
1224                                 rc = -EFAULT;
1225                         }*/ /* can not use copy_to_user when using page cache*/
1226                         if(*buf)
1227                                 memcpy(*buf,pReadData,data_length);
1228                 }
1229         }
1230
1231 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1232         if(*buf) {
1233                 if(resp_buf_type == CIFS_SMALL_BUFFER)
1234                         cifs_small_buf_release(iov[0].iov_base);
1235                 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1236                         cifs_buf_release(iov[0].iov_base);
1237         } else if(resp_buf_type != CIFS_NO_BUFFER) {
1238                 /* return buffer to caller to free */ 
1239                 *buf = iov[0].iov_base;         
1240                 if(resp_buf_type == CIFS_SMALL_BUFFER)
1241                         *pbuf_type = CIFS_SMALL_BUFFER;
1242                 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1243                         *pbuf_type = CIFS_LARGE_BUFFER;
1244         } /* else no valid buffer on return - leave as null */
1245
1246         /* Note: On -EAGAIN error only caller can retry on handle based calls
1247                 since file handle passed in no longer valid */
1248         return rc;
1249 }
1250
1251
1252 int
1253 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1254              const int netfid, const unsigned int count,
1255              const __u64 offset, unsigned int *nbytes, const char *buf,
1256              const char __user * ubuf, const int long_op)
1257 {
1258         int rc = -EACCES;
1259         WRITE_REQ *pSMB = NULL;
1260         WRITE_RSP *pSMBr = NULL;
1261         int bytes_returned, wct;
1262         __u32 bytes_sent;
1263         __u16 byte_count;
1264
1265         /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1266         if(tcon->ses == NULL)
1267                 return -ECONNABORTED;
1268
1269         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1270                 wct = 14;
1271         else
1272                 wct = 12;
1273
1274         rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1275                       (void **) &pSMBr);
1276         if (rc)
1277                 return rc;
1278         /* tcon and ses pointer are checked in smb_init */
1279         if (tcon->ses->server == NULL)
1280                 return -ECONNABORTED;
1281
1282         pSMB->AndXCommand = 0xFF;       /* none */
1283         pSMB->Fid = netfid;
1284         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1285         if(wct == 14) 
1286                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1287         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1288                 return -EIO;
1289         
1290         pSMB->Reserved = 0xFFFFFFFF;
1291         pSMB->WriteMode = 0;
1292         pSMB->Remaining = 0;
1293
1294         /* Can increase buffer size if buffer is big enough in some cases - ie we 
1295         can send more if LARGE_WRITE_X capability returned by the server and if
1296         our buffer is big enough or if we convert to iovecs on socket writes
1297         and eliminate the copy to the CIFS buffer */
1298         if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1299                 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1300         } else {
1301                 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1302                          & ~0xFF;
1303         }
1304
1305         if (bytes_sent > count)
1306                 bytes_sent = count;
1307         pSMB->DataOffset =
1308                 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1309         if(buf)
1310             memcpy(pSMB->Data,buf,bytes_sent);
1311         else if(ubuf) {
1312                 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1313                         cifs_buf_release(pSMB);
1314                         return -EFAULT;
1315                 }
1316         } else if (count != 0) {
1317                 /* No buffer */
1318                 cifs_buf_release(pSMB);
1319                 return -EINVAL;
1320         } /* else setting file size with write of zero bytes */
1321         if(wct == 14)
1322                 byte_count = bytes_sent + 1; /* pad */
1323         else /* wct == 12 */ {
1324                 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1325         }
1326         pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1327         pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1328         pSMB->hdr.smb_buf_length += byte_count;
1329
1330         if(wct == 14)
1331                 pSMB->ByteCount = cpu_to_le16(byte_count);
1332         else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
1333                 struct smb_com_writex_req * pSMBW = 
1334                         (struct smb_com_writex_req *)pSMB;
1335                 pSMBW->ByteCount = cpu_to_le16(byte_count);
1336         }
1337
1338         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1339                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1340         cifs_stats_inc(&tcon->num_writes);
1341         if (rc) {
1342                 cFYI(1, ("Send error in write = %d", rc));
1343                 *nbytes = 0;
1344         } else {
1345                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1346                 *nbytes = (*nbytes) << 16;
1347                 *nbytes += le16_to_cpu(pSMBr->Count);
1348         }
1349
1350         cifs_buf_release(pSMB);
1351
1352         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1353                 since file handle passed in no longer valid */
1354
1355         return rc;
1356 }
1357
1358 int
1359 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1360              const int netfid, const unsigned int count,
1361              const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1362              int n_vec, const int long_op)
1363 {
1364         int rc = -EACCES;
1365         WRITE_REQ *pSMB = NULL;
1366         int wct;
1367         int smb_hdr_len;
1368         int resp_buf_type = 0;
1369
1370         cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1371
1372         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1373                 wct = 14;
1374         else
1375                 wct = 12;
1376         rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1377         if (rc)
1378                 return rc;
1379         /* tcon and ses pointer are checked in smb_init */
1380         if (tcon->ses->server == NULL)
1381                 return -ECONNABORTED;
1382
1383         pSMB->AndXCommand = 0xFF;       /* none */
1384         pSMB->Fid = netfid;
1385         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1386         if(wct == 14)
1387                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1388         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1389                 return -EIO;
1390         pSMB->Reserved = 0xFFFFFFFF;
1391         pSMB->WriteMode = 0;
1392         pSMB->Remaining = 0;
1393
1394         pSMB->DataOffset =
1395             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1396
1397         pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1398         pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1399         smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1400         if(wct == 14)
1401                 pSMB->hdr.smb_buf_length += count+1;
1402         else /* wct == 12 */
1403                 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ 
1404         if(wct == 14)
1405                 pSMB->ByteCount = cpu_to_le16(count + 1);
1406         else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1407                 struct smb_com_writex_req * pSMBW =
1408                                 (struct smb_com_writex_req *)pSMB;
1409                 pSMBW->ByteCount = cpu_to_le16(count + 5);
1410         }
1411         iov[0].iov_base = pSMB;
1412         if(wct == 14)
1413                 iov[0].iov_len = smb_hdr_len + 4;
1414         else /* wct == 12 pad bigger by four bytes */
1415                 iov[0].iov_len = smb_hdr_len + 8;
1416         
1417
1418         rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1419                           long_op);
1420         cifs_stats_inc(&tcon->num_writes);
1421         if (rc) {
1422                 cFYI(1, ("Send error Write2 = %d", rc));
1423                 *nbytes = 0;
1424         } else if(resp_buf_type == 0) {
1425                 /* presumably this can not happen, but best to be safe */
1426                 rc = -EIO;
1427                 *nbytes = 0;
1428         } else {
1429                 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1430                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1431                 *nbytes = (*nbytes) << 16;
1432                 *nbytes += le16_to_cpu(pSMBr->Count);
1433         } 
1434
1435 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1436         if(resp_buf_type == CIFS_SMALL_BUFFER)
1437                 cifs_small_buf_release(iov[0].iov_base);
1438         else if(resp_buf_type == CIFS_LARGE_BUFFER)
1439                 cifs_buf_release(iov[0].iov_base);
1440
1441         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1442                 since file handle passed in no longer valid */
1443
1444         return rc;
1445 }
1446
1447
1448 int
1449 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1450             const __u16 smb_file_id, const __u64 len,
1451             const __u64 offset, const __u32 numUnlock,
1452             const __u32 numLock, const __u8 lockType, const int waitFlag)
1453 {
1454         int rc = 0;
1455         LOCK_REQ *pSMB = NULL;
1456         LOCK_RSP *pSMBr = NULL;
1457         int bytes_returned;
1458         int timeout = 0;
1459         __u16 count;
1460
1461         cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1462         rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1463
1464         if (rc)
1465                 return rc;
1466
1467         pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1468
1469         if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1470                 timeout = -1; /* no response expected */
1471                 pSMB->Timeout = 0;
1472         } else if (waitFlag == TRUE) {
1473                 timeout = 3;  /* blocking operation, no timeout */
1474                 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1475         } else {
1476                 pSMB->Timeout = 0;
1477         }
1478
1479         pSMB->NumberOfLocks = cpu_to_le16(numLock);
1480         pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1481         pSMB->LockType = lockType;
1482         pSMB->AndXCommand = 0xFF;       /* none */
1483         pSMB->Fid = smb_file_id; /* netfid stays le */
1484
1485         if((numLock != 0) || (numUnlock != 0)) {
1486                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1487                 /* BB where to store pid high? */
1488                 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1489                 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1490                 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1491                 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1492                 count = sizeof(LOCKING_ANDX_RANGE);
1493         } else {
1494                 /* oplock break */
1495                 count = 0;
1496         }
1497         pSMB->hdr.smb_buf_length += count;
1498         pSMB->ByteCount = cpu_to_le16(count);
1499
1500         if (waitFlag) {
1501                 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1502                         (struct smb_hdr *) pSMBr, &bytes_returned);
1503         } else {
1504                 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1505                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1506         }
1507         cifs_stats_inc(&tcon->num_locks);
1508         if (rc) {
1509                 cFYI(1, ("Send error in Lock = %d", rc));
1510         }
1511         cifs_small_buf_release(pSMB);
1512
1513         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1514         since file handle passed in no longer valid */
1515         return rc;
1516 }
1517
1518 int
1519 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1520                 const __u16 smb_file_id, const int get_flag, const __u64 len,
1521                 struct file_lock *pLockData, const __u16 lock_type, 
1522                 const int waitFlag)
1523 {
1524         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1525         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1526         char *data_offset;
1527         struct cifs_posix_lock *parm_data;
1528         int rc = 0;
1529         int timeout = 0;
1530         int bytes_returned = 0;
1531         __u16 params, param_offset, offset, byte_count, count;
1532
1533         cFYI(1, ("Posix Lock"));
1534
1535         if(pLockData == NULL)
1536                 return EINVAL;
1537
1538         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1539
1540         if (rc)
1541                 return rc;
1542
1543         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1544
1545         params = 6; 
1546         pSMB->MaxSetupCount = 0;
1547         pSMB->Reserved = 0;
1548         pSMB->Flags = 0;
1549         pSMB->Reserved2 = 0;
1550         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1551         offset = param_offset + params;
1552
1553         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1554
1555         count = sizeof(struct cifs_posix_lock);
1556         pSMB->MaxParameterCount = cpu_to_le16(2);
1557         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1558         pSMB->SetupCount = 1;
1559         pSMB->Reserved3 = 0;
1560         if(get_flag)
1561                 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1562         else
1563                 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1564         byte_count = 3 /* pad */  + params + count;
1565         pSMB->DataCount = cpu_to_le16(count);
1566         pSMB->ParameterCount = cpu_to_le16(params);
1567         pSMB->TotalDataCount = pSMB->DataCount;
1568         pSMB->TotalParameterCount = pSMB->ParameterCount;
1569         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1570         parm_data = (struct cifs_posix_lock *) 
1571                         (((char *) &pSMB->hdr.Protocol) + offset);
1572
1573         parm_data->lock_type = cpu_to_le16(lock_type);
1574         if(waitFlag) {
1575                 timeout = 3;  /* blocking operation, no timeout */
1576                 parm_data->lock_flags = cpu_to_le16(1);
1577                 pSMB->Timeout = cpu_to_le32(-1);
1578         } else
1579                 pSMB->Timeout = 0;
1580
1581         parm_data->pid = cpu_to_le32(current->tgid);
1582         parm_data->start = cpu_to_le64(pLockData->fl_start);
1583         parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
1584
1585         pSMB->DataOffset = cpu_to_le16(offset);
1586         pSMB->Fid = smb_file_id;
1587         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1588         pSMB->Reserved4 = 0;
1589         pSMB->hdr.smb_buf_length += byte_count;
1590         pSMB->ByteCount = cpu_to_le16(byte_count);
1591         if (waitFlag) {
1592                 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1593                         (struct smb_hdr *) pSMBr, &bytes_returned);
1594         } else {
1595                 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1596                         (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1597         }
1598
1599         if (rc) {
1600                 cFYI(1, ("Send error in Posix Lock = %d", rc));
1601         } else if (get_flag) {
1602                 /* lock structure can be returned on get */
1603                 __u16 data_offset;
1604                 __u16 data_count;
1605                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1606
1607                 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1608                         rc = -EIO;      /* bad smb */
1609                         goto plk_err_exit;
1610                 }
1611                 if(pLockData == NULL) {
1612                         rc = -EINVAL;
1613                         goto plk_err_exit;
1614                 }
1615                 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1616                 data_count  = le16_to_cpu(pSMBr->t2.DataCount);
1617                 if(data_count < sizeof(struct cifs_posix_lock)) {
1618                         rc = -EIO;
1619                         goto plk_err_exit;
1620                 }
1621                 parm_data = (struct cifs_posix_lock *)
1622                         ((char *)&pSMBr->hdr.Protocol + data_offset);
1623                 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1624                         pLockData->fl_type = F_UNLCK;
1625         }
1626  
1627 plk_err_exit:
1628         if (pSMB)
1629                 cifs_small_buf_release(pSMB);
1630
1631         /* Note: On -EAGAIN error only caller can retry on handle based calls
1632            since file handle passed in no longer valid */
1633
1634         return rc;
1635 }
1636
1637
1638 int
1639 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1640 {
1641         int rc = 0;
1642         CLOSE_REQ *pSMB = NULL;
1643         CLOSE_RSP *pSMBr = NULL;
1644         int bytes_returned;
1645         cFYI(1, ("In CIFSSMBClose"));
1646
1647 /* do not retry on dead session on close */
1648         rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1649         if(rc == -EAGAIN)
1650                 return 0;
1651         if (rc)
1652                 return rc;
1653
1654         pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1655
1656         pSMB->FileID = (__u16) smb_file_id;
1657         pSMB->LastWriteTime = 0xFFFFFFFF;
1658         pSMB->ByteCount = 0;
1659         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1660                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1661         cifs_stats_inc(&tcon->num_closes);
1662         if (rc) {
1663                 if(rc!=-EINTR) {
1664                         /* EINTR is expected when user ctl-c to kill app */
1665                         cERROR(1, ("Send error in Close = %d", rc));
1666                 }
1667         }
1668
1669         cifs_small_buf_release(pSMB);
1670
1671         /* Since session is dead, file will be closed on server already */
1672         if(rc == -EAGAIN)
1673                 rc = 0;
1674
1675         return rc;
1676 }
1677
1678 int
1679 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1680               const char *fromName, const char *toName,
1681               const struct nls_table *nls_codepage, int remap)
1682 {
1683         int rc = 0;
1684         RENAME_REQ *pSMB = NULL;
1685         RENAME_RSP *pSMBr = NULL;
1686         int bytes_returned;
1687         int name_len, name_len2;
1688         __u16 count;
1689
1690         cFYI(1, ("In CIFSSMBRename"));
1691 renameRetry:
1692         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1693                       (void **) &pSMBr);
1694         if (rc)
1695                 return rc;
1696
1697         pSMB->BufferFormat = 0x04;
1698         pSMB->SearchAttributes =
1699             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1700                         ATTR_DIRECTORY);
1701
1702         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1703                 name_len =
1704                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, 
1705                                      PATH_MAX, nls_codepage, remap);
1706                 name_len++;     /* trailing null */
1707                 name_len *= 2;
1708                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1709         /* protocol requires ASCII signature byte on Unicode string */
1710                 pSMB->OldFileName[name_len + 1] = 0x00;
1711                 name_len2 =
1712                     cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1713                                      toName, PATH_MAX, nls_codepage, remap);
1714                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1715                 name_len2 *= 2; /* convert to bytes */
1716         } else {                /* BB improve the check for buffer overruns BB */
1717                 name_len = strnlen(fromName, PATH_MAX);
1718                 name_len++;     /* trailing null */
1719                 strncpy(pSMB->OldFileName, fromName, name_len);
1720                 name_len2 = strnlen(toName, PATH_MAX);
1721                 name_len2++;    /* trailing null */
1722                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1723                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1724                 name_len2++;    /* trailing null */
1725                 name_len2++;    /* signature byte */
1726         }
1727
1728         count = 1 /* 1st signature byte */  + name_len + name_len2;
1729         pSMB->hdr.smb_buf_length += count;
1730         pSMB->ByteCount = cpu_to_le16(count);
1731
1732         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1733                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1734         cifs_stats_inc(&tcon->num_renames);
1735         if (rc) {
1736                 cFYI(1, ("Send error in rename = %d", rc));
1737         } 
1738
1739         cifs_buf_release(pSMB);
1740
1741         if (rc == -EAGAIN)
1742                 goto renameRetry;
1743
1744         return rc;
1745 }
1746
1747 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
1748                 int netfid, char * target_name, 
1749                 const struct nls_table * nls_codepage, int remap)
1750 {
1751         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1752         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1753         struct set_file_rename * rename_info;
1754         char *data_offset;
1755         char dummy_string[30];
1756         int rc = 0;
1757         int bytes_returned = 0;
1758         int len_of_str;
1759         __u16 params, param_offset, offset, count, byte_count;
1760
1761         cFYI(1, ("Rename to File by handle"));
1762         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1763                         (void **) &pSMBr);
1764         if (rc)
1765                 return rc;
1766
1767         params = 6;
1768         pSMB->MaxSetupCount = 0;
1769         pSMB->Reserved = 0;
1770         pSMB->Flags = 0;
1771         pSMB->Timeout = 0;
1772         pSMB->Reserved2 = 0;
1773         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1774         offset = param_offset + params;
1775
1776         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1777         rename_info = (struct set_file_rename *) data_offset;
1778         pSMB->MaxParameterCount = cpu_to_le16(2);
1779         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1780         pSMB->SetupCount = 1;
1781         pSMB->Reserved3 = 0;
1782         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1783         byte_count = 3 /* pad */  + params;
1784         pSMB->ParameterCount = cpu_to_le16(params);
1785         pSMB->TotalParameterCount = pSMB->ParameterCount;
1786         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1787         pSMB->DataOffset = cpu_to_le16(offset);
1788         /* construct random name ".cifs_tmp<inodenum><mid>" */
1789         rename_info->overwrite = cpu_to_le32(1);
1790         rename_info->root_fid  = 0;
1791         /* unicode only call */
1792         if(target_name == NULL) {
1793                 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1794                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1795                                         dummy_string, 24, nls_codepage, remap);
1796         } else {
1797                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1798                                         target_name, PATH_MAX, nls_codepage, remap);
1799         }
1800         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1801         count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1802         byte_count += count;
1803         pSMB->DataCount = cpu_to_le16(count);
1804         pSMB->TotalDataCount = pSMB->DataCount;
1805         pSMB->Fid = netfid;
1806         pSMB->InformationLevel =
1807                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1808         pSMB->Reserved4 = 0;
1809         pSMB->hdr.smb_buf_length += byte_count;
1810         pSMB->ByteCount = cpu_to_le16(byte_count);
1811         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1812                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1813         cifs_stats_inc(&pTcon->num_t2renames);
1814         if (rc) {
1815                 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1816         }
1817
1818         cifs_buf_release(pSMB);
1819
1820         /* Note: On -EAGAIN error only caller can retry on handle based calls
1821                 since file handle passed in no longer valid */
1822
1823         return rc;
1824 }
1825
1826 int
1827 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
1828             const __u16 target_tid, const char *toName, const int flags,
1829             const struct nls_table *nls_codepage, int remap)
1830 {
1831         int rc = 0;
1832         COPY_REQ *pSMB = NULL;
1833         COPY_RSP *pSMBr = NULL;
1834         int bytes_returned;
1835         int name_len, name_len2;
1836         __u16 count;
1837
1838         cFYI(1, ("In CIFSSMBCopy"));
1839 copyRetry:
1840         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1841                         (void **) &pSMBr);
1842         if (rc)
1843                 return rc;
1844
1845         pSMB->BufferFormat = 0x04;
1846         pSMB->Tid2 = target_tid;
1847
1848         pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1849
1850         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1851                 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, 
1852                                             fromName, PATH_MAX, nls_codepage,
1853                                             remap);
1854                 name_len++;     /* trailing null */
1855                 name_len *= 2;
1856                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1857                 /* protocol requires ASCII signature byte on Unicode string */
1858                 pSMB->OldFileName[name_len + 1] = 0x00;
1859                 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1860                                 toName, PATH_MAX, nls_codepage, remap);
1861                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1862                 name_len2 *= 2; /* convert to bytes */
1863         } else {                /* BB improve the check for buffer overruns BB */
1864                 name_len = strnlen(fromName, PATH_MAX);
1865                 name_len++;     /* trailing null */
1866                 strncpy(pSMB->OldFileName, fromName, name_len);
1867                 name_len2 = strnlen(toName, PATH_MAX);
1868                 name_len2++;    /* trailing null */
1869                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1870                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1871                 name_len2++;    /* trailing null */
1872                 name_len2++;    /* signature byte */
1873         }
1874
1875         count = 1 /* 1st signature byte */  + name_len + name_len2;
1876         pSMB->hdr.smb_buf_length += count;
1877         pSMB->ByteCount = cpu_to_le16(count);
1878
1879         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1880                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1881         if (rc) {
1882                 cFYI(1, ("Send error in copy = %d with %d files copied",
1883                         rc, le16_to_cpu(pSMBr->CopyCount)));
1884         }
1885         if (pSMB)
1886                 cifs_buf_release(pSMB);
1887
1888         if (rc == -EAGAIN)
1889                 goto copyRetry;
1890
1891         return rc;
1892 }
1893
1894 int
1895 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1896                       const char *fromName, const char *toName,
1897                       const struct nls_table *nls_codepage)
1898 {
1899         TRANSACTION2_SPI_REQ *pSMB = NULL;
1900         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1901         char *data_offset;
1902         int name_len;
1903         int name_len_target;
1904         int rc = 0;
1905         int bytes_returned = 0;
1906         __u16 params, param_offset, offset, byte_count;
1907
1908         cFYI(1, ("In Symlink Unix style"));
1909 createSymLinkRetry:
1910         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1911                       (void **) &pSMBr);
1912         if (rc)
1913                 return rc;
1914
1915         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1916                 name_len =
1917                     cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1918                                   /* find define for this maxpathcomponent */
1919                                   , nls_codepage);
1920                 name_len++;     /* trailing null */
1921                 name_len *= 2;
1922
1923         } else {                /* BB improve the check for buffer overruns BB */
1924                 name_len = strnlen(fromName, PATH_MAX);
1925                 name_len++;     /* trailing null */
1926                 strncpy(pSMB->FileName, fromName, name_len);
1927         }
1928         params = 6 + name_len;
1929         pSMB->MaxSetupCount = 0;
1930         pSMB->Reserved = 0;
1931         pSMB->Flags = 0;
1932         pSMB->Timeout = 0;
1933         pSMB->Reserved2 = 0;
1934         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1935                                      InformationLevel) - 4;
1936         offset = param_offset + params;
1937
1938         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1939         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1940                 name_len_target =
1941                     cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1942                                   /* find define for this maxpathcomponent */
1943                                   , nls_codepage);
1944                 name_len_target++;      /* trailing null */
1945                 name_len_target *= 2;
1946         } else {                /* BB improve the check for buffer overruns BB */
1947                 name_len_target = strnlen(toName, PATH_MAX);
1948                 name_len_target++;      /* trailing null */
1949                 strncpy(data_offset, toName, name_len_target);
1950         }
1951
1952         pSMB->MaxParameterCount = cpu_to_le16(2);
1953         /* BB find exact max on data count below from sess */
1954         pSMB->MaxDataCount = cpu_to_le16(1000);
1955         pSMB->SetupCount = 1;
1956         pSMB->Reserved3 = 0;
1957         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1958         byte_count = 3 /* pad */  + params + name_len_target;
1959         pSMB->DataCount = cpu_to_le16(name_len_target);
1960         pSMB->ParameterCount = cpu_to_le16(params);
1961         pSMB->TotalDataCount = pSMB->DataCount;
1962         pSMB->TotalParameterCount = pSMB->ParameterCount;
1963         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1964         pSMB->DataOffset = cpu_to_le16(offset);
1965         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1966         pSMB->Reserved4 = 0;
1967         pSMB->hdr.smb_buf_length += byte_count;
1968         pSMB->ByteCount = cpu_to_le16(byte_count);
1969         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1970                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1971         cifs_stats_inc(&tcon->num_symlinks);
1972         if (rc) {
1973                 cFYI(1,
1974                      ("Send error in SetPathInfo (create symlink) = %d",
1975                       rc));
1976         }
1977
1978         if (pSMB)
1979                 cifs_buf_release(pSMB);
1980
1981         if (rc == -EAGAIN)
1982                 goto createSymLinkRetry;
1983
1984         return rc;
1985 }
1986
1987 int
1988 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1989                        const char *fromName, const char *toName,
1990                        const struct nls_table *nls_codepage, int remap)
1991 {
1992         TRANSACTION2_SPI_REQ *pSMB = NULL;
1993         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1994         char *data_offset;
1995         int name_len;
1996         int name_len_target;
1997         int rc = 0;
1998         int bytes_returned = 0;
1999         __u16 params, param_offset, offset, byte_count;
2000
2001         cFYI(1, ("In Create Hard link Unix style"));
2002 createHardLinkRetry:
2003         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2004                       (void **) &pSMBr);
2005         if (rc)
2006                 return rc;
2007
2008         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2009                 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2010                                             PATH_MAX, nls_codepage, remap);
2011                 name_len++;     /* trailing null */
2012                 name_len *= 2;
2013
2014         } else {                /* BB improve the check for buffer overruns BB */
2015                 name_len = strnlen(toName, PATH_MAX);
2016                 name_len++;     /* trailing null */
2017                 strncpy(pSMB->FileName, toName, name_len);
2018         }
2019         params = 6 + name_len;
2020         pSMB->MaxSetupCount = 0;
2021         pSMB->Reserved = 0;
2022         pSMB->Flags = 0;
2023         pSMB->Timeout = 0;
2024         pSMB->Reserved2 = 0;
2025         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2026                                      InformationLevel) - 4;
2027         offset = param_offset + params;
2028
2029         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2030         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2031                 name_len_target =
2032                     cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2033                                      nls_codepage, remap);
2034                 name_len_target++;      /* trailing null */
2035                 name_len_target *= 2;
2036         } else {                /* BB improve the check for buffer overruns BB */
2037                 name_len_target = strnlen(fromName, PATH_MAX);
2038                 name_len_target++;      /* trailing null */
2039                 strncpy(data_offset, fromName, name_len_target);
2040         }
2041
2042         pSMB->MaxParameterCount = cpu_to_le16(2);
2043         /* BB find exact max on data count below from sess*/
2044         pSMB->MaxDataCount = cpu_to_le16(1000);
2045         pSMB->SetupCount = 1;
2046         pSMB->Reserved3 = 0;
2047         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2048         byte_count = 3 /* pad */  + params + name_len_target;
2049         pSMB->ParameterCount = cpu_to_le16(params);
2050         pSMB->TotalParameterCount = pSMB->ParameterCount;
2051         pSMB->DataCount = cpu_to_le16(name_len_target);
2052         pSMB->TotalDataCount = pSMB->DataCount;
2053         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2054         pSMB->DataOffset = cpu_to_le16(offset);
2055         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2056         pSMB->Reserved4 = 0;
2057         pSMB->hdr.smb_buf_length += byte_count;
2058         pSMB->ByteCount = cpu_to_le16(byte_count);
2059         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2060                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2061         cifs_stats_inc(&tcon->num_hardlinks);
2062         if (rc) {
2063                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2064         }
2065
2066         cifs_buf_release(pSMB);
2067         if (rc == -EAGAIN)
2068                 goto createHardLinkRetry;
2069
2070         return rc;
2071 }
2072
2073 int
2074 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2075                    const char *fromName, const char *toName,
2076                    const struct nls_table *nls_codepage, int remap)
2077 {
2078         int rc = 0;
2079         NT_RENAME_REQ *pSMB = NULL;
2080         RENAME_RSP *pSMBr = NULL;
2081         int bytes_returned;
2082         int name_len, name_len2;
2083         __u16 count;
2084
2085         cFYI(1, ("In CIFSCreateHardLink"));
2086 winCreateHardLinkRetry:
2087
2088         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2089                       (void **) &pSMBr);
2090         if (rc)
2091                 return rc;
2092
2093         pSMB->SearchAttributes =
2094             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2095                         ATTR_DIRECTORY);
2096         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2097         pSMB->ClusterCount = 0;
2098
2099         pSMB->BufferFormat = 0x04;
2100
2101         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2102                 name_len =
2103                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2104                                      PATH_MAX, nls_codepage, remap);
2105                 name_len++;     /* trailing null */
2106                 name_len *= 2;
2107                 pSMB->OldFileName[name_len] = 0;        /* pad */
2108                 pSMB->OldFileName[name_len + 1] = 0x04; 
2109                 name_len2 =
2110                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
2111                                      toName, PATH_MAX, nls_codepage, remap);
2112                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
2113                 name_len2 *= 2; /* convert to bytes */
2114         } else {                /* BB improve the check for buffer overruns BB */
2115                 name_len = strnlen(fromName, PATH_MAX);
2116                 name_len++;     /* trailing null */
2117                 strncpy(pSMB->OldFileName, fromName, name_len);
2118                 name_len2 = strnlen(toName, PATH_MAX);
2119                 name_len2++;    /* trailing null */
2120                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
2121                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2122                 name_len2++;    /* trailing null */
2123                 name_len2++;    /* signature byte */
2124         }
2125
2126         count = 1 /* string type byte */  + name_len + name_len2;
2127         pSMB->hdr.smb_buf_length += count;
2128         pSMB->ByteCount = cpu_to_le16(count);
2129
2130         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2131                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2132         cifs_stats_inc(&tcon->num_hardlinks);
2133         if (rc) {
2134                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2135         }
2136         cifs_buf_release(pSMB);
2137         if (rc == -EAGAIN)
2138                 goto winCreateHardLinkRetry;
2139
2140         return rc;
2141 }
2142
2143 int
2144 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2145                         const unsigned char *searchName,
2146                         char *symlinkinfo, const int buflen,
2147                         const struct nls_table *nls_codepage)
2148 {
2149 /* SMB_QUERY_FILE_UNIX_LINK */
2150         TRANSACTION2_QPI_REQ *pSMB = NULL;
2151         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2152         int rc = 0;
2153         int bytes_returned;
2154         int name_len;
2155         __u16 params, byte_count;
2156
2157         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2158
2159 querySymLinkRetry:
2160         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2161                       (void **) &pSMBr);
2162         if (rc)
2163                 return rc;
2164
2165         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2166                 name_len =
2167                     cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2168                                   /* find define for this maxpathcomponent */
2169                                   , nls_codepage);
2170                 name_len++;     /* trailing null */
2171                 name_len *= 2;
2172         } else {                /* BB improve the check for buffer overruns BB */
2173                 name_len = strnlen(searchName, PATH_MAX);
2174                 name_len++;     /* trailing null */
2175                 strncpy(pSMB->FileName, searchName, name_len);
2176         }
2177
2178         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2179         pSMB->TotalDataCount = 0;
2180         pSMB->MaxParameterCount = cpu_to_le16(2);
2181         /* BB find exact max data count below from sess structure BB */
2182         pSMB->MaxDataCount = cpu_to_le16(4000);
2183         pSMB->MaxSetupCount = 0;
2184         pSMB->Reserved = 0;
2185         pSMB->Flags = 0;
2186         pSMB->Timeout = 0;
2187         pSMB->Reserved2 = 0;
2188         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2189         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2190         pSMB->DataCount = 0;
2191         pSMB->DataOffset = 0;
2192         pSMB->SetupCount = 1;
2193         pSMB->Reserved3 = 0;
2194         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2195         byte_count = params + 1 /* pad */ ;
2196         pSMB->TotalParameterCount = cpu_to_le16(params);
2197         pSMB->ParameterCount = pSMB->TotalParameterCount;
2198         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2199         pSMB->Reserved4 = 0;
2200         pSMB->hdr.smb_buf_length += byte_count;
2201         pSMB->ByteCount = cpu_to_le16(byte_count);
2202
2203         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2204                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2205         if (rc) {
2206                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2207         } else {
2208                 /* decode response */
2209
2210                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2211                 if (rc || (pSMBr->ByteCount < 2))
2212                 /* BB also check enough total bytes returned */
2213                         rc = -EIO;      /* bad smb */
2214                 else {
2215                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2216                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2217
2218                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2219                                 name_len = UniStrnlen((wchar_t *) ((char *)
2220                                         &pSMBr->hdr.Protocol +data_offset),
2221                                         min_t(const int, buflen,count) / 2);
2222                         /* BB FIXME investigate remapping reserved chars here */
2223                                 cifs_strfromUCS_le(symlinkinfo,
2224                                         (__le16 *) ((char *)&pSMBr->hdr.Protocol +
2225                                                 data_offset),
2226                                         name_len, nls_codepage);
2227                         } else {
2228                                 strncpy(symlinkinfo,
2229                                         (char *) &pSMBr->hdr.Protocol + 
2230                                                 data_offset,
2231                                         min_t(const int, buflen, count));
2232                         }
2233                         symlinkinfo[buflen] = 0;
2234         /* just in case so calling code does not go off the end of buffer */
2235                 }
2236         }
2237         cifs_buf_release(pSMB);
2238         if (rc == -EAGAIN)
2239                 goto querySymLinkRetry;
2240         return rc;
2241 }
2242
2243 /* Initialize NT TRANSACT SMB into small smb request buffer.
2244    This assumes that all NT TRANSACTS that we init here have
2245    total parm and data under about 400 bytes (to fit in small cifs
2246    buffer size), which is the case so far, it easily fits. NB:
2247         Setup words themselves and ByteCount
2248         MaxSetupCount (size of returned setup area) and
2249         MaxParameterCount (returned parms size) must be set by caller */
2250 static int 
2251 smb_init_ntransact(const __u16 sub_command, const int setup_count,
2252                    const int parm_len, struct cifsTconInfo *tcon,
2253                    void ** ret_buf)
2254 {
2255         int rc;
2256         __u32 temp_offset;
2257         struct smb_com_ntransact_req * pSMB;
2258
2259         rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2260                                 (void **)&pSMB);
2261         if (rc)
2262                 return rc;
2263         *ret_buf = (void *)pSMB;
2264         pSMB->Reserved = 0;
2265         pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2266         pSMB->TotalDataCount  = 0;
2267         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2268                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2269         pSMB->ParameterCount = pSMB->TotalParameterCount;
2270         pSMB->DataCount  = pSMB->TotalDataCount;
2271         temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2272                         (setup_count * 2) - 4 /* for rfc1001 length itself */;
2273         pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2274         pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2275         pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2276         pSMB->SubCommand = cpu_to_le16(sub_command);
2277         return 0;
2278 }
2279
2280 static int
2281 validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2282                    int * pdatalen, int * pparmlen)
2283 {
2284         char * end_of_smb;
2285         __u32 data_count, data_offset, parm_count, parm_offset;
2286         struct smb_com_ntransact_rsp * pSMBr;
2287
2288         if(buf == NULL)
2289                 return -EINVAL;
2290
2291         pSMBr = (struct smb_com_ntransact_rsp *)buf;
2292
2293         /* ByteCount was converted from little endian in SendReceive */
2294         end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + 
2295                         (char *)&pSMBr->ByteCount;
2296
2297                 
2298         data_offset = le32_to_cpu(pSMBr->DataOffset);
2299         data_count = le32_to_cpu(pSMBr->DataCount);
2300         parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2301         parm_count = le32_to_cpu(pSMBr->ParameterCount);
2302
2303         *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2304         *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2305
2306         /* should we also check that parm and data areas do not overlap? */
2307         if(*ppparm > end_of_smb) {
2308                 cFYI(1,("parms start after end of smb"));
2309                 return -EINVAL;
2310         } else if(parm_count + *ppparm > end_of_smb) {
2311                 cFYI(1,("parm end after end of smb"));
2312                 return -EINVAL;
2313         } else if(*ppdata > end_of_smb) {
2314                 cFYI(1,("data starts after end of smb"));
2315                 return -EINVAL;
2316         } else if(data_count + *ppdata > end_of_smb) {
2317                 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2318                         *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr));  /* BB FIXME */
2319                 return -EINVAL;
2320         } else if(parm_count + data_count > pSMBr->ByteCount) {
2321                 cFYI(1,("parm count and data count larger than SMB"));
2322                 return -EINVAL;
2323         }
2324         return 0;
2325 }
2326
2327 int
2328 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2329                         const unsigned char *searchName,
2330                         char *symlinkinfo, const int buflen,__u16 fid,
2331                         const struct nls_table *nls_codepage)
2332 {
2333         int rc = 0;
2334         int bytes_returned;
2335         int name_len;
2336         struct smb_com_transaction_ioctl_req * pSMB;
2337         struct smb_com_transaction_ioctl_rsp * pSMBr;
2338
2339         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2340         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2341                       (void **) &pSMBr);
2342         if (rc)
2343                 return rc;
2344
2345         pSMB->TotalParameterCount = 0 ;
2346         pSMB->TotalDataCount = 0;
2347         pSMB->MaxParameterCount = cpu_to_le32(2);
2348         /* BB find exact data count max from sess structure BB */
2349         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2350                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2351         pSMB->MaxSetupCount = 4;
2352         pSMB->Reserved = 0;
2353         pSMB->ParameterOffset = 0;
2354         pSMB->DataCount = 0;
2355         pSMB->DataOffset = 0;
2356         pSMB->SetupCount = 4;
2357         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2358         pSMB->ParameterCount = pSMB->TotalParameterCount;
2359         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2360         pSMB->IsFsctl = 1; /* FSCTL */
2361         pSMB->IsRootFlag = 0;
2362         pSMB->Fid = fid; /* file handle always le */
2363         pSMB->ByteCount = 0;
2364
2365         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2366                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2367         if (rc) {
2368                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2369         } else {                /* decode response */
2370                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2371                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2372                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2373                 /* BB also check enough total bytes returned */
2374                         rc = -EIO;      /* bad smb */
2375                 else {
2376                         if(data_count && (data_count < 2048)) {
2377                                 char * end_of_smb = 2 /* sizeof byte count */ +
2378                                                 pSMBr->ByteCount +
2379                                                 (char *)&pSMBr->ByteCount;
2380
2381                                 struct reparse_data * reparse_buf = (struct reparse_data *)
2382                                         ((char *)&pSMBr->hdr.Protocol + data_offset);
2383                                 if((char*)reparse_buf >= end_of_smb) {
2384                                         rc = -EIO;
2385                                         goto qreparse_out;
2386                                 }
2387                                 if((reparse_buf->LinkNamesBuf + 
2388                                         reparse_buf->TargetNameOffset +
2389                                         reparse_buf->TargetNameLen) >
2390                                                 end_of_smb) {
2391                                         cFYI(1,("reparse buf extended beyond SMB"));
2392                                         rc = -EIO;
2393                                         goto qreparse_out;
2394                                 }
2395                                 
2396                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2397                                         name_len = UniStrnlen((wchar_t *)
2398                                                         (reparse_buf->LinkNamesBuf + 
2399                                                         reparse_buf->TargetNameOffset),
2400                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
2401                                         cifs_strfromUCS_le(symlinkinfo,
2402                                                 (__le16 *) (reparse_buf->LinkNamesBuf + 
2403                                                 reparse_buf->TargetNameOffset),
2404                                                 name_len, nls_codepage);
2405                                 } else { /* ASCII names */
2406                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
2407                                                 reparse_buf->TargetNameOffset, 
2408                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
2409                                 }
2410                         } else {
2411                                 rc = -EIO;
2412                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2413                         }
2414                         symlinkinfo[buflen] = 0; /* just in case so the caller
2415                                         does not go off the end of the buffer */
2416                         cFYI(1,("readlink result - %s",symlinkinfo));
2417                 }
2418         }
2419 qreparse_out:
2420         cifs_buf_release(pSMB);
2421
2422         /* Note: On -EAGAIN error only caller can retry on handle based calls
2423                 since file handle passed in no longer valid */
2424
2425         return rc;
2426 }
2427
2428 #ifdef CONFIG_CIFS_POSIX
2429
2430 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2431 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2432 {
2433         /* u8 cifs fields do not need le conversion */
2434         ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2435         ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
2436         ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2437         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2438
2439         return;
2440 }
2441
2442 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2443 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2444                                 const int acl_type,const int size_of_data_area)
2445 {
2446         int size =  0;
2447         int i;
2448         __u16 count;
2449         struct cifs_posix_ace * pACE;
2450         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2451         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2452
2453         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2454                 return -EOPNOTSUPP;
2455
2456         if(acl_type & ACL_TYPE_ACCESS) {
2457                 count = le16_to_cpu(cifs_acl->access_entry_count);
2458                 pACE = &cifs_acl->ace_array[0];
2459                 size = sizeof(struct cifs_posix_acl);
2460                 size += sizeof(struct cifs_posix_ace) * count;
2461                 /* check if we would go beyond end of SMB */
2462                 if(size_of_data_area < size) {
2463                         cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2464                         return -EINVAL;
2465                 }
2466         } else if(acl_type & ACL_TYPE_DEFAULT) {
2467                 count = le16_to_cpu(cifs_acl->access_entry_count);
2468                 size = sizeof(struct cifs_posix_acl);
2469                 size += sizeof(struct cifs_posix_ace) * count;
2470 /* skip past access ACEs to get to default ACEs */
2471                 pACE = &cifs_acl->ace_array[count];
2472                 count = le16_to_cpu(cifs_acl->default_entry_count);
2473                 size += sizeof(struct cifs_posix_ace) * count;
2474                 /* check if we would go beyond end of SMB */
2475                 if(size_of_data_area < size)
2476                         return -EINVAL;
2477         } else {
2478                 /* illegal type */
2479                 return -EINVAL;
2480         }
2481
2482         size = posix_acl_xattr_size(count);
2483         if((buflen == 0) || (local_acl == NULL)) {
2484                 /* used to query ACL EA size */                         
2485         } else if(size > buflen) {
2486                 return -ERANGE;
2487         } else /* buffer big enough */ {
2488                 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2489                 for(i = 0;i < count ;i++) {
2490                         cifs_convert_ace(&local_acl->a_entries[i],pACE);
2491                         pACE ++;
2492                 }
2493         }
2494         return size;
2495 }
2496
2497 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2498                         const posix_acl_xattr_entry * local_ace)
2499 {
2500         __u16 rc = 0; /* 0 = ACL converted ok */
2501
2502         cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2503         cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
2504         /* BB is there a better way to handle the large uid? */
2505         if(local_ace->e_id == cpu_to_le32(-1)) {
2506         /* Probably no need to le convert -1 on any arch but can not hurt */
2507                 cifs_ace->cifs_uid = cpu_to_le64(-1);
2508         } else 
2509                 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2510         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2511         return rc;
2512 }
2513
2514 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2515 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2516                 const int acl_type)
2517 {
2518         __u16 rc = 0;
2519         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2520         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2521         int count;
2522         int i;
2523
2524         if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2525                 return 0;
2526
2527         count = posix_acl_xattr_count((size_t)buflen);
2528         cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2529                 count, buflen, le32_to_cpu(local_acl->a_version)));
2530         if(le32_to_cpu(local_acl->a_version) != 2) {
2531                 cFYI(1,("unknown POSIX ACL version %d",
2532                      le32_to_cpu(local_acl->a_version)));
2533                 return 0;
2534         }
2535         cifs_acl->version = cpu_to_le16(1);
2536         if(acl_type == ACL_TYPE_ACCESS) 
2537                 cifs_acl->access_entry_count = cpu_to_le16(count);
2538         else if(acl_type == ACL_TYPE_DEFAULT)
2539                 cifs_acl->default_entry_count = cpu_to_le16(count);
2540         else {
2541                 cFYI(1,("unknown ACL type %d",acl_type));
2542                 return 0;
2543         }
2544         for(i=0;i<count;i++) {
2545                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2546                                         &local_acl->a_entries[i]);
2547                 if(rc != 0) {
2548                         /* ACE not converted */
2549                         break;
2550                 }
2551         }
2552         if(rc == 0) {
2553                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2554                 rc += sizeof(struct cifs_posix_acl);
2555                 /* BB add check to make sure ACL does not overflow SMB */
2556         }
2557         return rc;
2558 }
2559
2560 int
2561 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2562                         const unsigned char *searchName,
2563                         char *acl_inf, const int buflen, const int acl_type,
2564                         const struct nls_table *nls_codepage, int remap)
2565 {
2566 /* SMB_QUERY_POSIX_ACL */
2567         TRANSACTION2_QPI_REQ *pSMB = NULL;
2568         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2569         int rc = 0;
2570         int bytes_returned;
2571         int name_len;
2572         __u16 params, byte_count;
2573                                                                                                                                              
2574         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2575
2576 queryAclRetry:
2577         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2578                 (void **) &pSMBr);
2579         if (rc)
2580                 return rc;
2581                                                                                                                                              
2582         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2583                 name_len =
2584                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2585                                          PATH_MAX, nls_codepage, remap);
2586                 name_len++;     /* trailing null */
2587                 name_len *= 2;
2588                 pSMB->FileName[name_len] = 0;
2589                 pSMB->FileName[name_len+1] = 0;
2590         } else {                /* BB improve the check for buffer overruns BB */
2591                 name_len = strnlen(searchName, PATH_MAX);
2592                 name_len++;     /* trailing null */
2593                 strncpy(pSMB->FileName, searchName, name_len);
2594         }
2595
2596         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2597         pSMB->TotalDataCount = 0;
2598         pSMB->MaxParameterCount = cpu_to_le16(2);
2599         /* BB find exact max data count below from sess structure BB */
2600         pSMB->MaxDataCount = cpu_to_le16(4000);
2601         pSMB->MaxSetupCount = 0;
2602         pSMB->Reserved = 0;
2603         pSMB->Flags = 0;
2604         pSMB->Timeout = 0;
2605         pSMB->Reserved2 = 0;
2606         pSMB->ParameterOffset = cpu_to_le16(
2607                 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2608         pSMB->DataCount = 0;
2609         pSMB->DataOffset = 0;
2610         pSMB->SetupCount = 1;
2611         pSMB->Reserved3 = 0;
2612         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2613         byte_count = params + 1 /* pad */ ;
2614         pSMB->TotalParameterCount = cpu_to_le16(params);
2615         pSMB->ParameterCount = pSMB->TotalParameterCount;
2616         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2617         pSMB->Reserved4 = 0;
2618         pSMB->hdr.smb_buf_length += byte_count;
2619         pSMB->ByteCount = cpu_to_le16(byte_count);
2620
2621         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2622                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2623         cifs_stats_inc(&tcon->num_acl_get);
2624         if (rc) {
2625                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2626         } else {
2627                 /* decode response */
2628  
2629                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2630                 if (rc || (pSMBr->ByteCount < 2))
2631                 /* BB also check enough total bytes returned */
2632                         rc = -EIO;      /* bad smb */
2633                 else {
2634                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2635                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2636                         rc = cifs_copy_posix_acl(acl_inf,
2637                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2638                                 buflen,acl_type,count);
2639                 }
2640         }
2641         cifs_buf_release(pSMB);
2642         if (rc == -EAGAIN)
2643                 goto queryAclRetry;
2644         return rc;
2645 }
2646
2647 int
2648 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2649                         const unsigned char *fileName,
2650                         const char *local_acl, const int buflen, 
2651                         const int acl_type,
2652                         const struct nls_table *nls_codepage, int remap)
2653 {
2654         struct smb_com_transaction2_spi_req *pSMB = NULL;
2655         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2656         char *parm_data;
2657         int name_len;
2658         int rc = 0;
2659         int bytes_returned = 0;
2660         __u16 params, byte_count, data_count, param_offset, offset;
2661
2662         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2663 setAclRetry:
2664         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2665                       (void **) &pSMBr);
2666         if (rc)
2667                 return rc;
2668         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2669                 name_len =
2670                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
2671                                       PATH_MAX, nls_codepage, remap);
2672                 name_len++;     /* trailing null */
2673                 name_len *= 2;
2674         } else {                /* BB improve the check for buffer overruns BB */
2675                 name_len = strnlen(fileName, PATH_MAX);
2676                 name_len++;     /* trailing null */
2677                 strncpy(pSMB->FileName, fileName, name_len);
2678         }
2679         params = 6 + name_len;
2680         pSMB->MaxParameterCount = cpu_to_le16(2);
2681         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2682         pSMB->MaxSetupCount = 0;
2683         pSMB->Reserved = 0;
2684         pSMB->Flags = 0;
2685         pSMB->Timeout = 0;
2686         pSMB->Reserved2 = 0;
2687         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2688                                      InformationLevel) - 4;
2689         offset = param_offset + params;
2690         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2691         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2692
2693         /* convert to on the wire format for POSIX ACL */
2694         data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2695
2696         if(data_count == 0) {
2697                 rc = -EOPNOTSUPP;
2698                 goto setACLerrorExit;
2699         }
2700         pSMB->DataOffset = cpu_to_le16(offset);
2701         pSMB->SetupCount = 1;
2702         pSMB->Reserved3 = 0;
2703         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2704         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2705         byte_count = 3 /* pad */  + params + data_count;
2706         pSMB->DataCount = cpu_to_le16(data_count);
2707         pSMB->TotalDataCount = pSMB->DataCount;
2708         pSMB->ParameterCount = cpu_to_le16(params);
2709         pSMB->TotalParameterCount = pSMB->ParameterCount;
2710         pSMB->Reserved4 = 0;
2711         pSMB->hdr.smb_buf_length += byte_count;
2712         pSMB->ByteCount = cpu_to_le16(byte_count);
2713         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2714                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2715         if (rc) {
2716                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2717         }
2718
2719 setACLerrorExit:
2720         cifs_buf_release(pSMB);
2721         if (rc == -EAGAIN)
2722                 goto setAclRetry;
2723         return rc;
2724 }
2725
2726 /* BB fix tabs in this function FIXME BB */
2727 int
2728 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2729                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2730 {
2731         int rc = 0;
2732         struct smb_t2_qfi_req *pSMB = NULL;
2733         struct smb_t2_qfi_rsp *pSMBr = NULL;
2734         int bytes_returned;
2735         __u16 params, byte_count;
2736
2737         cFYI(1,("In GetExtAttr"));
2738         if(tcon == NULL)
2739                 return -ENODEV;
2740
2741 GetExtAttrRetry:
2742         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2743                       (void **) &pSMBr);
2744         if (rc)
2745                 return rc;
2746
2747         params = 2 /* level */ +2 /* fid */;
2748         pSMB->t2.TotalDataCount = 0;
2749         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2750         /* BB find exact max data count below from sess structure BB */
2751         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2752         pSMB->t2.MaxSetupCount = 0;
2753         pSMB->t2.Reserved = 0;
2754         pSMB->t2.Flags = 0;
2755         pSMB->t2.Timeout = 0;
2756         pSMB->t2.Reserved2 = 0;
2757         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2758                         Fid) - 4);
2759         pSMB->t2.DataCount = 0;
2760         pSMB->t2.DataOffset = 0;
2761         pSMB->t2.SetupCount = 1;
2762         pSMB->t2.Reserved3 = 0;
2763         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2764         byte_count = params + 1 /* pad */ ;
2765         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2766         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2767         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2768         pSMB->Pad = 0;
2769         pSMB->Fid = netfid;
2770         pSMB->hdr.smb_buf_length += byte_count;
2771         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2772
2773         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2774                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2775         if (rc) {
2776                 cFYI(1, ("error %d in GetExtAttr", rc));
2777         } else {
2778                 /* decode response */
2779                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2780                 if (rc || (pSMBr->ByteCount < 2))
2781                 /* BB also check enough total bytes returned */
2782                         /* If rc should we check for EOPNOSUPP and
2783                         disable the srvino flag? or in caller? */
2784                         rc = -EIO;      /* bad smb */
2785                 else {
2786                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2787                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2788                         struct file_chattr_info * pfinfo;
2789                         /* BB Do we need a cast or hash here ? */
2790                         if(count != 16) {
2791                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
2792                                 rc = -EIO;
2793                                 goto GetExtAttrOut;
2794                         }
2795                         pfinfo = (struct file_chattr_info *)
2796                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2797                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2798                         *pMask = le64_to_cpu(pfinfo->mask);
2799                 }
2800         }
2801 GetExtAttrOut:
2802         cifs_buf_release(pSMB);
2803         if (rc == -EAGAIN)
2804                 goto GetExtAttrRetry;
2805         return rc;
2806 }
2807
2808
2809 #endif /* CONFIG_POSIX */
2810
2811
2812 /* security id for everyone */
2813 const static struct cifs_sid sid_everyone = 
2814                 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2815 /* group users */
2816 const static struct cifs_sid sid_user = 
2817                 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2818
2819 /* Convert CIFS ACL to POSIX form */
2820 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2821 {
2822         return 0;
2823 }
2824
2825 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2826 int
2827 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2828          /*  BB fix up return info */ char *acl_inf, const int buflen, 
2829                   const int acl_type /* ACCESS/DEFAULT not sure implication */)
2830 {
2831         int rc = 0;
2832         int buf_type = 0;
2833         QUERY_SEC_DESC_REQ * pSMB;
2834         struct kvec iov[1];
2835
2836         cFYI(1, ("GetCifsACL"));
2837
2838         rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 
2839                         8 /* parm len */, tcon, (void **) &pSMB);
2840         if (rc)
2841                 return rc;
2842
2843         pSMB->MaxParameterCount = cpu_to_le32(4);
2844         /* BB TEST with big acls that might need to be e.g. larger than 16K */
2845         pSMB->MaxSetupCount = 0;
2846         pSMB->Fid = fid; /* file handle always le */
2847         pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2848                                      CIFS_ACL_DACL);
2849         pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2850         pSMB->hdr.smb_buf_length += 11;
2851         iov[0].iov_base = (char *)pSMB;
2852         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2853
2854         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2855         cifs_stats_inc(&tcon->num_acl_get);
2856         if (rc) {
2857                 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2858         } else {                /* decode response */
2859                 struct cifs_sid * psec_desc;
2860                 __le32 * parm;
2861                 int parm_len;
2862                 int data_len;
2863                 int acl_len;
2864                 struct smb_com_ntransact_rsp * pSMBr;
2865
2866 /* validate_nttransact */
2867                 rc = validate_ntransact(iov[0].iov_base, (char **)&parm, 
2868                                         (char **)&psec_desc,
2869                                         &parm_len, &data_len);
2870                 
2871                 if(rc)
2872                         goto qsec_out;
2873                 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2874
2875                 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc));  /* BB removeme BB */
2876
2877                 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2878                         rc = -EIO;      /* bad smb */
2879                         goto qsec_out;
2880                 }
2881
2882 /* BB check that data area is minimum length and as big as acl_len */
2883
2884                 acl_len = le32_to_cpu(*(__le32 *)parm);
2885                 /* BB check if(acl_len > bufsize) */
2886
2887                 parse_sec_desc(psec_desc, acl_len);
2888         }
2889 qsec_out:
2890         if(buf_type == CIFS_SMALL_BUFFER)
2891                 cifs_small_buf_release(iov[0].iov_base);
2892         else if(buf_type == CIFS_LARGE_BUFFER)
2893                 cifs_buf_release(iov[0].iov_base);
2894 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2895         return rc;
2896 }
2897
2898 /* Legacy Query Path Information call for lookup to old servers such
2899    as Win9x/WinME */
2900 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2901                  const unsigned char *searchName,
2902                  FILE_ALL_INFO * pFinfo,
2903                  const struct nls_table *nls_codepage, int remap)
2904 {
2905         QUERY_INFORMATION_REQ * pSMB;
2906         QUERY_INFORMATION_RSP * pSMBr;
2907         int rc = 0;
2908         int bytes_returned;
2909         int name_len;
2910
2911         cFYI(1, ("In SMBQPath path %s", searchName)); 
2912 QInfRetry:
2913         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2914                       (void **) &pSMBr);
2915         if (rc)
2916                 return rc;
2917
2918         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2919                 name_len =
2920                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2921                                      PATH_MAX, nls_codepage, remap);
2922                 name_len++;     /* trailing null */
2923                 name_len *= 2;
2924         } else {               
2925                 name_len = strnlen(searchName, PATH_MAX);
2926                 name_len++;     /* trailing null */
2927                 strncpy(pSMB->FileName, searchName, name_len);
2928         }
2929         pSMB->BufferFormat = 0x04;
2930         name_len++; /* account for buffer type byte */  
2931         pSMB->hdr.smb_buf_length += (__u16) name_len;
2932         pSMB->ByteCount = cpu_to_le16(name_len);
2933
2934         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2935                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2936         if (rc) {
2937                 cFYI(1, ("Send error in QueryInfo = %d", rc));
2938         } else if (pFinfo) {            /* decode response */
2939                 struct timespec ts;
2940                 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2941                 /* BB FIXME - add time zone adjustment BB */
2942                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2943                 ts.tv_nsec = 0;
2944                 ts.tv_sec = time;
2945                 /* decode time fields */
2946                 pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
2947                 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2948                 pFinfo->LastAccessTime = 0;
2949                 pFinfo->AllocationSize =
2950                         cpu_to_le64(le32_to_cpu(pSMBr->size));
2951                 pFinfo->EndOfFile = pFinfo->AllocationSize;
2952                 pFinfo->Attributes =
2953                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
2954         } else
2955                 rc = -EIO; /* bad buffer passed in */
2956
2957         cifs_buf_release(pSMB);
2958
2959         if (rc == -EAGAIN)
2960                 goto QInfRetry;
2961
2962         return rc;
2963 }
2964
2965
2966
2967
2968 int
2969 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2970                  const unsigned char *searchName,
2971                  FILE_ALL_INFO * pFindData,
2972                  int legacy /* old style infolevel */,
2973                  const struct nls_table *nls_codepage, int remap)
2974 {
2975 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2976         TRANSACTION2_QPI_REQ *pSMB = NULL;
2977         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2978         int rc = 0;
2979         int bytes_returned;
2980         int name_len;
2981         __u16 params, byte_count;
2982
2983 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2984 QPathInfoRetry:
2985         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2986                       (void **) &pSMBr);
2987         if (rc)
2988                 return rc;
2989
2990         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2991                 name_len =
2992                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2993                                      PATH_MAX, nls_codepage, remap);
2994                 name_len++;     /* trailing null */
2995                 name_len *= 2;
2996         } else {                /* BB improve the check for buffer overruns BB */
2997                 name_len = strnlen(searchName, PATH_MAX);
2998                 name_len++;     /* trailing null */
2999                 strncpy(pSMB->FileName, searchName, name_len);
3000         }
3001
3002         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3003         pSMB->TotalDataCount = 0;
3004         pSMB->MaxParameterCount = cpu_to_le16(2);
3005         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3006         pSMB->MaxSetupCount = 0;
3007         pSMB->Reserved = 0;
3008         pSMB->Flags = 0;
3009         pSMB->Timeout = 0;
3010         pSMB->Reserved2 = 0;
3011         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3012         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3013         pSMB->DataCount = 0;
3014         pSMB->DataOffset = 0;
3015         pSMB->SetupCount = 1;
3016         pSMB->Reserved3 = 0;
3017         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3018         byte_count = params + 1 /* pad */ ;
3019         pSMB->TotalParameterCount = cpu_to_le16(params);
3020         pSMB->ParameterCount = pSMB->TotalParameterCount;
3021         if(legacy)
3022                 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3023         else
3024                 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3025         pSMB->Reserved4 = 0;
3026         pSMB->hdr.smb_buf_length += byte_count;
3027         pSMB->ByteCount = cpu_to_le16(byte_count);
3028
3029         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3030                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3031         if (rc) {
3032                 cFYI(1, ("Send error in QPathInfo = %d", rc));
3033         } else {                /* decode response */
3034                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3035
3036                 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3037                         rc = -EIO;
3038                 else if (!legacy && (pSMBr->ByteCount < 40)) 
3039                         rc = -EIO;      /* bad smb */
3040                 else if(legacy && (pSMBr->ByteCount < 24))
3041                         rc = -EIO;  /* 24 or 26 expected but we do not read last field */
3042                 else if (pFindData){
3043                         int size;
3044                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3045                         if(legacy) /* we do not read the last field, EAsize, fortunately
3046                                            since it varies by subdialect and on Set vs. Get, is  
3047                                            two bytes or 4 bytes depending but we don't care here */
3048                                 size = sizeof(FILE_INFO_STANDARD);
3049                         else
3050                                 size = sizeof(FILE_ALL_INFO);
3051                         memcpy((char *) pFindData,
3052                                (char *) &pSMBr->hdr.Protocol +
3053                                data_offset, size);
3054                 } else
3055                     rc = -ENOMEM;
3056         }
3057         cifs_buf_release(pSMB);
3058         if (rc == -EAGAIN)
3059                 goto QPathInfoRetry;
3060
3061         return rc;
3062 }
3063
3064 int
3065 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3066                      const unsigned char *searchName,
3067                      FILE_UNIX_BASIC_INFO * pFindData,
3068                      const struct nls_table *nls_codepage, int remap)
3069 {
3070 /* SMB_QUERY_FILE_UNIX_BASIC */
3071         TRANSACTION2_QPI_REQ *pSMB = NULL;
3072         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3073         int rc = 0;
3074         int bytes_returned = 0;
3075         int name_len;
3076         __u16 params, byte_count;
3077
3078         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3079 UnixQPathInfoRetry:
3080         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3081                       (void **) &pSMBr);
3082         if (rc)
3083                 return rc;
3084
3085         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3086                 name_len =
3087                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3088                                   PATH_MAX, nls_codepage, remap);
3089                 name_len++;     /* trailing null */
3090                 name_len *= 2;
3091         } else {                /* BB improve the check for buffer overruns BB */
3092                 name_len = strnlen(searchName, PATH_MAX);
3093                 name_len++;     /* trailing null */
3094                 strncpy(pSMB->FileName, searchName, name_len);
3095         }
3096
3097         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3098         pSMB->TotalDataCount = 0;
3099         pSMB->MaxParameterCount = cpu_to_le16(2);
3100         /* BB find exact max SMB PDU from sess structure BB */
3101         pSMB->MaxDataCount = cpu_to_le16(4000); 
3102         pSMB->MaxSetupCount = 0;
3103         pSMB->Reserved = 0;
3104         pSMB->Flags = 0;
3105         pSMB->Timeout = 0;
3106         pSMB->Reserved2 = 0;
3107         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3108         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3109         pSMB->DataCount = 0;
3110         pSMB->DataOffset = 0;
3111         pSMB->SetupCount = 1;
3112         pSMB->Reserved3 = 0;
3113         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3114         byte_count = params + 1 /* pad */ ;
3115         pSMB->TotalParameterCount = cpu_to_le16(params);
3116         pSMB->ParameterCount = pSMB->TotalParameterCount;
3117         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3118         pSMB->Reserved4 = 0;
3119         pSMB->hdr.smb_buf_length += byte_count;
3120         pSMB->ByteCount = cpu_to_le16(byte_count);
3121
3122         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3123                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3124         if (rc) {
3125                 cFYI(1, ("Send error in QPathInfo = %d", rc));
3126         } else {                /* decode response */
3127                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3128
3129                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3130                         rc = -EIO;      /* bad smb */
3131                 } else {
3132                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3133                         memcpy((char *) pFindData,
3134                                (char *) &pSMBr->hdr.Protocol +
3135                                data_offset,
3136                                sizeof (FILE_UNIX_BASIC_INFO));
3137                 }
3138         }
3139         cifs_buf_release(pSMB);
3140         if (rc == -EAGAIN)
3141                 goto UnixQPathInfoRetry;
3142
3143         return rc;
3144 }
3145
3146 #if 0  /* function unused at present */
3147 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3148                const char *searchName, FILE_ALL_INFO * findData,
3149                const struct nls_table *nls_codepage)
3150 {
3151 /* level 257 SMB_ */
3152         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3153         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3154         int rc = 0;
3155         int bytes_returned;
3156         int name_len;
3157         __u16 params, byte_count;
3158
3159         cFYI(1, ("In FindUnique"));
3160 findUniqueRetry:
3161         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3162                       (void **) &pSMBr);
3163         if (rc)
3164                 return rc;
3165
3166         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3167                 name_len =
3168                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
3169                                   /* find define for this maxpathcomponent */
3170                                   , nls_codepage);
3171                 name_len++;     /* trailing null */
3172                 name_len *= 2;
3173         } else {                /* BB improve the check for buffer overruns BB */
3174                 name_len = strnlen(searchName, PATH_MAX);
3175                 name_len++;     /* trailing null */
3176                 strncpy(pSMB->FileName, searchName, name_len);
3177         }
3178
3179         params = 12 + name_len /* includes null */ ;
3180         pSMB->TotalDataCount = 0;       /* no EAs */
3181         pSMB->MaxParameterCount = cpu_to_le16(2);
3182         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3183         pSMB->MaxSetupCount = 0;
3184         pSMB->Reserved = 0;
3185         pSMB->Flags = 0;
3186         pSMB->Timeout = 0;
3187         pSMB->Reserved2 = 0;
3188         pSMB->ParameterOffset = cpu_to_le16(
3189          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3190         pSMB->DataCount = 0;
3191         pSMB->DataOffset = 0;
3192         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
3193         pSMB->Reserved3 = 0;
3194         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3195         byte_count = params + 1 /* pad */ ;
3196         pSMB->TotalParameterCount = cpu_to_le16(params);
3197         pSMB->ParameterCount = pSMB->TotalParameterCount;
3198         pSMB->SearchAttributes =
3199             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3200                         ATTR_DIRECTORY);
3201         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
3202         pSMB->SearchFlags = cpu_to_le16(1);
3203         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3204         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
3205         pSMB->hdr.smb_buf_length += byte_count;
3206         pSMB->ByteCount = cpu_to_le16(byte_count);
3207
3208         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3209                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3210
3211         if (rc) {
3212                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3213         } else {                /* decode response */
3214                 cifs_stats_inc(&tcon->num_ffirst);
3215                 /* BB fill in */
3216         }
3217
3218         cifs_buf_release(pSMB);
3219         if (rc == -EAGAIN)
3220                 goto findUniqueRetry;
3221
3222         return rc;
3223 }
3224 #endif /* end unused (temporarily) function */
3225
3226 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3227 int
3228 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3229               const char *searchName, 
3230               const struct nls_table *nls_codepage,
3231               __u16 *   pnetfid,
3232               struct cifs_search_info * psrch_inf, int remap, const char dirsep)
3233 {
3234 /* level 257 SMB_ */
3235         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3236         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3237         T2_FFIRST_RSP_PARMS * parms;
3238         int rc = 0;
3239         int bytes_returned = 0;
3240         int name_len;
3241         __u16 params, byte_count;
3242
3243         cFYI(1, ("In FindFirst for %s",searchName));
3244
3245 findFirstRetry:
3246         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3247                       (void **) &pSMBr);
3248         if (rc)
3249                 return rc;
3250
3251         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3252                 name_len =
3253                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
3254                                  PATH_MAX, nls_codepage, remap);
3255                 /* We can not add the asterik earlier in case
3256                 it got remapped to 0xF03A as if it were part of the
3257                 directory name instead of a wildcard */
3258                 name_len *= 2;
3259                 pSMB->FileName[name_len] = dirsep;
3260                 pSMB->FileName[name_len+1] = 0;
3261                 pSMB->FileName[name_len+2] = '*';
3262                 pSMB->FileName[name_len+3] = 0;
3263                 name_len += 4; /* now the trailing null */
3264                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3265                 pSMB->FileName[name_len+1] = 0;
3266                 name_len += 2;
3267         } else {        /* BB add check for overrun of SMB buf BB */
3268                 name_len = strnlen(searchName, PATH_MAX);
3269 /* BB fix here and in unicode clause above ie
3270                 if(name_len > buffersize-header)
3271                         free buffer exit; BB */
3272                 strncpy(pSMB->FileName, searchName, name_len);
3273                 pSMB->FileName[name_len] = dirsep;
3274                 pSMB->FileName[name_len+1] = '*';
3275                 pSMB->FileName[name_len+2] = 0;
3276                 name_len += 3;
3277         }
3278
3279         params = 12 + name_len /* includes null */ ;
3280         pSMB->TotalDataCount = 0;       /* no EAs */
3281         pSMB->MaxParameterCount = cpu_to_le16(10);
3282         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3283                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3284         pSMB->MaxSetupCount = 0;
3285         pSMB->Reserved = 0;
3286         pSMB->Flags = 0;
3287         pSMB->Timeout = 0;
3288         pSMB->Reserved2 = 0;
3289         byte_count = params + 1 /* pad */ ;
3290         pSMB->TotalParameterCount = cpu_to_le16(params);
3291         pSMB->ParameterCount = pSMB->TotalParameterCount;
3292         pSMB->ParameterOffset = cpu_to_le16(
3293               offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3294                 - 4);
3295         pSMB->DataCount = 0;
3296         pSMB->DataOffset = 0;
3297         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
3298         pSMB->Reserved3 = 0;
3299         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3300         pSMB->SearchAttributes =
3301             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3302                         ATTR_DIRECTORY);
3303         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3304         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
3305                 CIFS_SEARCH_RETURN_RESUME);
3306         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3307
3308         /* BB what should we set StorageType to? Does it matter? BB */
3309         pSMB->SearchStorageType = 0;
3310         pSMB->hdr.smb_buf_length += byte_count;
3311         pSMB->ByteCount = cpu_to_le16(byte_count);
3312
3313         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3314                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3315         cifs_stats_inc(&tcon->num_ffirst);
3316
3317         if (rc) {/* BB add logic to retry regular search if Unix search
3318                         rejected unexpectedly by server */
3319                 /* BB Add code to handle unsupported level rc */
3320                 cFYI(1, ("Error in FindFirst = %d", rc));
3321
3322                 cifs_buf_release(pSMB);
3323
3324                 /* BB eventually could optimize out free and realloc of buf */
3325                 /*    for this case */
3326                 if (rc == -EAGAIN)
3327                         goto findFirstRetry;
3328         } else { /* decode response */
3329                 /* BB remember to free buffer if error BB */
3330                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3331                 if(rc == 0) {
3332                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3333                                 psrch_inf->unicode = TRUE;
3334                         else
3335                                 psrch_inf->unicode = FALSE;
3336
3337                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3338                         psrch_inf->smallBuf = 0;
3339                         psrch_inf->srch_entries_start = 
3340                                 (char *) &pSMBr->hdr.Protocol + 
3341                                         le16_to_cpu(pSMBr->t2.DataOffset);
3342                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3343                                le16_to_cpu(pSMBr->t2.ParameterOffset));
3344
3345                         if(parms->EndofSearch)
3346                                 psrch_inf->endOfSearch = TRUE;
3347                         else
3348                                 psrch_inf->endOfSearch = FALSE;
3349
3350                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3351                         psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3352                                 psrch_inf->entries_in_buffer;
3353                         *pnetfid = parms->SearchHandle;
3354                 } else {
3355                         cifs_buf_release(pSMB);
3356                 }
3357         }
3358
3359         return rc;
3360 }
3361
3362 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3363             __u16 searchHandle, struct cifs_search_info * psrch_inf)
3364 {
3365         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3366         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3367         T2_FNEXT_RSP_PARMS * parms;
3368         char *response_data;
3369         int rc = 0;
3370         int bytes_returned, name_len;
3371         __u16 params, byte_count;
3372
3373         cFYI(1, ("In FindNext"));
3374
3375         if(psrch_inf->endOfSearch == TRUE)
3376                 return -ENOENT;
3377
3378         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3379                 (void **) &pSMBr);
3380         if (rc)
3381                 return rc;
3382
3383         params = 14;    /* includes 2 bytes of null string, converted to LE below */
3384         byte_count = 0;
3385         pSMB->TotalDataCount = 0;       /* no EAs */
3386         pSMB->MaxParameterCount = cpu_to_le16(8);
3387         pSMB->MaxDataCount =
3388             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3389         pSMB->MaxSetupCount = 0;
3390         pSMB->Reserved = 0;
3391         pSMB->Flags = 0;
3392         pSMB->Timeout = 0;
3393         pSMB->Reserved2 = 0;
3394         pSMB->ParameterOffset =  cpu_to_le16(
3395               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3396         pSMB->DataCount = 0;
3397         pSMB->DataOffset = 0;
3398         pSMB->SetupCount = 1;
3399         pSMB->Reserved3 = 0;
3400         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3401         pSMB->SearchHandle = searchHandle;      /* always kept as le */
3402         pSMB->SearchCount =
3403                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3404         /* test for Unix extensions */
3405 /*      if (tcon->ses->capabilities & CAP_UNIX) {
3406                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3407                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3408         } else {
3409                 pSMB->InformationLevel =
3410                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3411                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3412         } */
3413         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3414         pSMB->ResumeKey = psrch_inf->resume_key;
3415         pSMB->SearchFlags =
3416               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3417
3418         name_len = psrch_inf->resume_name_len;
3419         params += name_len;
3420         if(name_len < PATH_MAX) {
3421                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3422                 byte_count += name_len;
3423                 /* 14 byte parm len above enough for 2 byte null terminator */
3424                 pSMB->ResumeFileName[name_len] = 0;
3425                 pSMB->ResumeFileName[name_len+1] = 0;
3426         } else {
3427                 rc = -EINVAL;
3428                 goto FNext2_err_exit;
3429         }
3430         byte_count = params + 1 /* pad */ ;
3431         pSMB->TotalParameterCount = cpu_to_le16(params);
3432         pSMB->ParameterCount = pSMB->TotalParameterCount;
3433         pSMB->hdr.smb_buf_length += byte_count;
3434         pSMB->ByteCount = cpu_to_le16(byte_count);
3435                                                                                               
3436         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3437                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3438         cifs_stats_inc(&tcon->num_fnext);
3439         if (rc) {
3440                 if (rc == -EBADF) {
3441                         psrch_inf->endOfSearch = TRUE;
3442                         rc = 0; /* search probably was closed at end of search above */
3443                 } else
3444                         cFYI(1, ("FindNext returned = %d", rc));
3445         } else {                /* decode response */
3446                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3447                 
3448                 if(rc == 0) {
3449                         /* BB fixme add lock for file (srch_info) struct here */
3450                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3451                                 psrch_inf->unicode = TRUE;
3452                         else
3453                                 psrch_inf->unicode = FALSE;
3454                         response_data = (char *) &pSMBr->hdr.Protocol +
3455                                le16_to_cpu(pSMBr->t2.ParameterOffset);
3456                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
3457                         response_data = (char *)&pSMBr->hdr.Protocol +
3458                                 le16_to_cpu(pSMBr->t2.DataOffset);
3459                         if(psrch_inf->smallBuf)
3460                                 cifs_small_buf_release(
3461                                         psrch_inf->ntwrk_buf_start);
3462                         else
3463                                 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3464                         psrch_inf->srch_entries_start = response_data;
3465                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
3466                         psrch_inf->smallBuf = 0;
3467                         if(parms->EndofSearch)
3468                                 psrch_inf->endOfSearch = TRUE;
3469                         else
3470                                 psrch_inf->endOfSearch = FALSE;
3471                                                                                               
3472                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3473                         psrch_inf->index_of_last_entry +=
3474                                 psrch_inf->entries_in_buffer;
3475 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3476
3477                         /* BB fixme add unlock here */
3478                 }
3479
3480         }
3481
3482         /* BB On error, should we leave previous search buf (and count and
3483         last entry fields) intact or free the previous one? */
3484
3485         /* Note: On -EAGAIN error only caller can retry on handle based calls
3486         since file handle passed in no longer valid */
3487 FNext2_err_exit:
3488         if (rc != 0)
3489                 cifs_buf_release(pSMB);
3490                                                                                               
3491         return rc;
3492 }
3493
3494 int
3495 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3496 {
3497         int rc = 0;
3498         FINDCLOSE_REQ *pSMB = NULL;
3499         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */