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