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