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