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