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