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