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