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