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