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