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