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